[imposm] 01/47: Imported Upstream version 2.1.3

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Fri Mar 13 19:07:35 UTC 2015


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository imposm.

commit 8ae2b2414f0263f79e0e7e4aec70e20b9bb306e4
Author: David Paleino <dapal at debian.org>
Date:   Sun Apr 24 19:43:11 2011 +0200

    Imported Upstream version 2.1.3
---
 CHANGES                                |   25 +
 LICENSE                                |  202 ++
 MANIFEST.in                            |    6 +
 PKG-INFO                               |   58 +
 README                                 |   14 +
 imposm.egg-info/PKG-INFO               |   58 +
 imposm.egg-info/SOURCES.txt            |   37 +
 imposm.egg-info/dependency_links.txt   |    1 +
 imposm.egg-info/entry_points.txt       |    4 +
 imposm.egg-info/namespace_packages.txt |    1 +
 imposm.egg-info/requires.txt           |    3 +
 imposm.egg-info/top_level.txt          |    1 +
 imposm/900913.sql                      |    1 +
 imposm/__init__.py                     |    1 +
 imposm/app.py                          |  246 ++
 imposm/base.py                         |  112 +
 imposm/cache/__init__.py               |    3 +
 imposm/cache/osm.py                    |   57 +
 imposm/cache/tc.c                      | 5530 ++++++++++++++++++++++++++++++++
 imposm/cache/tc.pyx                    |  269 ++
 imposm/db/__init__.py                  |    4 +
 imposm/db/postgis.py                   |  353 ++
 imposm/dbimporter.py                   |  185 ++
 imposm/defaultmapping.py               |  419 +++
 imposm/geom.py                         |  152 +
 imposm/mapping.py                      |  416 +++
 imposm/merge.py                        |   93 +
 imposm/multipolygon.py                 |  306 ++
 imposm/psqldb.py                       |  100 +
 imposm/reader.py                       |  142 +
 imposm/test/__init__.py                |    0
 imposm/test/test_cache.py              |   93 +
 imposm/test/test_multipolygon.py       |  127 +
 imposm/util.py                         |  237 ++
 imposm/version.py                      |   15 +
 imposm/writer.py                       |  104 +
 setup.cfg                              |   11 +
 setup.py                               |   88 +
 38 files changed, 9474 insertions(+)

diff --git a/CHANGES b/CHANGES
new file mode 100644
index 0000000..57a2c24
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,25 @@
+Changelog
+---------
+
+2.1.3 2011-04-19
+~~~~~~~~~~~~~~~~
+
+- support for colons and other special chars in field and
+  table names (e.g. de:name)
+
+2.1.2 2011-04-13
+~~~~~~~~~~~~~~~~
+
+- make it work on 32bit systems
+
+2.1.1 2011-04-12
+~~~~~~~~~~~~~~~~
+
+- new ``--proj`` option to change DB projection from EPSG:900913
+- abort if there are existing cache files
+- new ``--merge-cache`` and ``--overwrite-cache`` options
+
+2.1.0 2011-03-29
+~~~~~~~~~~~~~~~~
+
+- first open source release
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..101809a
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,6 @@
+include setup.py
+include LICENSE
+include CHANGES
+include imposm/900913.sql
+include imposm/cache/tc.c
+include imposm/cache/tc.pyx
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..7576020
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,58 @@
+Metadata-Version: 1.0
+Name: imposm
+Version: 2.1.3
+Summary: OpenStreetMap importer for PostGIS.
+Home-page: http://imposm.org/
+Author: Oliver Tonnhofer
+Author-email: olt at omniscale.de
+License: Apache Software License 2.0
+Description: .. # -*- restructuredtext -*-
+        
+        Imposm is an importer for OpenStreetMap data. It reads XML and PBF files and
+        can import the data into PostgreSQL/PostGIS databases.
+        
+        It is designed to create databases that are optimized for rendering/WMS
+        services.
+        
+        It is developed and supported by `Omniscale <http://omniscale.com>`_, runs on
+        Linux or Mac OS X and is released as open source under the `Apache Software
+        License 2.0 <http://www.apache.org/licenses/LICENSE-2.0.html>`_.
+        
+        See http://imposm.org/ for more information.
+        
+        Changelog
+        ---------
+        
+        2.1.3 2011-04-19
+        ~~~~~~~~~~~~~~~~
+        
+        - support for colons and other special chars in field and
+          table names (e.g. de:name)
+        
+        2.1.2 2011-04-13
+        ~~~~~~~~~~~~~~~~
+        
+        - make it work on 32bit systems
+        
+        2.1.1 2011-04-12
+        ~~~~~~~~~~~~~~~~
+        
+        - new ``--proj`` option to change DB projection from EPSG:900913
+        - abort if there are existing cache files
+        - new ``--merge-cache`` and ``--overwrite-cache`` options
+        
+        2.1.0 2011-03-29
+        ~~~~~~~~~~~~~~~~
+        
+        - first open source release
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: C
+Classifier: Programming Language :: C++
+Classifier: Programming Language :: Python :: 2.5
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Topic :: Scientific/Engineering :: GIS
diff --git a/README b/README
new file mode 100644
index 0000000..21f5e77
--- /dev/null
+++ b/README
@@ -0,0 +1,14 @@
+.. # -*- restructuredtext -*-
+
+Imposm is an importer for OpenStreetMap data. It reads XML and PBF files and
+can import the data into PostgreSQL/PostGIS databases.
+
+It is designed to create databases that are optimized for rendering/WMS
+services.
+
+It is developed and supported by `Omniscale <http://omniscale.com>`_, runs on
+Linux or Mac OS X and is released as open source under the `Apache Software
+License 2.0 <http://www.apache.org/licenses/LICENSE-2.0.html>`_.
+
+See http://imposm.org/ for more information.
+
diff --git a/imposm.egg-info/PKG-INFO b/imposm.egg-info/PKG-INFO
new file mode 100644
index 0000000..7576020
--- /dev/null
+++ b/imposm.egg-info/PKG-INFO
@@ -0,0 +1,58 @@
+Metadata-Version: 1.0
+Name: imposm
+Version: 2.1.3
+Summary: OpenStreetMap importer for PostGIS.
+Home-page: http://imposm.org/
+Author: Oliver Tonnhofer
+Author-email: olt at omniscale.de
+License: Apache Software License 2.0
+Description: .. # -*- restructuredtext -*-
+        
+        Imposm is an importer for OpenStreetMap data. It reads XML and PBF files and
+        can import the data into PostgreSQL/PostGIS databases.
+        
+        It is designed to create databases that are optimized for rendering/WMS
+        services.
+        
+        It is developed and supported by `Omniscale <http://omniscale.com>`_, runs on
+        Linux or Mac OS X and is released as open source under the `Apache Software
+        License 2.0 <http://www.apache.org/licenses/LICENSE-2.0.html>`_.
+        
+        See http://imposm.org/ for more information.
+        
+        Changelog
+        ---------
+        
+        2.1.3 2011-04-19
+        ~~~~~~~~~~~~~~~~
+        
+        - support for colons and other special chars in field and
+          table names (e.g. de:name)
+        
+        2.1.2 2011-04-13
+        ~~~~~~~~~~~~~~~~
+        
+        - make it work on 32bit systems
+        
+        2.1.1 2011-04-12
+        ~~~~~~~~~~~~~~~~
+        
+        - new ``--proj`` option to change DB projection from EPSG:900913
+        - abort if there are existing cache files
+        - new ``--merge-cache`` and ``--overwrite-cache`` options
+        
+        2.1.0 2011-03-29
+        ~~~~~~~~~~~~~~~~
+        
+        - first open source release
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: C
+Classifier: Programming Language :: C++
+Classifier: Programming Language :: Python :: 2.5
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Topic :: Scientific/Engineering :: GIS
diff --git a/imposm.egg-info/SOURCES.txt b/imposm.egg-info/SOURCES.txt
new file mode 100644
index 0000000..d2cdc80
--- /dev/null
+++ b/imposm.egg-info/SOURCES.txt
@@ -0,0 +1,37 @@
+CHANGES
+LICENSE
+MANIFEST.in
+README
+setup.cfg
+setup.py
+imposm/900913.sql
+imposm/__init__.py
+imposm/app.py
+imposm/base.py
+imposm/dbimporter.py
+imposm/defaultmapping.py
+imposm/geom.py
+imposm/mapping.py
+imposm/merge.py
+imposm/multipolygon.py
+imposm/psqldb.py
+imposm/reader.py
+imposm/util.py
+imposm/version.py
+imposm/writer.py
+imposm.egg-info/PKG-INFO
+imposm.egg-info/SOURCES.txt
+imposm.egg-info/dependency_links.txt
+imposm.egg-info/entry_points.txt
+imposm.egg-info/namespace_packages.txt
+imposm.egg-info/requires.txt
+imposm.egg-info/top_level.txt
+imposm/cache/__init__.py
+imposm/cache/osm.py
+imposm/cache/tc.c
+imposm/cache/tc.pyx
+imposm/db/__init__.py
+imposm/db/postgis.py
+imposm/test/__init__.py
+imposm/test/test_cache.py
+imposm/test/test_multipolygon.py
\ No newline at end of file
diff --git a/imposm.egg-info/dependency_links.txt b/imposm.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/imposm.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/imposm.egg-info/entry_points.txt b/imposm.egg-info/entry_points.txt
new file mode 100644
index 0000000..8acaa0f
--- /dev/null
+++ b/imposm.egg-info/entry_points.txt
@@ -0,0 +1,4 @@
+[console_scripts]
+imposm-psqldb = imposm.psqldb:main
+imposm = imposm.app:main
+
diff --git a/imposm.egg-info/namespace_packages.txt b/imposm.egg-info/namespace_packages.txt
new file mode 100644
index 0000000..b31019c
--- /dev/null
+++ b/imposm.egg-info/namespace_packages.txt
@@ -0,0 +1 @@
+imposm
diff --git a/imposm.egg-info/requires.txt b/imposm.egg-info/requires.txt
new file mode 100644
index 0000000..0c1e698
--- /dev/null
+++ b/imposm.egg-info/requires.txt
@@ -0,0 +1,3 @@
+imposm.parser
+psycopg2
+Shapely
\ No newline at end of file
diff --git a/imposm.egg-info/top_level.txt b/imposm.egg-info/top_level.txt
new file mode 100644
index 0000000..b31019c
--- /dev/null
+++ b/imposm.egg-info/top_level.txt
@@ -0,0 +1 @@
+imposm
diff --git a/imposm/900913.sql b/imposm/900913.sql
new file mode 100644
index 0000000..133099a
--- /dev/null
+++ b/imposm/900913.sql
@@ -0,0 +1 @@
+INSERT INTO spatial_ref_sys (srid, auth_name, auth_srid, srtext, proj4text)VALUES (900913,'EPSG',900913,'PROJCS["WGS84 / Simple Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS_1984", 6378137.0, 298.257223563]],PRIMEM["Greenwich", 0.0],UNIT["degree", 0.017453292519943295],AXIS["Longitude", EAST],AXIS["Latitude", NORTH]],PROJECTION["Mercator_1SP_Google"],PARAMETER["latitude_of_origin", 0.0],PARAMETER["central_meridian", 0.0],PARAMETER["scale_factor", 1.0],PARAMETER["false_easting" [...]
diff --git a/imposm/__init__.py b/imposm/__init__.py
new file mode 100644
index 0000000..b0d6433
--- /dev/null
+++ b/imposm/__init__.py
@@ -0,0 +1 @@
+__import__('pkg_resources').declare_namespace(__name__)
\ No newline at end of file
diff --git a/imposm/app.py b/imposm/app.py
new file mode 100644
index 0000000..33c3b1d
--- /dev/null
+++ b/imposm/app.py
@@ -0,0 +1,246 @@
+# Copyright 2011 Omniscale (http://omniscale.com)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import with_statement
+import glob
+import sys
+import os
+import optparse
+import logging
+
+import multiprocessing
+from imposm.util import setproctitle
+
+try:
+    import shapely_speedups
+except ImportError:
+    pass
+else:
+    print 'patching shapely'
+    shapely_speedups.patch_shapely()
+
+import imposm.mapping
+import imposm.util
+import imposm.version
+from imposm.writer import ImposmWriter
+from imposm.db import DB
+from imposm.cache import OSMCache
+from imposm.reader import ImposmReader
+from imposm.mapping import TagMapper
+
+try:
+    n_cpu = multiprocessing.cpu_count()
+except NotImplementedError:
+    n_cpu = 2
+
+def setup_logging():
+    imposm_log = logging.getLogger('imposm')
+    imposm_log.setLevel(logging.INFO)
+
+    ch = logging.StreamHandler(sys.stdout)
+    ch.setLevel(logging.DEBUG)
+    formatter = logging.Formatter(
+        "[%(asctime)s] %(name)s - %(levelname)s - %(message)s")
+    ch.setFormatter(formatter)
+    imposm_log.addHandler(ch)
+
+__version__ = imposm.version.__version__
+
+def main():
+    setproctitle('imposm: main')
+    setup_logging()
+
+    usage = '%prog [options] [input]...'
+    parser = optparse.OptionParser(usage=usage, add_help_option=False,
+        version="%prog " + __version__)
+    parser.add_option('--help', dest='help', action='store_true',
+        default=False, help='show this help message and exit')
+    parser.add_option('-m', '--mapping-file', dest='mapping_file',
+        metavar='<file>')
+    parser.add_option('-h', '--host', dest='host', metavar='<host>')
+    parser.add_option('-d', '--database', dest='db', metavar='<dbname>')
+    parser.add_option('-U', '--user', dest='user', metavar='<user>')
+    parser.add_option('--proj', dest='proj', metavar='EPSG:900913')
+    
+    parser.add_option('-c', '--concurrency', dest='concurrency', metavar='N',
+                      type='int', default=n_cpu)
+
+    parser.add_option('--merge-cache', dest='merge_cache', default=False,
+        action='store_true')
+    parser.add_option('--overwrite-cache', dest='overwrite_cache', default=False,
+        action='store_true')
+    parser.add_option('--cache-dir', dest='cache_dir', default='.',
+        help="path where node/ways/relations should be cached [current working dir]")
+    
+    
+    parser.add_option('--table-prefix',
+        dest='table_prefix', default='osm_new_', metavar='osm_new_',
+        help='prefix for imported tables')
+    parser.add_option('--table-prefix-production',
+        dest='table_prefix_production', default='osm_', metavar='osm_',
+        help='prefix for production tables')
+    parser.add_option('--table-prefix-backup',
+        dest='table_prefix_backup', default='osm_old_', metavar='osm_old_',
+        help='prefix for backup tables')
+
+
+
+    parser.add_option('--read', dest='read', default=False,
+        action='store_true')
+    parser.add_option('--write', dest='write', default=False,
+        action='store_true')
+    parser.add_option('--optimize', dest='optimize', default=False,
+        action='store_true')
+    parser.add_option('--deploy-production-tables', dest='deploy_tables', default=False,
+        action='store_true', help='remove backup tables, move production tables '
+        'to backup tables and move import tables to production tables')
+    parser.add_option('--recover-production-tables', dest='recover_tables', default=False,
+        action='store_true', help='move production tables to import tables and'
+        'move backup tables to production tables')
+    parser.add_option('--remove-backup-tables', dest='remove_backup_tables', default=False,
+        action='store_true')
+        
+
+    parser.add_option('-n', '--dry-run', dest='dry_run', default=False,
+        action='store_true')
+
+    (options, args) = parser.parse_args()
+
+    if options.help:
+        parser.print_help()
+        sys.exit(1)
+
+    mapping_file = os.path.join(os.path.dirname(__file__),
+        'defaultmapping.py')
+    if options.mapping_file:
+        print 'loading %s as mapping' % options.mapping_file
+        mapping_file = options.mapping_file
+
+    mappings = {}
+    execfile(mapping_file, mappings)
+    tag_mapping = TagMapper([m for n, m in mappings.iteritems() 
+        if isinstance(m, imposm.mapping.Mapping)])
+
+    if (options.write or options.optimize or options.deploy_tables
+        or options.remove_backup_tables or options.recover_tables):
+        db_conf = mappings['db_conf']
+        db_conf.host = options.host or db_conf.host
+        if not options.db:
+            parser.error('-d/--database is required for this mode')
+        db_conf.db = options.db or db_conf.db
+        db_conf.user = options.user or db_conf.user
+        if options.user:
+            from getpass import getpass
+            db_conf.password = getpass('password for %(user)s at %(host)s:' % db_conf)
+        
+        if options.proj:
+            if ':' not in options.proj:
+                print 'ERROR: --proj should be in EPSG:00000 format'
+                sys.exit(1)
+            db_conf.proj = options.proj
+    
+    logger = imposm.util.ProgressLog
+    
+    imposm_timer = imposm.util.Timer('imposm', logger)
+    
+    if options.read:
+        if not options.merge_cache:
+            cache_files = glob.glob(os.path.join(options.cache_dir, 'imposm_*.cache'))
+            if cache_files:
+                if not options.overwrite_cache:
+                    print (
+                        "ERROR: found existing cache files in '%s'. "
+                        'remove files or use --overwrite-cache or --merge-cache.'
+                        % os.path.abspath(options.cache_dir)
+                    )
+                    sys.exit(2)
+                for cache_file in cache_files:
+                    os.unlink(cache_file)
+    
+    cache = OSMCache(options.cache_dir)
+    
+    if options.read:
+        read_timer = imposm.util.Timer('reading', logger)
+        
+        if args:
+            reader = ImposmReader(tag_mapping, cache=cache, merge=options.merge_cache,
+                pool_size=options.concurrency, logger=logger)
+            reader.estimated_coords = imposm.util.estimate_records(args)
+            for arg in args:
+                logger.message('## reading %s' % arg)
+                reader.read(arg)
+        
+        read_timer.stop()
+
+    if options.write:
+        db = DB(db_conf)
+        write_timer = imposm.util.Timer('writing', logger)
+        
+        logger.message('## dropping/creating tables')
+        if not options.dry_run:
+            db.create_tables(tag_mapping.mappings)
+
+        logger.message('## writing data')
+        # create views so we can access the table during the insert, ignore
+        # errors for missing tables (i.e. generalized tables)
+        if not options.dry_run:
+            db.create_views(mappings, ignore_errors=True)
+            db.connection.commit()
+
+        writer = ImposmWriter(tag_mapping, db, cache=cache, 
+            pool_size=options.concurrency, logger=logger,
+            dry_run=options.dry_run)
+        writer.relations()
+        writer.ways()
+        writer.nodes()
+
+        if not options.dry_run:
+            db = DB(db_conf)
+            db.create_generalized_tables(mappings)
+            db.create_views(mappings)
+            db.connection.commit()
+        
+        write_timer.stop()
+
+    if options.optimize:
+        db = DB(db_conf)
+        optimize_timer = imposm.util.Timer('optimizing', logger)
+        logger.message('## optimizing tables')
+        db.optimize(mappings)
+        optimize_timer.stop()
+    
+    if options.recover_tables:
+        assert not options.deploy_tables, ('cannot swap and recover production '
+            'tables at the same time')
+        options.table_prefix, options.table_prefix_backup = \
+            options.table_prefix_backup, options.table_prefix
+        
+    if options.deploy_tables or options.recover_tables:
+        db = DB(db_conf)
+        db.swap_tables(options.table_prefix, 
+            options.table_prefix_production, options.table_prefix_backup)
+        db.remove_views(options.table_prefix)
+        db.db_conf.prefix = options.table_prefix_production
+        db.create_views(mappings)
+        db.connection.commit()
+    
+    if options.remove_backup_tables:
+        db = DB(db_conf)
+        db.remove_tables(options.table_prefix_backup)
+        db.connection.commit()
+    
+    imposm_timer.stop()
+
+if __name__ == '__main__':
+    main()
diff --git a/imposm/base.py b/imposm/base.py
new file mode 100644
index 0000000..ce2a7aa
--- /dev/null
+++ b/imposm/base.py
@@ -0,0 +1,112 @@
+# Copyright 2011 Omniscale (http://omniscale.com)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import with_statement
+
+import itertools
+from imposm.merge import multimerge
+
+__all__ = [
+    'Node', 'Way', 'Relation',
+]
+
+class Node(object):
+    def __init__(self, osm_id, tags, coord):
+        self.osm_id = osm_id
+        self.tags = tags
+        self.coord = coord
+    
+    def __repr__(self):
+        return 'Node(%r, %r, %r)' % (self.osm_id, self.tags, self.coord)
+
+    def merge(self, tags, coord):
+        pass
+
+    def to_tuple(self):
+        return self.osm_id, self.tags, self.coord
+
+class Way(object):
+    def __init__(self, osm_id, tags, refs, inserted=False):
+        self.osm_id = osm_id
+        self.tags = tags
+        self.refs = refs
+        self.partial_refs = None
+        if refs and isinstance(refs[0], list):
+            self.refs = refs[0]
+            self.partial_refs = refs
+        self.inserted = inserted
+
+    def __repr__(self):
+        return 'Way(%r, %r, %r, inserted=%r)' % (self.osm_id, self.tags,
+            self.refs, self.inserted)
+
+    def merge(self, tags, refs):
+        self.tags.update(tags)
+
+        if self.refs != refs:
+            if self.partial_refs:
+                merge_refs = []
+                merge_refs.extend(self.partial_refs)
+            else:
+                merge_refs = self.refs
+            merge_refs.append(refs)
+            result = multimerge(merge_refs)
+            if result is None:
+                self.partial_refs = merge_refs
+            else:
+                self.refs = result
+                self.partial_refs = None
+
+    def to_tuple(self):
+        return self.osm_id, self.tags, self.refs
+
+
+class Relation(object):
+    def __init__(self, osm_id, tags, members):
+        self.osm_id = osm_id
+        self.tags = tags
+        self.members = members
+
+    def merge(self, tags, members):
+        self.tags.update(tags)
+        if self.members != members:
+            self.members = merge_relation_members(self.members, members)
+
+    def to_tuple(self):
+        return self.osm_id, self.tags, self.members
+
+def merge_relation_members(a, b):
+    """
+    concatenate two lists of members, removing duplicates, retaining order
+    """
+    combined = []
+    added_ids = set()
+    for m in itertools.chain(a, b):
+        if m[0] not in added_ids:
+            combined.append(m)
+            added_ids.add(m[0])
+    return combined
+
+
+class OSMElem(object):
+    __slots__ = 'osm_id name coords cls type tags geom'.split()
+    
+    def __init__(self, osm_id, coords, type, tags):
+        self.osm_id = osm_id
+        self.name = tags.get('name')
+        self.coords = coords
+        self.cls = type[0]
+        self.type = type[1]
+        self.tags = tags
+        self.geom = None
\ No newline at end of file
diff --git a/imposm/cache/__init__.py b/imposm/cache/__init__.py
new file mode 100644
index 0000000..409de17
--- /dev/null
+++ b/imposm/cache/__init__.py
@@ -0,0 +1,3 @@
+from . osm import OSMCache
+
+__all__ = ['OSMCache']
\ No newline at end of file
diff --git a/imposm/cache/osm.py b/imposm/cache/osm.py
new file mode 100644
index 0000000..2f7e194
--- /dev/null
+++ b/imposm/cache/osm.py
@@ -0,0 +1,57 @@
+# Copyright 2011 Omniscale (http://omniscale.com)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+
+from . tc import CoordDB, NodeDB, WayDB, RelationDB
+
+class OSMCache(object):
+    def __init__(self, path, suffix='imposm_', prefix='.cache'):
+        self.path = path
+        self.suffix = suffix
+        self.prefix = prefix
+        self.coords_fname = os.path.join(path, suffix + 'coords' + prefix) 
+        self.nodes_fname = os.path.join(path, suffix + 'nodes' + prefix) 
+        self.ways_fname = os.path.join(path, suffix + 'ways' + prefix) 
+        self.relations_fname = os.path.join(path, suffix + 'relations' + prefix) 
+        self.caches = {}
+
+    def close_all(self):
+        for mode_, cache in self.caches.values():
+            cache.close()
+        self.caches = {}
+
+    def coords_cache(self, mode='r', estimated_records=None):
+        return self._x_cache(self.coords_fname, CoordDB, mode, estimated_records)
+
+    def nodes_cache(self, mode='r', estimated_records=None):
+        return self._x_cache(self.nodes_fname, NodeDB, mode, estimated_records)
+
+    def ways_cache(self, mode='r', estimated_records=None):
+        return self._x_cache(self.ways_fname, WayDB, mode, estimated_records)
+
+    def relations_cache(self, mode='r', estimated_records=None):
+        return self._x_cache(self.relations_fname, RelationDB, mode, estimated_records)
+
+    def _x_cache(self, x, x_class, mode, estimated_records=None):
+        if x in self.caches:
+            current_mode, cache = self.caches[x]
+            if current_mode == mode:
+                return cache
+            else:
+                cache.close()
+        cache = x_class(x, mode, estimated_records=estimated_records)
+        self.caches[x] = mode, cache
+
+        return cache
\ No newline at end of file
diff --git a/imposm/cache/tc.c b/imposm/cache/tc.c
new file mode 100644
index 0000000..4c5659d
--- /dev/null
+++ b/imposm/cache/tc.c
@@ -0,0 +1,5530 @@
+/* Generated by Cython 0.14.1 on Wed Apr 13 15:39:58 2011 */
+
+#define PY_SSIZE_T_CLEAN
+#include "Python.h"
+#ifndef Py_PYTHON_H
+    #error Python headers needed to compile C extensions, please install development version of Python.
+#else
+
+#include <stddef.h> /* For offsetof */
+#ifndef offsetof
+#define offsetof(type, member) ( (size_t) & ((type*)0) -> member )
+#endif
+
+#if !defined(WIN32) && !defined(MS_WINDOWS)
+  #ifndef __stdcall
+    #define __stdcall
+  #endif
+  #ifndef __cdecl
+    #define __cdecl
+  #endif
+  #ifndef __fastcall
+    #define __fastcall
+  #endif
+#endif
+
+#ifndef DL_IMPORT
+  #define DL_IMPORT(t) t
+#endif
+#ifndef DL_EXPORT
+  #define DL_EXPORT(t) t
+#endif
+
+#ifndef PY_LONG_LONG
+  #define PY_LONG_LONG LONG_LONG
+#endif
+
+#if PY_VERSION_HEX < 0x02040000
+  #define METH_COEXIST 0
+  #define PyDict_CheckExact(op) (Py_TYPE(op) == &PyDict_Type)
+  #define PyDict_Contains(d,o)   PySequence_Contains(d,o)
+#endif
+
+#if PY_VERSION_HEX < 0x02050000
+  typedef int Py_ssize_t;
+  #define PY_SSIZE_T_MAX INT_MAX
+  #define PY_SSIZE_T_MIN INT_MIN
+  #define PY_FORMAT_SIZE_T ""
+  #define PyInt_FromSsize_t(z) PyInt_FromLong(z)
+  #define PyInt_AsSsize_t(o)   PyInt_AsLong(o)
+  #define PyNumber_Index(o)    PyNumber_Int(o)
+  #define PyIndex_Check(o)     PyNumber_Check(o)
+  #define PyErr_WarnEx(category, message, stacklevel) PyErr_Warn(category, message)
+#endif
+
+#if PY_VERSION_HEX < 0x02060000
+  #define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt)
+  #define Py_TYPE(ob)   (((PyObject*)(ob))->ob_type)
+  #define Py_SIZE(ob)   (((PyVarObject*)(ob))->ob_size)
+  #define PyVarObject_HEAD_INIT(type, size) \
+          PyObject_HEAD_INIT(type) size,
+  #define PyType_Modified(t)
+
+  typedef struct {
+     void *buf;
+     PyObject *obj;
+     Py_ssize_t len;
+     Py_ssize_t itemsize;
+     int readonly;
+     int ndim;
+     char *format;
+     Py_ssize_t *shape;
+     Py_ssize_t *strides;
+     Py_ssize_t *suboffsets;
+     void *internal;
+  } Py_buffer;
+
+  #define PyBUF_SIMPLE 0
+  #define PyBUF_WRITABLE 0x0001
+  #define PyBUF_FORMAT 0x0004
+  #define PyBUF_ND 0x0008
+  #define PyBUF_STRIDES (0x0010 | PyBUF_ND)
+  #define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES)
+  #define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES)
+  #define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES)
+  #define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES)
+
+#endif
+
+#if PY_MAJOR_VERSION < 3
+  #define __Pyx_BUILTIN_MODULE_NAME "__builtin__"
+#else
+  #define __Pyx_BUILTIN_MODULE_NAME "builtins"
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+  #define Py_TPFLAGS_CHECKTYPES 0
+  #define Py_TPFLAGS_HAVE_INDEX 0
+#endif
+
+#if (PY_VERSION_HEX < 0x02060000) || (PY_MAJOR_VERSION >= 3)
+  #define Py_TPFLAGS_HAVE_NEWBUFFER 0
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+  #define PyBaseString_Type            PyUnicode_Type
+  #define PyStringObject               PyUnicodeObject
+  #define PyString_Type                PyUnicode_Type
+  #define PyString_Check               PyUnicode_Check
+  #define PyString_CheckExact          PyUnicode_CheckExact
+#endif
+
+#if PY_VERSION_HEX < 0x02060000
+  #define PyBytesObject                PyStringObject
+  #define PyBytes_Type                 PyString_Type
+  #define PyBytes_Check                PyString_Check
+  #define PyBytes_CheckExact           PyString_CheckExact
+  #define PyBytes_FromString           PyString_FromString
+  #define PyBytes_FromStringAndSize    PyString_FromStringAndSize
+  #define PyBytes_FromFormat           PyString_FromFormat
+  #define PyBytes_DecodeEscape         PyString_DecodeEscape
+  #define PyBytes_AsString             PyString_AsString
+  #define PyBytes_AsStringAndSize      PyString_AsStringAndSize
+  #define PyBytes_Size                 PyString_Size
+  #define PyBytes_AS_STRING            PyString_AS_STRING
+  #define PyBytes_GET_SIZE             PyString_GET_SIZE
+  #define PyBytes_Repr                 PyString_Repr
+  #define PyBytes_Concat               PyString_Concat
+  #define PyBytes_ConcatAndDel         PyString_ConcatAndDel
+#endif
+
+#if PY_VERSION_HEX < 0x02060000
+  #define PySet_Check(obj)             PyObject_TypeCheck(obj, &PySet_Type)
+  #define PyFrozenSet_Check(obj)       PyObject_TypeCheck(obj, &PyFrozenSet_Type)
+#endif
+#ifndef PySet_CheckExact
+  #define PySet_CheckExact(obj)        (Py_TYPE(obj) == &PySet_Type)
+#endif
+
+#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type)
+
+#if PY_MAJOR_VERSION >= 3
+  #define PyIntObject                  PyLongObject
+  #define PyInt_Type                   PyLong_Type
+  #define PyInt_Check(op)              PyLong_Check(op)
+  #define PyInt_CheckExact(op)         PyLong_CheckExact(op)
+  #define PyInt_FromString             PyLong_FromString
+  #define PyInt_FromUnicode            PyLong_FromUnicode
+  #define PyInt_FromLong               PyLong_FromLong
+  #define PyInt_FromSize_t             PyLong_FromSize_t
+  #define PyInt_FromSsize_t            PyLong_FromSsize_t
+  #define PyInt_AsLong                 PyLong_AsLong
+  #define PyInt_AS_LONG                PyLong_AS_LONG
+  #define PyInt_AsSsize_t              PyLong_AsSsize_t
+  #define PyInt_AsUnsignedLongMask     PyLong_AsUnsignedLongMask
+  #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+  #define PyBoolObject                 PyLongObject
+#endif
+
+
+#if PY_MAJOR_VERSION >= 3
+  #define __Pyx_PyNumber_Divide(x,y)         PyNumber_TrueDivide(x,y)
+  #define __Pyx_PyNumber_InPlaceDivide(x,y)  PyNumber_InPlaceTrueDivide(x,y)
+#else
+  #define __Pyx_PyNumber_Divide(x,y)         PyNumber_Divide(x,y)
+  #define __Pyx_PyNumber_InPlaceDivide(x,y)  PyNumber_InPlaceDivide(x,y)
+#endif
+
+#if (PY_MAJOR_VERSION < 3) || (PY_VERSION_HEX >= 0x03010300)
+  #define __Pyx_PySequence_GetSlice(obj, a, b) PySequence_GetSlice(obj, a, b)
+  #define __Pyx_PySequence_SetSlice(obj, a, b, value) PySequence_SetSlice(obj, a, b, value)
+  #define __Pyx_PySequence_DelSlice(obj, a, b) PySequence_DelSlice(obj, a, b)
+#else
+  #define __Pyx_PySequence_GetSlice(obj, a, b) (unlikely(!(obj)) ? \
+        (PyErr_SetString(PyExc_SystemError, "null argument to internal routine"), (PyObject*)0) : \
+        (likely((obj)->ob_type->tp_as_mapping) ? (PySequence_GetSlice(obj, a, b)) : \
+            (PyErr_Format(PyExc_TypeError, "'%.200s' object is unsliceable", (obj)->ob_type->tp_name), (PyObject*)0)))
+  #define __Pyx_PySequence_SetSlice(obj, a, b, value) (unlikely(!(obj)) ? \
+        (PyErr_SetString(PyExc_SystemError, "null argument to internal routine"), -1) : \
+        (likely((obj)->ob_type->tp_as_mapping) ? (PySequence_SetSlice(obj, a, b, value)) : \
+            (PyErr_Format(PyExc_TypeError, "'%.200s' object doesn't support slice assignment", (obj)->ob_type->tp_name), -1)))
+  #define __Pyx_PySequence_DelSlice(obj, a, b) (unlikely(!(obj)) ? \
+        (PyErr_SetString(PyExc_SystemError, "null argument to internal routine"), -1) : \
+        (likely((obj)->ob_type->tp_as_mapping) ? (PySequence_DelSlice(obj, a, b)) : \
+            (PyErr_Format(PyExc_TypeError, "'%.200s' object doesn't support slice deletion", (obj)->ob_type->tp_name), -1)))
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+  #define PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : PyInstanceMethod_New(func))
+#endif
+
+#if PY_VERSION_HEX < 0x02050000
+  #define __Pyx_GetAttrString(o,n)   PyObject_GetAttrString((o),((char *)(n)))
+  #define __Pyx_SetAttrString(o,n,a) PyObject_SetAttrString((o),((char *)(n)),(a))
+  #define __Pyx_DelAttrString(o,n)   PyObject_DelAttrString((o),((char *)(n)))
+#else
+  #define __Pyx_GetAttrString(o,n)   PyObject_GetAttrString((o),(n))
+  #define __Pyx_SetAttrString(o,n,a) PyObject_SetAttrString((o),(n),(a))
+  #define __Pyx_DelAttrString(o,n)   PyObject_DelAttrString((o),(n))
+#endif
+
+#if PY_VERSION_HEX < 0x02050000
+  #define __Pyx_NAMESTR(n) ((char *)(n))
+  #define __Pyx_DOCSTR(n)  ((char *)(n))
+#else
+  #define __Pyx_NAMESTR(n) (n)
+  #define __Pyx_DOCSTR(n)  (n)
+#endif
+
+#ifdef __cplusplus
+#define __PYX_EXTERN_C extern "C"
+#else
+#define __PYX_EXTERN_C extern
+#endif
+
+#if defined(WIN32) || defined(MS_WINDOWS)
+#define _USE_MATH_DEFINES
+#endif
+#include <math.h>
+#define __PYX_HAVE_API__imposm__cache__tc
+#include "stdint.h"
+#include "marshal.h"
+#include "tcutil.h"
+#include "tcbdb.h"
+
+#ifdef PYREX_WITHOUT_ASSERTIONS
+#define CYTHON_WITHOUT_ASSERTIONS
+#endif
+
+
+/* inline attribute */
+#ifndef CYTHON_INLINE
+  #if defined(__GNUC__)
+    #define CYTHON_INLINE __inline__
+  #elif defined(_MSC_VER)
+    #define CYTHON_INLINE __inline
+  #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+    #define CYTHON_INLINE inline
+  #else
+    #define CYTHON_INLINE
+  #endif
+#endif
+
+/* unused attribute */
+#ifndef CYTHON_UNUSED
+# if defined(__GNUC__)
+#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+#     define CYTHON_UNUSED __attribute__ ((__unused__))
+#   else
+#     define CYTHON_UNUSED
+#   endif
+# elif defined(__ICC) || defined(__INTEL_COMPILER)
+#   define CYTHON_UNUSED __attribute__ ((__unused__))
+# else
+#   define CYTHON_UNUSED
+# endif
+#endif
+
+typedef struct {PyObject **p; char *s; const long n; const char* encoding; const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; /*proto*/
+
+
+/* Type Conversion Predeclarations */
+
+#define __Pyx_PyBytes_FromUString(s) PyBytes_FromString((char*)s)
+#define __Pyx_PyBytes_AsUString(s)   ((unsigned char*) PyBytes_AsString(s))
+
+#define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False))
+static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*);
+static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x);
+
+static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*);
+static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t);
+static CYTHON_INLINE size_t __Pyx_PyInt_AsSize_t(PyObject*);
+
+#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x))
+
+
+#ifdef __GNUC__
+/* Test for GCC > 2.95 */
+#if __GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))
+#define likely(x)   __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#else /* __GNUC__ > 2 ... */
+#define likely(x)   (x)
+#define unlikely(x) (x)
+#endif /* __GNUC__ > 2 ... */
+#else /* __GNUC__ */
+#define likely(x)   (x)
+#define unlikely(x) (x)
+#endif /* __GNUC__ */
+    
+static PyObject *__pyx_m;
+static PyObject *__pyx_b;
+static PyObject *__pyx_empty_tuple;
+static PyObject *__pyx_empty_bytes;
+static int __pyx_lineno;
+static int __pyx_clineno = 0;
+static const char * __pyx_cfilenm= __FILE__;
+static const char *__pyx_filename;
+
+
+static const char *__pyx_f[] = {
+  "tc.pyx",
+};
+
+/* Type declarations */
+
+/* "imposm/cache/tc.pyx":75
+ *     return <double>((x / COORD_FACTOR) - 180.0)
+ * 
+ * ctypedef struct coord:             # <<<<<<<<<<<<<<
+ *     uint32_t x
+ *     uint32_t y
+ */
+
+typedef struct {
+  uint32_t x;
+  uint32_t y;
+} __pyx_t_6imposm_5cache_2tc_coord;
+
+/* "imposm/cache/tc.pyx":90
+ * }
+ * 
+ * cdef class BDB:             # <<<<<<<<<<<<<<
+ *     cdef TCBDB *db
+ *     cdef object filename
+ */
+
+struct __pyx_obj_6imposm_5cache_2tc_BDB {
+  PyObject_HEAD
+  struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB *__pyx_vtab;
+  TCBDB *db;
+  PyObject *filename;
+  int _opened;
+  BDBCUR *_cur;
+};
+
+/* "imposm/cache/tc.pyx":200
+ *         tcbdbdel(self.db)
+ * 
+ * cdef class CoordDB(BDB):             # <<<<<<<<<<<<<<
+ *     def put(self, osmid, x, y):
+ *         return self._put(osmid, x, y)
+ */
+
+struct __pyx_obj_6imposm_5cache_2tc_CoordDB {
+  struct __pyx_obj_6imposm_5cache_2tc_BDB __pyx_base;
+};
+
+/* "imposm/cache/tc.pyx":253
+ *         return Node(osmid, data[0], data[1])
+ * 
+ * cdef class RefTagDB(BDB):             # <<<<<<<<<<<<<<
+ *     """
+ *     Database for items with references and tags (i.e. ways/relations).
+ */
+
+struct __pyx_obj_6imposm_5cache_2tc_RefTagDB {
+  struct __pyx_obj_6imposm_5cache_2tc_BDB __pyx_base;
+};
+
+/* "imposm/cache/tc.pyx":263
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>data, len(data))
+ * 
+ * cdef class WayDB(RefTagDB):             # <<<<<<<<<<<<<<
+ *     cdef object _obj(self, int64_t osmid, data):
+ *         return Way(osmid, data[0], data[1])
+ */
+
+struct __pyx_obj_6imposm_5cache_2tc_WayDB {
+  struct __pyx_obj_6imposm_5cache_2tc_RefTagDB __pyx_base;
+};
+
+/* "imposm/cache/tc.pyx":267
+ *         return Way(osmid, data[0], data[1])
+ * 
+ * cdef class RelationDB(RefTagDB):             # <<<<<<<<<<<<<<
+ *     cdef object _obj(self, int64_t osmid, data):
+ *         return Relation(osmid, data[0], data[1])
+ */
+
+struct __pyx_obj_6imposm_5cache_2tc_RelationDB {
+  struct __pyx_obj_6imposm_5cache_2tc_RefTagDB __pyx_base;
+};
+
+/* "imposm/cache/tc.pyx":243
+ *         return osmid, data
+ * 
+ * cdef class NodeDB(BDB):             # <<<<<<<<<<<<<<
+ *     def put(self, osmid, tags, pos):
+ *         return self.put_marshaled(osmid, PyMarshal_WriteObjectToString((tags, pos), 2))
+ */
+
+struct __pyx_obj_6imposm_5cache_2tc_NodeDB {
+  struct __pyx_obj_6imposm_5cache_2tc_BDB __pyx_base;
+};
+
+
+/* "imposm/cache/tc.pyx":90
+ * }
+ * 
+ * cdef class BDB:             # <<<<<<<<<<<<<<
+ *     cdef TCBDB *db
+ *     cdef object filename
+ */
+
+struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB {
+  PyObject *(*_obj)(struct __pyx_obj_6imposm_5cache_2tc_BDB *, int64_t, PyObject *);
+  PyObject *(*_get_cur)(struct __pyx_obj_6imposm_5cache_2tc_BDB *);
+};
+static struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB *__pyx_vtabptr_6imposm_5cache_2tc_BDB;
+
+
+/* "imposm/cache/tc.pyx":200
+ *         tcbdbdel(self.db)
+ * 
+ * cdef class CoordDB(BDB):             # <<<<<<<<<<<<<<
+ *     def put(self, osmid, x, y):
+ *         return self._put(osmid, x, y)
+ */
+
+struct __pyx_vtabstruct_6imposm_5cache_2tc_CoordDB {
+  struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB __pyx_base;
+  int (*_put)(struct __pyx_obj_6imposm_5cache_2tc_CoordDB *, int64_t, double, double);
+};
+static struct __pyx_vtabstruct_6imposm_5cache_2tc_CoordDB *__pyx_vtabptr_6imposm_5cache_2tc_CoordDB;
+
+
+/* "imposm/cache/tc.pyx":243
+ *         return osmid, data
+ * 
+ * cdef class NodeDB(BDB):             # <<<<<<<<<<<<<<
+ *     def put(self, osmid, tags, pos):
+ *         return self.put_marshaled(osmid, PyMarshal_WriteObjectToString((tags, pos), 2))
+ */
+
+struct __pyx_vtabstruct_6imposm_5cache_2tc_NodeDB {
+  struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB __pyx_base;
+};
+static struct __pyx_vtabstruct_6imposm_5cache_2tc_NodeDB *__pyx_vtabptr_6imposm_5cache_2tc_NodeDB;
+
+
+/* "imposm/cache/tc.pyx":253
+ *         return Node(osmid, data[0], data[1])
+ * 
+ * cdef class RefTagDB(BDB):             # <<<<<<<<<<<<<<
+ *     """
+ *     Database for items with references and tags (i.e. ways/relations).
+ */
+
+struct __pyx_vtabstruct_6imposm_5cache_2tc_RefTagDB {
+  struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB __pyx_base;
+};
+static struct __pyx_vtabstruct_6imposm_5cache_2tc_RefTagDB *__pyx_vtabptr_6imposm_5cache_2tc_RefTagDB;
+
+
+/* "imposm/cache/tc.pyx":267
+ *         return Way(osmid, data[0], data[1])
+ * 
+ * cdef class RelationDB(RefTagDB):             # <<<<<<<<<<<<<<
+ *     cdef object _obj(self, int64_t osmid, data):
+ *         return Relation(osmid, data[0], data[1])
+ */
+
+struct __pyx_vtabstruct_6imposm_5cache_2tc_RelationDB {
+  struct __pyx_vtabstruct_6imposm_5cache_2tc_RefTagDB __pyx_base;
+};
+static struct __pyx_vtabstruct_6imposm_5cache_2tc_RelationDB *__pyx_vtabptr_6imposm_5cache_2tc_RelationDB;
+
+
+/* "imposm/cache/tc.pyx":263
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>data, len(data))
+ * 
+ * cdef class WayDB(RefTagDB):             # <<<<<<<<<<<<<<
+ *     cdef object _obj(self, int64_t osmid, data):
+ *         return Way(osmid, data[0], data[1])
+ */
+
+struct __pyx_vtabstruct_6imposm_5cache_2tc_WayDB {
+  struct __pyx_vtabstruct_6imposm_5cache_2tc_RefTagDB __pyx_base;
+};
+static struct __pyx_vtabstruct_6imposm_5cache_2tc_WayDB *__pyx_vtabptr_6imposm_5cache_2tc_WayDB;
+
+#ifndef CYTHON_REFNANNY
+  #define CYTHON_REFNANNY 0
+#endif
+
+#if CYTHON_REFNANNY
+  typedef struct {
+    void (*INCREF)(void*, PyObject*, int);
+    void (*DECREF)(void*, PyObject*, int);
+    void (*GOTREF)(void*, PyObject*, int);
+    void (*GIVEREF)(void*, PyObject*, int);
+    void* (*SetupContext)(const char*, int, const char*);
+    void (*FinishContext)(void**);
+  } __Pyx_RefNannyAPIStruct;
+  static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL;
+  static __Pyx_RefNannyAPIStruct * __Pyx_RefNannyImportAPI(const char *modname) {
+    PyObject *m = NULL, *p = NULL;
+    void *r = NULL;
+    m = PyImport_ImportModule((char *)modname);
+    if (!m) goto end;
+    p = PyObject_GetAttrString(m, (char *)"RefNannyAPI");
+    if (!p) goto end;
+    r = PyLong_AsVoidPtr(p);
+  end:
+    Py_XDECREF(p);
+    Py_XDECREF(m);
+    return (__Pyx_RefNannyAPIStruct *)r;
+  }
+  #define __Pyx_RefNannySetupContext(name)           void *__pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__)
+  #define __Pyx_RefNannyFinishContext()           __Pyx_RefNanny->FinishContext(&__pyx_refnanny)
+  #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
+  #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
+  #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
+  #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
+  #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r);} } while(0)
+#else
+  #define __Pyx_RefNannySetupContext(name)
+  #define __Pyx_RefNannyFinishContext()
+  #define __Pyx_INCREF(r) Py_INCREF(r)
+  #define __Pyx_DECREF(r) Py_DECREF(r)
+  #define __Pyx_GOTREF(r)
+  #define __Pyx_GIVEREF(r)
+  #define __Pyx_XDECREF(r) Py_XDECREF(r)
+#endif /* CYTHON_REFNANNY */
+#define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);} } while(0)
+#define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r);} } while(0)
+
+static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/
+
+static void __Pyx_RaiseDoubleKeywordsError(
+    const char* func_name, PyObject* kw_name); /*proto*/
+
+static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[],     PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args,     const char* function_name); /*proto*/
+
+static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact,
+    Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); /*proto*/
+
+static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
+static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
+
+static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
+
+static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index);
+
+static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected);
+
+static PyObject *__Pyx_UnpackItem(PyObject *, Py_ssize_t index); /*proto*/
+static int __Pyx_EndUnpack(PyObject *, Py_ssize_t expected); /*proto*/
+
+
+static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) {
+    PyObject *r;
+    if (!j) return NULL;
+    r = PyObject_GetItem(o, j);
+    Py_DECREF(j);
+    return r;
+}
+
+
+#define __Pyx_GetItemInt_List(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \
+                                                    __Pyx_GetItemInt_List_Fast(o, i) : \
+                                                    __Pyx_GetItemInt_Generic(o, to_py_func(i)))
+
+static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i) {
+    if (likely(o != Py_None)) {
+        if (likely((0 <= i) & (i < PyList_GET_SIZE(o)))) {
+            PyObject *r = PyList_GET_ITEM(o, i);
+            Py_INCREF(r);
+            return r;
+        }
+        else if ((-PyList_GET_SIZE(o) <= i) & (i < 0)) {
+            PyObject *r = PyList_GET_ITEM(o, PyList_GET_SIZE(o) + i);
+            Py_INCREF(r);
+            return r;
+        }
+    }
+    return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i));
+}
+
+#define __Pyx_GetItemInt_Tuple(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \
+                                                    __Pyx_GetItemInt_Tuple_Fast(o, i) : \
+                                                    __Pyx_GetItemInt_Generic(o, to_py_func(i)))
+
+static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i) {
+    if (likely(o != Py_None)) {
+        if (likely((0 <= i) & (i < PyTuple_GET_SIZE(o)))) {
+            PyObject *r = PyTuple_GET_ITEM(o, i);
+            Py_INCREF(r);
+            return r;
+        }
+        else if ((-PyTuple_GET_SIZE(o) <= i) & (i < 0)) {
+            PyObject *r = PyTuple_GET_ITEM(o, PyTuple_GET_SIZE(o) + i);
+            Py_INCREF(r);
+            return r;
+        }
+    }
+    return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i));
+}
+
+
+#define __Pyx_GetItemInt(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \
+                                                    __Pyx_GetItemInt_Fast(o, i) : \
+                                                    __Pyx_GetItemInt_Generic(o, to_py_func(i)))
+
+static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i) {
+    PyObject *r;
+    if (PyList_CheckExact(o) && ((0 <= i) & (i < PyList_GET_SIZE(o)))) {
+        r = PyList_GET_ITEM(o, i);
+        Py_INCREF(r);
+    }
+    else if (PyTuple_CheckExact(o) && ((0 <= i) & (i < PyTuple_GET_SIZE(o)))) {
+        r = PyTuple_GET_ITEM(o, i);
+        Py_INCREF(r);
+    }
+    else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_item && (likely(i >= 0))) {
+        r = PySequence_GetItem(o, i);
+    }
+    else {
+        r = __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i));
+    }
+    return r;
+}
+
+static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/
+
+static CYTHON_INLINE int64_t __Pyx_PyInt_from_py_int64_t(PyObject *);
+
+static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_int64_t(int64_t);
+
+static CYTHON_INLINE unsigned char __Pyx_PyInt_AsUnsignedChar(PyObject *);
+
+static CYTHON_INLINE unsigned short __Pyx_PyInt_AsUnsignedShort(PyObject *);
+
+static CYTHON_INLINE unsigned int __Pyx_PyInt_AsUnsignedInt(PyObject *);
+
+static CYTHON_INLINE char __Pyx_PyInt_AsChar(PyObject *);
+
+static CYTHON_INLINE short __Pyx_PyInt_AsShort(PyObject *);
+
+static CYTHON_INLINE int __Pyx_PyInt_AsInt(PyObject *);
+
+static CYTHON_INLINE signed char __Pyx_PyInt_AsSignedChar(PyObject *);
+
+static CYTHON_INLINE signed short __Pyx_PyInt_AsSignedShort(PyObject *);
+
+static CYTHON_INLINE signed int __Pyx_PyInt_AsSignedInt(PyObject *);
+
+static CYTHON_INLINE int __Pyx_PyInt_AsLongDouble(PyObject *);
+
+static CYTHON_INLINE unsigned long __Pyx_PyInt_AsUnsignedLong(PyObject *);
+
+static CYTHON_INLINE unsigned PY_LONG_LONG __Pyx_PyInt_AsUnsignedLongLong(PyObject *);
+
+static CYTHON_INLINE long __Pyx_PyInt_AsLong(PyObject *);
+
+static CYTHON_INLINE PY_LONG_LONG __Pyx_PyInt_AsLongLong(PyObject *);
+
+static CYTHON_INLINE signed long __Pyx_PyInt_AsSignedLong(PyObject *);
+
+static CYTHON_INLINE signed PY_LONG_LONG __Pyx_PyInt_AsSignedLongLong(PyObject *);
+
+static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/
+
+static void __Pyx_AddTraceback(const char *funcname); /*proto*/
+
+static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/
+/* Module declarations from libc.stdint */
+
+/* Module declarations from imposm.cache.tc */
+
+static PyTypeObject *__pyx_ptype_6imposm_5cache_2tc_BDB = 0;
+static PyTypeObject *__pyx_ptype_6imposm_5cache_2tc_CoordDB = 0;
+static PyTypeObject *__pyx_ptype_6imposm_5cache_2tc_NodeDB = 0;
+static PyTypeObject *__pyx_ptype_6imposm_5cache_2tc_RefTagDB = 0;
+static PyTypeObject *__pyx_ptype_6imposm_5cache_2tc_WayDB = 0;
+static PyTypeObject *__pyx_ptype_6imposm_5cache_2tc_RelationDB = 0;
+static uint32_t __pyx_f_6imposm_5cache_2tc__coord_to_uint32(double); /*proto*/
+static double __pyx_f_6imposm_5cache_2tc__uint32_to_coord(uint32_t); /*proto*/
+static CYTHON_INLINE __pyx_t_6imposm_5cache_2tc_coord __pyx_f_6imposm_5cache_2tc_coord_struct(double, double); /*proto*/
+#define __Pyx_MODULE_NAME "imposm.cache.tc"
+static int __pyx_module_is_main_imposm__cache__tc = 0;
+
+/* Implementation of imposm.cache.tc */
+static PyObject *__pyx_builtin_IOError;
+static PyObject *__pyx_builtin_StopIteration;
+static char __pyx_k_1[] = "imposm.base";
+static char __pyx_k__r[] = "r";
+static char __pyx_k__w[] = "w";
+static char __pyx_k__x[] = "x";
+static char __pyx_k__y[] = "y";
+static char __pyx_k__db[] = "db";
+static char __pyx_k__Way[] = "Way";
+static char __pyx_k__pos[] = "pos";
+static char __pyx_k__Node[] = "Node";
+static char __pyx_k___cur[] = "_cur";
+static char __pyx_k___obj[] = "_obj";
+static char __pyx_k___put[] = "_put";
+static char __pyx_k__data[] = "data";
+static char __pyx_k__mode[] = "mode";
+static char __pyx_k__refs[] = "refs";
+static char __pyx_k__tags[] = "tags";
+static char __pyx_k__osmid[] = "osmid";
+static char __pyx_k___modes[] = "_modes";
+static char __pyx_k__append[] = "append";
+static char __pyx_k__IOError[] = "IOError";
+static char __pyx_k___opened[] = "_opened";
+static char __pyx_k__Relation[] = "Relation";
+static char __pyx_k____main__[] = "__main__";
+static char __pyx_k____test__[] = "__test__";
+static char __pyx_k___get_cur[] = "_get_cur";
+static char __pyx_k___tune_db[] = "_tune_db";
+static char __pyx_k__filename[] = "filename";
+static char __pyx_k__StopIteration[] = "StopIteration";
+static char __pyx_k__put_marshaled[] = "put_marshaled";
+static char __pyx_k__estimated_records[] = "estimated_records";
+static PyObject *__pyx_n_s_1;
+static PyObject *__pyx_n_s__IOError;
+static PyObject *__pyx_n_s__Node;
+static PyObject *__pyx_n_s__Relation;
+static PyObject *__pyx_n_s__StopIteration;
+static PyObject *__pyx_n_s__Way;
+static PyObject *__pyx_n_s____main__;
+static PyObject *__pyx_n_s____test__;
+static PyObject *__pyx_n_s___cur;
+static PyObject *__pyx_n_s___get_cur;
+static PyObject *__pyx_n_s___modes;
+static PyObject *__pyx_n_s___obj;
+static PyObject *__pyx_n_s___opened;
+static PyObject *__pyx_n_s___put;
+static PyObject *__pyx_n_s___tune_db;
+static PyObject *__pyx_n_s__append;
+static PyObject *__pyx_n_s__data;
+static PyObject *__pyx_n_s__db;
+static PyObject *__pyx_n_s__estimated_records;
+static PyObject *__pyx_n_s__filename;
+static PyObject *__pyx_n_s__mode;
+static PyObject *__pyx_n_s__osmid;
+static PyObject *__pyx_n_s__pos;
+static PyObject *__pyx_n_s__put_marshaled;
+static PyObject *__pyx_n_s__r;
+static PyObject *__pyx_n_s__refs;
+static PyObject *__pyx_n_s__tags;
+static PyObject *__pyx_n_s__w;
+static PyObject *__pyx_n_s__x;
+static PyObject *__pyx_n_s__y;
+static PyObject *__pyx_int_0;
+static PyObject *__pyx_int_3;
+static PyObject *__pyx_int_128;
+
+/* "imposm/cache/tc.pyx":69
+ * DEF COORD_FACTOR = 11930464.7083 # ((2<<31)-1)/360.0
+ * 
+ * cdef uint32_t _coord_to_uint32(double x) nogil:             # <<<<<<<<<<<<<<
+ *     return <uint32_t>((x + 180.0) * COORD_FACTOR)
+ * 
+ */
+
+static  uint32_t __pyx_f_6imposm_5cache_2tc__coord_to_uint32(double __pyx_v_x) {
+  uint32_t __pyx_r;
+
+  /* "imposm/cache/tc.pyx":70
+ * 
+ * cdef uint32_t _coord_to_uint32(double x) nogil:
+ *     return <uint32_t>((x + 180.0) * COORD_FACTOR)             # <<<<<<<<<<<<<<
+ * 
+ * cdef double _uint32_to_coord(uint32_t x) nogil:
+ */
+  __pyx_r = ((uint32_t)((__pyx_v_x + 180.0) * 11930464.7083));
+  goto __pyx_L0;
+
+  __pyx_r = 0;
+  __pyx_L0:;
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":72
+ *     return <uint32_t>((x + 180.0) * COORD_FACTOR)
+ * 
+ * cdef double _uint32_to_coord(uint32_t x) nogil:             # <<<<<<<<<<<<<<
+ *     return <double>((x / COORD_FACTOR) - 180.0)
+ * 
+ */
+
+static  double __pyx_f_6imposm_5cache_2tc__uint32_to_coord(uint32_t __pyx_v_x) {
+  double __pyx_r;
+
+  /* "imposm/cache/tc.pyx":73
+ * 
+ * cdef double _uint32_to_coord(uint32_t x) nogil:
+ *     return <double>((x / COORD_FACTOR) - 180.0)             # <<<<<<<<<<<<<<
+ * 
+ * ctypedef struct coord:
+ */
+  __pyx_r = ((__pyx_v_x / 11930464.7083) - 180.0);
+  goto __pyx_L0;
+
+  __pyx_r = 0;
+  __pyx_L0:;
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":79
+ *     uint32_t y
+ * 
+ * cdef inline coord coord_struct(double x, double y) nogil:             # <<<<<<<<<<<<<<
+ *     cdef coord p
+ *     p.x = _coord_to_uint32(x)
+ */
+
+static CYTHON_INLINE __pyx_t_6imposm_5cache_2tc_coord __pyx_f_6imposm_5cache_2tc_coord_struct(double __pyx_v_x, double __pyx_v_y) {
+  __pyx_t_6imposm_5cache_2tc_coord __pyx_v_p;
+  __pyx_t_6imposm_5cache_2tc_coord __pyx_r;
+
+  /* "imposm/cache/tc.pyx":81
+ * cdef inline coord coord_struct(double x, double y) nogil:
+ *     cdef coord p
+ *     p.x = _coord_to_uint32(x)             # <<<<<<<<<<<<<<
+ *     p.y = _coord_to_uint32(y)
+ *     return p
+ */
+  __pyx_v_p.x = __pyx_f_6imposm_5cache_2tc__coord_to_uint32(__pyx_v_x);
+
+  /* "imposm/cache/tc.pyx":82
+ *     cdef coord p
+ *     p.x = _coord_to_uint32(x)
+ *     p.y = _coord_to_uint32(y)             # <<<<<<<<<<<<<<
+ *     return p
+ * 
+ */
+  __pyx_v_p.y = __pyx_f_6imposm_5cache_2tc__coord_to_uint32(__pyx_v_y);
+
+  /* "imposm/cache/tc.pyx":83
+ *     p.x = _coord_to_uint32(x)
+ *     p.y = _coord_to_uint32(y)
+ *     return p             # <<<<<<<<<<<<<<
+ * 
+ * _modes = {
+ */
+  __pyx_r = __pyx_v_p;
+  goto __pyx_L0;
+
+  __pyx_L0:;
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":95
+ *     cdef int _opened
+ *     cdef BDBCUR *_cur
+ *     def __cinit__(self, filename, mode='w', estimated_records=0):             # <<<<<<<<<<<<<<
+ *         self.db = tcbdbnew()
+ *         self._opened = 0
+ */
+
+static int __pyx_pf_6imposm_5cache_2tc_3BDB___cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static int __pyx_pf_6imposm_5cache_2tc_3BDB___cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_filename = 0;
+  PyObject *__pyx_v_mode = 0;
+  PyObject *__pyx_v_estimated_records = 0;
+  int __pyx_r;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__filename,&__pyx_n_s__mode,&__pyx_n_s__estimated_records,0};
+  __Pyx_RefNannySetupContext("__cinit__");
+  if (unlikely(__pyx_kwds)) {
+    Py_ssize_t kw_args = PyDict_Size(__pyx_kwds);
+    PyObject* values[3] = {0,0,0};
+    values[1] = ((PyObject *)__pyx_n_s__w);
+    values[2] = ((PyObject *)__pyx_int_0);
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
+      case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+      case  0: break;
+      default: goto __pyx_L5_argtuple_error;
+    }
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  0:
+      values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__filename);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      if (kw_args > 0) {
+        PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__mode);
+        if (value) { values[1] = value; kw_args--; }
+      }
+      case  2:
+      if (kw_args > 0) {
+        PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__estimated_records);
+        if (value) { values[2] = value; kw_args--; }
+      }
+    }
+    if (unlikely(kw_args > 0)) {
+      if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "__cinit__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_filename = values[0];
+    __pyx_v_mode = values[1];
+    __pyx_v_estimated_records = values[2];
+  } else {
+    __pyx_v_mode = ((PyObject *)__pyx_n_s__w);
+    __pyx_v_estimated_records = ((PyObject *)__pyx_int_0);
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  3: __pyx_v_estimated_records = PyTuple_GET_ITEM(__pyx_args, 2);
+      case  2: __pyx_v_mode = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: __pyx_v_filename = PyTuple_GET_ITEM(__pyx_args, 0);
+      break;
+      default: goto __pyx_L5_argtuple_error;
+    }
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 1, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.BDB.__cinit__");
+  __Pyx_RefNannyFinishContext();
+  return -1;
+  __pyx_L4_argument_unpacking_done:;
+
+  /* "imposm/cache/tc.pyx":96
+ *     cdef BDBCUR *_cur
+ *     def __cinit__(self, filename, mode='w', estimated_records=0):
+ *         self.db = tcbdbnew()             # <<<<<<<<<<<<<<
+ *         self._opened = 0
+ * 
+ */
+  ((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->db = tcbdbnew();
+
+  /* "imposm/cache/tc.pyx":97
+ *     def __cinit__(self, filename, mode='w', estimated_records=0):
+ *         self.db = tcbdbnew()
+ *         self._opened = 0             # <<<<<<<<<<<<<<
+ * 
+ *     def __init__(self, filename, mode='w', estimated_records=0):
+ */
+  ((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->_opened = 0;
+
+  __pyx_r = 0;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":99
+ *         self._opened = 0
+ * 
+ *     def __init__(self, filename, mode='w', estimated_records=0):             # <<<<<<<<<<<<<<
+ *         self.filename = filename
+ *         self._tune_db(estimated_records)
+ */
+
+static int __pyx_pf_6imposm_5cache_2tc_3BDB_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static int __pyx_pf_6imposm_5cache_2tc_3BDB_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_filename = 0;
+  PyObject *__pyx_v_mode = 0;
+  PyObject *__pyx_v_estimated_records = 0;
+  int __pyx_r;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  TCBDB *__pyx_t_4;
+  char *__pyx_t_5;
+  int __pyx_t_6;
+  int __pyx_t_7;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__filename,&__pyx_n_s__mode,&__pyx_n_s__estimated_records,0};
+  __Pyx_RefNannySetupContext("__init__");
+  if (unlikely(__pyx_kwds)) {
+    Py_ssize_t kw_args = PyDict_Size(__pyx_kwds);
+    PyObject* values[3] = {0,0,0};
+    values[1] = ((PyObject *)__pyx_n_s__w);
+    values[2] = ((PyObject *)__pyx_int_0);
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
+      case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+      case  0: break;
+      default: goto __pyx_L5_argtuple_error;
+    }
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  0:
+      values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__filename);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      if (kw_args > 0) {
+        PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__mode);
+        if (value) { values[1] = value; kw_args--; }
+      }
+      case  2:
+      if (kw_args > 0) {
+        PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__estimated_records);
+        if (value) { values[2] = value; kw_args--; }
+      }
+    }
+    if (unlikely(kw_args > 0)) {
+      if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_filename = values[0];
+    __pyx_v_mode = values[1];
+    __pyx_v_estimated_records = values[2];
+  } else {
+    __pyx_v_mode = ((PyObject *)__pyx_n_s__w);
+    __pyx_v_estimated_records = ((PyObject *)__pyx_int_0);
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  3: __pyx_v_estimated_records = PyTuple_GET_ITEM(__pyx_args, 2);
+      case  2: __pyx_v_mode = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: __pyx_v_filename = PyTuple_GET_ITEM(__pyx_args, 0);
+      break;
+      default: goto __pyx_L5_argtuple_error;
+    }
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("__init__", 0, 1, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.BDB.__init__");
+  __Pyx_RefNannyFinishContext();
+  return -1;
+  __pyx_L4_argument_unpacking_done:;
+
+  /* "imposm/cache/tc.pyx":100
+ * 
+ *     def __init__(self, filename, mode='w', estimated_records=0):
+ *         self.filename = filename             # <<<<<<<<<<<<<<
+ *         self._tune_db(estimated_records)
+ *         tcbdbsetcmpfunc(self.db, tccmpint64, NULL)
+ */
+  __Pyx_INCREF(__pyx_v_filename);
+  __Pyx_GIVEREF(__pyx_v_filename);
+  __Pyx_GOTREF(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->filename);
+  __Pyx_DECREF(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->filename);
+  ((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->filename = __pyx_v_filename;
+
+  /* "imposm/cache/tc.pyx":101
+ *     def __init__(self, filename, mode='w', estimated_records=0):
+ *         self.filename = filename
+ *         self._tune_db(estimated_records)             # <<<<<<<<<<<<<<
+ *         tcbdbsetcmpfunc(self.db, tccmpint64, NULL)
+ *         if not tcbdbopen(self.db, filename, _modes[mode]):
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___tune_db); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  __Pyx_INCREF(__pyx_v_estimated_records);
+  PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_v_estimated_records);
+  __Pyx_GIVEREF(__pyx_v_estimated_records);
+  __pyx_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+
+  /* "imposm/cache/tc.pyx":102
+ *         self.filename = filename
+ *         self._tune_db(estimated_records)
+ *         tcbdbsetcmpfunc(self.db, tccmpint64, NULL)             # <<<<<<<<<<<<<<
+ *         if not tcbdbopen(self.db, filename, _modes[mode]):
+ *             raise IOError
+ */
+  tcbdbsetcmpfunc(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->db, tccmpint64, NULL);
+
+  /* "imposm/cache/tc.pyx":103
+ *         self._tune_db(estimated_records)
+ *         tcbdbsetcmpfunc(self.db, tccmpint64, NULL)
+ *         if not tcbdbopen(self.db, filename, _modes[mode]):             # <<<<<<<<<<<<<<
+ *             raise IOError
+ *         self._opened = 1
+ */
+  __pyx_t_4 = ((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->db;
+  __pyx_t_5 = PyBytes_AsString(__pyx_v_filename); if (unlikely((!__pyx_t_5) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 103; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_GetName(__pyx_m, __pyx_n_s___modes); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 103; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_2 = PyObject_GetItem(__pyx_t_3, __pyx_v_mode); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 103; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_6 = __Pyx_PyInt_AsInt(__pyx_t_2); if (unlikely((__pyx_t_6 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 103; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_7 = (!tcbdbopen(__pyx_t_4, __pyx_t_5, __pyx_t_6));
+  if (__pyx_t_7) {
+
+    /* "imposm/cache/tc.pyx":104
+ *         tcbdbsetcmpfunc(self.db, tccmpint64, NULL)
+ *         if not tcbdbopen(self.db, filename, _modes[mode]):
+ *             raise IOError             # <<<<<<<<<<<<<<
+ *         self._opened = 1
+ * 
+ */
+    __Pyx_Raise(__pyx_builtin_IOError, 0, 0);
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 104; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L6;
+  }
+  __pyx_L6:;
+
+  /* "imposm/cache/tc.pyx":105
+ *         if not tcbdbopen(self.db, filename, _modes[mode]):
+ *             raise IOError
+ *         self._opened = 1             # <<<<<<<<<<<<<<
+ * 
+ *     def _tune_db(self, estimated_records):
+ */
+  ((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->_opened = 1;
+
+  __pyx_r = 0;
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("imposm.cache.tc.BDB.__init__");
+  __pyx_r = -1;
+  __pyx_L0:;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":107
+ *         self._opened = 1
+ * 
+ *     def _tune_db(self, estimated_records):             # <<<<<<<<<<<<<<
+ *         if estimated_records:
+ *             lmemb = 128 # default
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_2_tune_db(PyObject *__pyx_v_self, PyObject *__pyx_v_estimated_records); /*proto*/
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_2_tune_db(PyObject *__pyx_v_self, PyObject *__pyx_v_estimated_records) {
+  PyObject *__pyx_v_lmemb;
+  long __pyx_v_nmemb;
+  long __pyx_v_fpow;
+  PyObject *__pyx_v_bnum;
+  PyObject *__pyx_r = NULL;
+  int __pyx_t_1;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  TCBDB *__pyx_t_4;
+  int __pyx_t_5;
+  int __pyx_t_6;
+  int __pyx_t_7;
+  __Pyx_RefNannySetupContext("_tune_db");
+  __pyx_v_lmemb = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_v_bnum = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "imposm/cache/tc.pyx":108
+ * 
+ *     def _tune_db(self, estimated_records):
+ *         if estimated_records:             # <<<<<<<<<<<<<<
+ *             lmemb = 128 # default
+ *             nmemb = -1
+ */
+  __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_v_estimated_records); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__pyx_t_1) {
+
+    /* "imposm/cache/tc.pyx":109
+ *     def _tune_db(self, estimated_records):
+ *         if estimated_records:
+ *             lmemb = 128 # default             # <<<<<<<<<<<<<<
+ *             nmemb = -1
+ *             fpow = 13 # 2^13 = 8196
+ */
+    __Pyx_INCREF(__pyx_int_128);
+    __Pyx_DECREF(__pyx_v_lmemb);
+    __pyx_v_lmemb = __pyx_int_128;
+
+    /* "imposm/cache/tc.pyx":110
+ *         if estimated_records:
+ *             lmemb = 128 # default
+ *             nmemb = -1             # <<<<<<<<<<<<<<
+ *             fpow = 13 # 2^13 = 8196
+ *             bnum = int((estimated_records*3)/lmemb)
+ */
+    __pyx_v_nmemb = -1;
+
+    /* "imposm/cache/tc.pyx":111
+ *             lmemb = 128 # default
+ *             nmemb = -1
+ *             fpow = 13 # 2^13 = 8196             # <<<<<<<<<<<<<<
+ *             bnum = int((estimated_records*3)/lmemb)
+ *             tcbdbtune(self.db, lmemb, nmemb, bnum, 5, fpow, BDBTLARGE | BDBTDEFLATE)
+ */
+    __pyx_v_fpow = 13;
+
+    /* "imposm/cache/tc.pyx":112
+ *             nmemb = -1
+ *             fpow = 13 # 2^13 = 8196
+ *             bnum = int((estimated_records*3)/lmemb)             # <<<<<<<<<<<<<<
+ *             tcbdbtune(self.db, lmemb, nmemb, bnum, 5, fpow, BDBTLARGE | BDBTDEFLATE)
+ *         else:
+ */
+    __pyx_t_2 = PyNumber_Multiply(__pyx_v_estimated_records, __pyx_int_3); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_3 = __Pyx_PyNumber_Divide(__pyx_t_2, __pyx_v_lmemb); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+    PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_3);
+    __pyx_t_3 = 0;
+    __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)(&PyInt_Type))), ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+    __Pyx_DECREF(__pyx_v_bnum);
+    __pyx_v_bnum = __pyx_t_3;
+    __pyx_t_3 = 0;
+
+    /* "imposm/cache/tc.pyx":113
+ *             fpow = 13 # 2^13 = 8196
+ *             bnum = int((estimated_records*3)/lmemb)
+ *             tcbdbtune(self.db, lmemb, nmemb, bnum, 5, fpow, BDBTLARGE | BDBTDEFLATE)             # <<<<<<<<<<<<<<
+ *         else:
+ *             tcbdbtune(self.db, -1, -1, -1, 5, 13, BDBTLARGE | BDBTDEFLATE)
+ */
+    __pyx_t_4 = ((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->db;
+    __pyx_t_5 = __Pyx_PyInt_AsInt(__pyx_v_lmemb); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_6 = __Pyx_PyInt_AsInt(__pyx_v_bnum); if (unlikely((__pyx_t_6 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_7 = 5;
+    tcbdbtune(__pyx_t_4, __pyx_t_5, __pyx_v_nmemb, __pyx_t_6, __pyx_t_7, __pyx_v_fpow, (BDBTLARGE | BDBTDEFLATE));
+    goto __pyx_L5;
+  }
+  /*else*/ {
+
+    /* "imposm/cache/tc.pyx":115
+ *             tcbdbtune(self.db, lmemb, nmemb, bnum, 5, fpow, BDBTLARGE | BDBTDEFLATE)
+ *         else:
+ *             tcbdbtune(self.db, -1, -1, -1, 5, 13, BDBTLARGE | BDBTDEFLATE)             # <<<<<<<<<<<<<<
+ * 
+ *     def get(self, int64_t osmid):
+ */
+    tcbdbtune(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->db, -1, -1, -1, 5, 13, (BDBTLARGE | BDBTDEFLATE));
+  }
+  __pyx_L5:;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("imposm.cache.tc.BDB._tune_db");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_lmemb);
+  __Pyx_DECREF(__pyx_v_bnum);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":117
+ *             tcbdbtune(self.db, -1, -1, -1, 5, 13, BDBTLARGE | BDBTDEFLATE)
+ * 
+ *     def get(self, int64_t osmid):             # <<<<<<<<<<<<<<
+ *         """
+ *         Return object with given id.
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_3get(PyObject *__pyx_v_self, PyObject *__pyx_arg_osmid); /*proto*/
+static char __pyx_doc_6imposm_5cache_2tc_3BDB_3get[] = "\n        Return object with given id.\n        Returns None if id is not stored.\n        ";
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_3get(PyObject *__pyx_v_self, PyObject *__pyx_arg_osmid) {
+  int64_t __pyx_v_osmid;
+  void *__pyx_v_ret;
+  int __pyx_v_ret_size;
+  PyObject *__pyx_r = NULL;
+  int __pyx_t_1;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  __Pyx_RefNannySetupContext("get");
+  assert(__pyx_arg_osmid); {
+    __pyx_v_osmid = __Pyx_PyInt_from_py_int64_t(__pyx_arg_osmid); if (unlikely((__pyx_v_osmid == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 117; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.BDB.get");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+
+  /* "imposm/cache/tc.pyx":124
+ *         cdef void *ret
+ *         cdef int ret_size
+ *         ret = tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)             # <<<<<<<<<<<<<<
+ *         if not ret: return None
+ *         return self._obj(osmid, PyMarshal_ReadObjectFromString(<char *>ret, ret_size))
+ */
+  __pyx_v_ret = tcbdbget3(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->db, ((char *)(&__pyx_v_osmid)), (sizeof(int64_t)), (&__pyx_v_ret_size));
+
+  /* "imposm/cache/tc.pyx":125
+ *         cdef int ret_size
+ *         ret = tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)
+ *         if not ret: return None             # <<<<<<<<<<<<<<
+ *         return self._obj(osmid, PyMarshal_ReadObjectFromString(<char *>ret, ret_size))
+ * 
+ */
+  __pyx_t_1 = (!(__pyx_v_ret != 0));
+  if (__pyx_t_1) {
+    __Pyx_XDECREF(__pyx_r);
+    __Pyx_INCREF(Py_None);
+    __pyx_r = Py_None;
+    goto __pyx_L0;
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  /* "imposm/cache/tc.pyx":126
+ *         ret = tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)
+ *         if not ret: return None
+ *         return self._obj(osmid, PyMarshal_ReadObjectFromString(<char *>ret, ret_size))             # <<<<<<<<<<<<<<
+ * 
+ *     cdef object _obj(self, int64_t osmid, data):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_2 = PyMarshal_ReadObjectFromString(((char *)__pyx_v_ret), __pyx_v_ret_size); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = ((struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB *)((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->__pyx_vtab)->_obj(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self), __pyx_v_osmid, __pyx_t_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_r = __pyx_t_3;
+  __pyx_t_3 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("imposm.cache.tc.BDB.get");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":128
+ *         return self._obj(osmid, PyMarshal_ReadObjectFromString(<char *>ret, ret_size))
+ * 
+ *     cdef object _obj(self, int64_t osmid, data):             # <<<<<<<<<<<<<<
+ *         """
+ *         Create an object from the id and unmarshaled data.
+ */
+
+static  PyObject *__pyx_f_6imposm_5cache_2tc_3BDB__obj(struct __pyx_obj_6imposm_5cache_2tc_BDB *__pyx_v_self, int64_t __pyx_v_osmid, PyObject *__pyx_v_data) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannySetupContext("_obj");
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":135
+ *         pass
+ * 
+ *     def __iter__(self):             # <<<<<<<<<<<<<<
+ *         """
+ *         Return an iterator over the database.
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_4__iter__(PyObject *__pyx_v_self); /*proto*/
+static char __pyx_doc_6imposm_5cache_2tc_3BDB_4__iter__[] = "\n        Return an iterator over the database.\n        Resets any existing iterator.\n        ";
+struct wrapperbase __pyx_wrapperbase_6imposm_5cache_2tc_3BDB_4__iter__;
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_4__iter__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = NULL;
+  int __pyx_t_1;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  __Pyx_RefNannySetupContext("__iter__");
+
+  /* "imposm/cache/tc.pyx":140
+ *         Resets any existing iterator.
+ *         """
+ *         if self._cur:             # <<<<<<<<<<<<<<
+ *             tcbdbcurdel(self._cur)
+ *         self._cur = tcbdbcurnew(self.db)
+ */
+  __pyx_t_1 = (((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->_cur != 0);
+  if (__pyx_t_1) {
+
+    /* "imposm/cache/tc.pyx":141
+ *         """
+ *         if self._cur:
+ *             tcbdbcurdel(self._cur)             # <<<<<<<<<<<<<<
+ *         self._cur = tcbdbcurnew(self.db)
+ *         if not tcbdbcurfirst(self._cur):
+ */
+    tcbdbcurdel(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->_cur);
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  /* "imposm/cache/tc.pyx":142
+ *         if self._cur:
+ *             tcbdbcurdel(self._cur)
+ *         self._cur = tcbdbcurnew(self.db)             # <<<<<<<<<<<<<<
+ *         if not tcbdbcurfirst(self._cur):
+ *             return iter([])
+ */
+  ((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->_cur = tcbdbcurnew(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->db);
+
+  /* "imposm/cache/tc.pyx":143
+ *             tcbdbcurdel(self._cur)
+ *         self._cur = tcbdbcurnew(self.db)
+ *         if not tcbdbcurfirst(self._cur):             # <<<<<<<<<<<<<<
+ *             return iter([])
+ *         return self
+ */
+  __pyx_t_1 = (!tcbdbcurfirst(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->_cur));
+  if (__pyx_t_1) {
+
+    /* "imposm/cache/tc.pyx":144
+ *         self._cur = tcbdbcurnew(self.db)
+ *         if not tcbdbcurfirst(self._cur):
+ *             return iter([])             # <<<<<<<<<<<<<<
+ *         return self
+ * 
+ */
+    __Pyx_XDECREF(__pyx_r);
+    __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+    __pyx_t_3 = PyObject_GetIter(((PyObject *)__pyx_t_2)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+    __pyx_r = __pyx_t_3;
+    __pyx_t_3 = 0;
+    goto __pyx_L0;
+    goto __pyx_L6;
+  }
+  __pyx_L6:;
+
+  /* "imposm/cache/tc.pyx":145
+ *         if not tcbdbcurfirst(self._cur):
+ *             return iter([])
+ *         return self             # <<<<<<<<<<<<<<
+ * 
+ *     def __contains__(self, int64_t osmid):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(__pyx_v_self);
+  __pyx_r = __pyx_v_self;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("imposm.cache.tc.BDB.__iter__");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":147
+ *         return self
+ * 
+ *     def __contains__(self, int64_t osmid):             # <<<<<<<<<<<<<<
+ *         cdef void *ret
+ *         cdef int ret_size
+ */
+
+static int __pyx_pf_6imposm_5cache_2tc_3BDB_5__contains__(PyObject *__pyx_v_self, PyObject *__pyx_arg_osmid); /*proto*/
+static int __pyx_pf_6imposm_5cache_2tc_3BDB_5__contains__(PyObject *__pyx_v_self, PyObject *__pyx_arg_osmid) {
+  int64_t __pyx_v_osmid;
+  void *__pyx_v_ret;
+  int __pyx_v_ret_size;
+  int __pyx_r;
+  int __pyx_t_1;
+  __Pyx_RefNannySetupContext("__contains__");
+  assert(__pyx_arg_osmid); {
+    __pyx_v_osmid = __Pyx_PyInt_from_py_int64_t(__pyx_arg_osmid); if (unlikely((__pyx_v_osmid == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 147; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.BDB.__contains__");
+  __Pyx_RefNannyFinishContext();
+  return -1;
+  __pyx_L4_argument_unpacking_done:;
+
+  /* "imposm/cache/tc.pyx":150
+ *         cdef void *ret
+ *         cdef int ret_size
+ *         ret = tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size);             # <<<<<<<<<<<<<<
+ *         if ret:
+ *             return 1
+ */
+  __pyx_v_ret = tcbdbget3(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->db, ((char *)(&__pyx_v_osmid)), (sizeof(int64_t)), (&__pyx_v_ret_size));
+
+  /* "imposm/cache/tc.pyx":151
+ *         cdef int ret_size
+ *         ret = tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size);
+ *         if ret:             # <<<<<<<<<<<<<<
+ *             return 1
+ *         else:
+ */
+  __pyx_t_1 = (__pyx_v_ret != 0);
+  if (__pyx_t_1) {
+
+    /* "imposm/cache/tc.pyx":152
+ *         ret = tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size);
+ *         if ret:
+ *             return 1             # <<<<<<<<<<<<<<
+ *         else:
+ *             return 0
+ */
+    __pyx_r = 1;
+    goto __pyx_L0;
+    goto __pyx_L5;
+  }
+  /*else*/ {
+
+    /* "imposm/cache/tc.pyx":154
+ *             return 1
+ *         else:
+ *             return 0             # <<<<<<<<<<<<<<
+ * 
+ *     def __len__(self):
+ */
+    __pyx_r = 0;
+    goto __pyx_L0;
+  }
+  __pyx_L5:;
+
+  __pyx_r = 0;
+  __pyx_L0:;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":156
+ *             return 0
+ * 
+ *     def __len__(self):             # <<<<<<<<<<<<<<
+ *         return tcbdbrnum(self.db)
+ * 
+ */
+
+static Py_ssize_t __pyx_pf_6imposm_5cache_2tc_3BDB_6__len__(PyObject *__pyx_v_self); /*proto*/
+static Py_ssize_t __pyx_pf_6imposm_5cache_2tc_3BDB_6__len__(PyObject *__pyx_v_self) {
+  Py_ssize_t __pyx_r;
+  __Pyx_RefNannySetupContext("__len__");
+
+  /* "imposm/cache/tc.pyx":157
+ * 
+ *     def __len__(self):
+ *         return tcbdbrnum(self.db)             # <<<<<<<<<<<<<<
+ * 
+ *     def __next__(self):
+ */
+  __pyx_r = tcbdbrnum(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->db);
+  goto __pyx_L0;
+
+  __pyx_r = 0;
+  __pyx_L0:;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":159
+ *         return tcbdbrnum(self.db)
+ * 
+ *     def __next__(self):             # <<<<<<<<<<<<<<
+ *         """
+ *         Return next item as object.
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_7__next__(PyObject *__pyx_v_self); /*proto*/
+static char __pyx_doc_6imposm_5cache_2tc_3BDB_7__next__[] = "\n        Return next item as object.\n        ";
+struct wrapperbase __pyx_wrapperbase_6imposm_5cache_2tc_3BDB_7__next__;
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_7__next__(PyObject *__pyx_v_self) {
+  int64_t __pyx_v_osmid;
+  PyObject *__pyx_v_data;
+  PyObject *__pyx_r = NULL;
+  int __pyx_t_1;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  int64_t __pyx_t_5;
+  PyObject *__pyx_t_6 = NULL;
+  __Pyx_RefNannySetupContext("__next__");
+  __pyx_v_data = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "imposm/cache/tc.pyx":165
+ *         cdef int64_t osmid
+ * 
+ *         if not self._cur: raise StopIteration             # <<<<<<<<<<<<<<
+ * 
+ *         osmid, data = self._get_cur()
+ */
+  __pyx_t_1 = (!(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->_cur != 0));
+  if (__pyx_t_1) {
+    __Pyx_Raise(__pyx_builtin_StopIteration, 0, 0);
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  /* "imposm/cache/tc.pyx":167
+ *         if not self._cur: raise StopIteration
+ * 
+ *         osmid, data = self._get_cur()             # <<<<<<<<<<<<<<
+ * 
+ *         # advance cursor, set to NULL if at the end
+ */
+  __pyx_t_2 = ((struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB *)((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->__pyx_vtab)->_get_cur(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 167; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  if (PyTuple_CheckExact(__pyx_t_2) && likely(PyTuple_GET_SIZE(__pyx_t_2) == 2)) {
+    PyObject* tuple = __pyx_t_2;
+    __pyx_t_3 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_3);
+    __pyx_t_5 = __Pyx_PyInt_from_py_int64_t(__pyx_t_3); if (unlikely((__pyx_t_5 == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 167; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __pyx_t_4 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    __pyx_v_osmid = __pyx_t_5;
+    __Pyx_DECREF(__pyx_v_data);
+    __pyx_v_data = __pyx_t_4;
+    __pyx_t_4 = 0;
+  } else {
+    __pyx_t_6 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 167; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_6);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    __pyx_t_3 = __Pyx_UnpackItem(__pyx_t_6, 0); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 167; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_5 = __Pyx_PyInt_from_py_int64_t(__pyx_t_3); if (unlikely((__pyx_t_5 == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 167; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __pyx_t_4 = __Pyx_UnpackItem(__pyx_t_6, 1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 167; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    if (__Pyx_EndUnpack(__pyx_t_6, 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 167; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+    __pyx_v_osmid = __pyx_t_5;
+    __Pyx_DECREF(__pyx_v_data);
+    __pyx_v_data = __pyx_t_4;
+    __pyx_t_4 = 0;
+  }
+
+  /* "imposm/cache/tc.pyx":170
+ * 
+ *         # advance cursor, set to NULL if at the end
+ *         if tcbdbcurnext(self._cur) == 0:             # <<<<<<<<<<<<<<
+ *             tcbdbcurdel(self._cur)
+ *             self._cur = NULL
+ */
+  __pyx_t_1 = (tcbdbcurnext(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->_cur) == 0);
+  if (__pyx_t_1) {
+
+    /* "imposm/cache/tc.pyx":171
+ *         # advance cursor, set to NULL if at the end
+ *         if tcbdbcurnext(self._cur) == 0:
+ *             tcbdbcurdel(self._cur)             # <<<<<<<<<<<<<<
+ *             self._cur = NULL
+ * 
+ */
+    tcbdbcurdel(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->_cur);
+
+    /* "imposm/cache/tc.pyx":172
+ *         if tcbdbcurnext(self._cur) == 0:
+ *             tcbdbcurdel(self._cur)
+ *             self._cur = NULL             # <<<<<<<<<<<<<<
+ * 
+ *         # return objectified item
+ */
+    ((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->_cur = NULL;
+    goto __pyx_L6;
+  }
+  __pyx_L6:;
+
+  /* "imposm/cache/tc.pyx":175
+ * 
+ *         # return objectified item
+ *         return self._obj(osmid, data)             # <<<<<<<<<<<<<<
+ * 
+ *     cdef object _get_cur(self):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_2 = ((struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB *)((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->__pyx_vtab)->_obj(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self), __pyx_v_osmid, __pyx_v_data); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 175; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_r = __pyx_t_2;
+  __pyx_t_2 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_AddTraceback("imposm.cache.tc.BDB.__next__");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_data);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":177
+ *         return self._obj(osmid, data)
+ * 
+ *     cdef object _get_cur(self):             # <<<<<<<<<<<<<<
+ *         """
+ *         Return the current object at the current cursor position
+ */
+
+static  PyObject *__pyx_f_6imposm_5cache_2tc_3BDB__get_cur(struct __pyx_obj_6imposm_5cache_2tc_BDB *__pyx_v_self) {
+  int __pyx_v_size;
+  void *__pyx_v_ret;
+  int64_t __pyx_v_osmid;
+  PyObject *__pyx_v_value;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  __Pyx_RefNannySetupContext("_get_cur");
+  __pyx_v_value = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "imposm/cache/tc.pyx":184
+ *         cdef int size
+ *         cdef void *ret
+ *         ret = tcbdbcurkey3(self._cur, &size)             # <<<<<<<<<<<<<<
+ *         osmid = (<int64_t *>ret)[0]
+ *         ret = tcbdbcurval3(self._cur, &size)
+ */
+  __pyx_v_ret = tcbdbcurkey3(__pyx_v_self->_cur, (&__pyx_v_size));
+
+  /* "imposm/cache/tc.pyx":185
+ *         cdef void *ret
+ *         ret = tcbdbcurkey3(self._cur, &size)
+ *         osmid = (<int64_t *>ret)[0]             # <<<<<<<<<<<<<<
+ *         ret = tcbdbcurval3(self._cur, &size)
+ *         value = PyMarshal_ReadObjectFromString(<char *>ret, size)
+ */
+  __pyx_v_osmid = (((int64_t *)__pyx_v_ret)[0]);
+
+  /* "imposm/cache/tc.pyx":186
+ *         ret = tcbdbcurkey3(self._cur, &size)
+ *         osmid = (<int64_t *>ret)[0]
+ *         ret = tcbdbcurval3(self._cur, &size)             # <<<<<<<<<<<<<<
+ *         value = PyMarshal_ReadObjectFromString(<char *>ret, size)
+ *         return osmid, value
+ */
+  __pyx_v_ret = tcbdbcurval3(__pyx_v_self->_cur, (&__pyx_v_size));
+
+  /* "imposm/cache/tc.pyx":187
+ *         osmid = (<int64_t *>ret)[0]
+ *         ret = tcbdbcurval3(self._cur, &size)
+ *         value = PyMarshal_ReadObjectFromString(<char *>ret, size)             # <<<<<<<<<<<<<<
+ *         return osmid, value
+ * 
+ */
+  __pyx_t_1 = PyMarshal_ReadObjectFromString(((char *)__pyx_v_ret), __pyx_v_size); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 187; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(__pyx_v_value);
+  __pyx_v_value = __pyx_t_1;
+  __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":188
+ *         ret = tcbdbcurval3(self._cur, &size)
+ *         value = PyMarshal_ReadObjectFromString(<char *>ret, size)
+ *         return osmid, value             # <<<<<<<<<<<<<<
+ * 
+ *     def close(self):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 188; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 188; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1);
+  __Pyx_GIVEREF(__pyx_t_1);
+  __Pyx_INCREF(__pyx_v_value);
+  PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_value);
+  __Pyx_GIVEREF(__pyx_v_value);
+  __pyx_t_1 = 0;
+  __pyx_r = ((PyObject *)__pyx_t_2);
+  __pyx_t_2 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("imposm.cache.tc.BDB._get_cur");
+  __pyx_r = 0;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_value);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":190
+ *         return osmid, value
+ * 
+ *     def close(self):             # <<<<<<<<<<<<<<
+ *         if self._opened:
+ *             tcbdbclose(self.db)
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_8close(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_8close(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannySetupContext("close");
+
+  /* "imposm/cache/tc.pyx":191
+ * 
+ *     def close(self):
+ *         if self._opened:             # <<<<<<<<<<<<<<
+ *             tcbdbclose(self.db)
+ *         self._opened = 0
+ */
+  if (((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->_opened) {
+
+    /* "imposm/cache/tc.pyx":192
+ *     def close(self):
+ *         if self._opened:
+ *             tcbdbclose(self.db)             # <<<<<<<<<<<<<<
+ *         self._opened = 0
+ * 
+ */
+    tcbdbclose(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->db);
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  /* "imposm/cache/tc.pyx":193
+ *         if self._opened:
+ *             tcbdbclose(self.db)
+ *         self._opened = 0             # <<<<<<<<<<<<<<
+ * 
+ *     def __dealloc__(self):
+ */
+  ((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->_opened = 0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":195
+ *         self._opened = 0
+ * 
+ *     def __dealloc__(self):             # <<<<<<<<<<<<<<
+ *         if self._opened:
+ *             tcbdbclose(self.db)
+ */
+
+static void __pyx_pf_6imposm_5cache_2tc_3BDB_9__dealloc__(PyObject *__pyx_v_self); /*proto*/
+static void __pyx_pf_6imposm_5cache_2tc_3BDB_9__dealloc__(PyObject *__pyx_v_self) {
+  __Pyx_RefNannySetupContext("__dealloc__");
+
+  /* "imposm/cache/tc.pyx":196
+ * 
+ *     def __dealloc__(self):
+ *         if self._opened:             # <<<<<<<<<<<<<<
+ *             tcbdbclose(self.db)
+ *         tcbdbdel(self.db)
+ */
+  if (((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->_opened) {
+
+    /* "imposm/cache/tc.pyx":197
+ *     def __dealloc__(self):
+ *         if self._opened:
+ *             tcbdbclose(self.db)             # <<<<<<<<<<<<<<
+ *         tcbdbdel(self.db)
+ * 
+ */
+    tcbdbclose(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->db);
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  /* "imposm/cache/tc.pyx":198
+ *         if self._opened:
+ *             tcbdbclose(self.db)
+ *         tcbdbdel(self.db)             # <<<<<<<<<<<<<<
+ * 
+ * cdef class CoordDB(BDB):
+ */
+  tcbdbdel(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->db);
+
+  __Pyx_RefNannyFinishContext();
+}
+
+/* "imposm/cache/tc.pyx":201
+ * 
+ * cdef class CoordDB(BDB):
+ *     def put(self, osmid, x, y):             # <<<<<<<<<<<<<<
+ *         return self._put(osmid, x, y)
+ * 
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_put(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_put(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_osmid = 0;
+  PyObject *__pyx_v_x = 0;
+  PyObject *__pyx_v_y = 0;
+  PyObject *__pyx_r = NULL;
+  int64_t __pyx_t_1;
+  double __pyx_t_2;
+  double __pyx_t_3;
+  PyObject *__pyx_t_4 = NULL;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__osmid,&__pyx_n_s__x,&__pyx_n_s__y,0};
+  __Pyx_RefNannySetupContext("put");
+  if (unlikely(__pyx_kwds)) {
+    Py_ssize_t kw_args = PyDict_Size(__pyx_kwds);
+    PyObject* values[3] = {0,0,0};
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
+      case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+      case  0: break;
+      default: goto __pyx_L5_argtuple_error;
+    }
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  0:
+      values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__osmid);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__x);
+      if (likely(values[1])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("put", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 201; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+      case  2:
+      values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__y);
+      if (likely(values[2])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("put", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 201; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    }
+    if (unlikely(kw_args > 0)) {
+      if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "put") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 201; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_osmid = values[0];
+    __pyx_v_x = values[1];
+    __pyx_v_y = values[2];
+  } else if (PyTuple_GET_SIZE(__pyx_args) != 3) {
+    goto __pyx_L5_argtuple_error;
+  } else {
+    __pyx_v_osmid = PyTuple_GET_ITEM(__pyx_args, 0);
+    __pyx_v_x = PyTuple_GET_ITEM(__pyx_args, 1);
+    __pyx_v_y = PyTuple_GET_ITEM(__pyx_args, 2);
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("put", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 201; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.CoordDB.put");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+
+  /* "imposm/cache/tc.pyx":202
+ * cdef class CoordDB(BDB):
+ *     def put(self, osmid, x, y):
+ *         return self._put(osmid, x, y)             # <<<<<<<<<<<<<<
+ * 
+ *     def put_marshaled(self, osmid, x, y):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = __Pyx_PyInt_from_py_int64_t(__pyx_v_osmid); if (unlikely((__pyx_t_1 == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 202; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __pyx_PyFloat_AsDouble(__pyx_v_x); if (unlikely((__pyx_t_2 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 202; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __pyx_PyFloat_AsDouble(__pyx_v_y); if (unlikely((__pyx_t_3 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 202; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_4 = __Pyx_PyBool_FromLong(((struct __pyx_vtabstruct_6imposm_5cache_2tc_CoordDB *)((struct __pyx_obj_6imposm_5cache_2tc_CoordDB *)__pyx_v_self)->__pyx_base.__pyx_vtab)->_put(((struct __pyx_obj_6imposm_5cache_2tc_CoordDB *)__pyx_v_self), __pyx_t_1, __pyx_t_2, __pyx_t_3)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 202; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_r = __pyx_t_4;
+  __pyx_t_4 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("imposm.cache.tc.CoordDB.put");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":204
+ *         return self._put(osmid, x, y)
+ * 
+ *     def put_marshaled(self, osmid, x, y):             # <<<<<<<<<<<<<<
+ *         return self._put(osmid, x, y)
+ * 
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_1put_marshaled(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_1put_marshaled(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_osmid = 0;
+  PyObject *__pyx_v_x = 0;
+  PyObject *__pyx_v_y = 0;
+  PyObject *__pyx_r = NULL;
+  int64_t __pyx_t_1;
+  double __pyx_t_2;
+  double __pyx_t_3;
+  PyObject *__pyx_t_4 = NULL;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__osmid,&__pyx_n_s__x,&__pyx_n_s__y,0};
+  __Pyx_RefNannySetupContext("put_marshaled");
+  if (unlikely(__pyx_kwds)) {
+    Py_ssize_t kw_args = PyDict_Size(__pyx_kwds);
+    PyObject* values[3] = {0,0,0};
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
+      case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+      case  0: break;
+      default: goto __pyx_L5_argtuple_error;
+    }
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  0:
+      values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__osmid);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__x);
+      if (likely(values[1])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("put_marshaled", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 204; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+      case  2:
+      values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__y);
+      if (likely(values[2])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("put_marshaled", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 204; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    }
+    if (unlikely(kw_args > 0)) {
+      if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "put_marshaled") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 204; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_osmid = values[0];
+    __pyx_v_x = values[1];
+    __pyx_v_y = values[2];
+  } else if (PyTuple_GET_SIZE(__pyx_args) != 3) {
+    goto __pyx_L5_argtuple_error;
+  } else {
+    __pyx_v_osmid = PyTuple_GET_ITEM(__pyx_args, 0);
+    __pyx_v_x = PyTuple_GET_ITEM(__pyx_args, 1);
+    __pyx_v_y = PyTuple_GET_ITEM(__pyx_args, 2);
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("put_marshaled", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 204; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.CoordDB.put_marshaled");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+
+  /* "imposm/cache/tc.pyx":205
+ * 
+ *     def put_marshaled(self, osmid, x, y):
+ *         return self._put(osmid, x, y)             # <<<<<<<<<<<<<<
+ * 
+ *     cdef bint _put(self, int64_t osmid, double x, double y) nogil:
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = __Pyx_PyInt_from_py_int64_t(__pyx_v_osmid); if (unlikely((__pyx_t_1 == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 205; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __pyx_PyFloat_AsDouble(__pyx_v_x); if (unlikely((__pyx_t_2 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 205; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __pyx_PyFloat_AsDouble(__pyx_v_y); if (unlikely((__pyx_t_3 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 205; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_4 = __Pyx_PyBool_FromLong(((struct __pyx_vtabstruct_6imposm_5cache_2tc_CoordDB *)((struct __pyx_obj_6imposm_5cache_2tc_CoordDB *)__pyx_v_self)->__pyx_base.__pyx_vtab)->_put(((struct __pyx_obj_6imposm_5cache_2tc_CoordDB *)__pyx_v_self), __pyx_t_1, __pyx_t_2, __pyx_t_3)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 205; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_r = __pyx_t_4;
+  __pyx_t_4 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("imposm.cache.tc.CoordDB.put_marshaled");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":207
+ *         return self._put(osmid, x, y)
+ * 
+ *     cdef bint _put(self, int64_t osmid, double x, double y) nogil:             # <<<<<<<<<<<<<<
+ *         cdef coord p = coord_struct(x, y)
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>&p, sizeof(coord))
+ */
+
+static  int __pyx_f_6imposm_5cache_2tc_7CoordDB__put(struct __pyx_obj_6imposm_5cache_2tc_CoordDB *__pyx_v_self, int64_t __pyx_v_osmid, double __pyx_v_x, double __pyx_v_y) {
+  __pyx_t_6imposm_5cache_2tc_coord __pyx_v_p;
+  int __pyx_r;
+
+  /* "imposm/cache/tc.pyx":208
+ * 
+ *     cdef bint _put(self, int64_t osmid, double x, double y) nogil:
+ *         cdef coord p = coord_struct(x, y)             # <<<<<<<<<<<<<<
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>&p, sizeof(coord))
+ * 
+ */
+  __pyx_v_p = __pyx_f_6imposm_5cache_2tc_coord_struct(__pyx_v_x, __pyx_v_y);
+
+  /* "imposm/cache/tc.pyx":209
+ *     cdef bint _put(self, int64_t osmid, double x, double y) nogil:
+ *         cdef coord p = coord_struct(x, y)
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>&p, sizeof(coord))             # <<<<<<<<<<<<<<
+ * 
+ *     def get(self, int64_t osmid):
+ */
+  __pyx_r = tcbdbput(__pyx_v_self->__pyx_base.db, ((char *)(&__pyx_v_osmid)), (sizeof(int64_t)), ((char *)(&__pyx_v_p)), (sizeof(__pyx_t_6imposm_5cache_2tc_coord)));
+  goto __pyx_L0;
+
+  __pyx_r = 0;
+  __pyx_L0:;
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":211
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>&p, sizeof(coord))
+ * 
+ *     def get(self, int64_t osmid):             # <<<<<<<<<<<<<<
+ *         cdef coord *value
+ *         cdef int ret_size
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_2get(PyObject *__pyx_v_self, PyObject *__pyx_arg_osmid); /*proto*/
+static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_2get(PyObject *__pyx_v_self, PyObject *__pyx_arg_osmid) {
+  int64_t __pyx_v_osmid;
+  __pyx_t_6imposm_5cache_2tc_coord *__pyx_v_value;
+  int __pyx_v_ret_size;
+  PyObject *__pyx_r = NULL;
+  int __pyx_t_1;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  __Pyx_RefNannySetupContext("get");
+  assert(__pyx_arg_osmid); {
+    __pyx_v_osmid = __Pyx_PyInt_from_py_int64_t(__pyx_arg_osmid); if (unlikely((__pyx_v_osmid == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 211; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.CoordDB.get");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+
+  /* "imposm/cache/tc.pyx":214
+ *         cdef coord *value
+ *         cdef int ret_size
+ *         value = <coord *>tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)             # <<<<<<<<<<<<<<
+ *         if not value: return
+ *         return _uint32_to_coord(value.x), _uint32_to_coord(value.y)
+ */
+  __pyx_v_value = ((__pyx_t_6imposm_5cache_2tc_coord *)tcbdbget3(((struct __pyx_obj_6imposm_5cache_2tc_CoordDB *)__pyx_v_self)->__pyx_base.db, ((char *)(&__pyx_v_osmid)), (sizeof(int64_t)), (&__pyx_v_ret_size)));
+
+  /* "imposm/cache/tc.pyx":215
+ *         cdef int ret_size
+ *         value = <coord *>tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)
+ *         if not value: return             # <<<<<<<<<<<<<<
+ *         return _uint32_to_coord(value.x), _uint32_to_coord(value.y)
+ * 
+ */
+  __pyx_t_1 = (!(__pyx_v_value != 0));
+  if (__pyx_t_1) {
+    __Pyx_XDECREF(__pyx_r);
+    __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+    goto __pyx_L0;
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  /* "imposm/cache/tc.pyx":216
+ *         value = <coord *>tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)
+ *         if not value: return
+ *         return _uint32_to_coord(value.x), _uint32_to_coord(value.y)             # <<<<<<<<<<<<<<
+ * 
+ *     def get_coords(self, refs):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_2 = PyFloat_FromDouble(__pyx_f_6imposm_5cache_2tc__uint32_to_coord(__pyx_v_value->x)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 216; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyFloat_FromDouble(__pyx_f_6imposm_5cache_2tc__uint32_to_coord(__pyx_v_value->y)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 216; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 216; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_4));
+  PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2);
+  __Pyx_GIVEREF(__pyx_t_2);
+  PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_3);
+  __Pyx_GIVEREF(__pyx_t_3);
+  __pyx_t_2 = 0;
+  __pyx_t_3 = 0;
+  __pyx_r = ((PyObject *)__pyx_t_4);
+  __pyx_t_4 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("imposm.cache.tc.CoordDB.get");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":218
+ *         return _uint32_to_coord(value.x), _uint32_to_coord(value.y)
+ * 
+ *     def get_coords(self, refs):             # <<<<<<<<<<<<<<
+ *         cdef coord *value
+ *         cdef int ret_size
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_3get_coords(PyObject *__pyx_v_self, PyObject *__pyx_v_refs); /*proto*/
+static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_3get_coords(PyObject *__pyx_v_self, PyObject *__pyx_v_refs) {
+  __pyx_t_6imposm_5cache_2tc_coord *__pyx_v_value;
+  int __pyx_v_ret_size;
+  int64_t __pyx_v_osmid;
+  PyObject *__pyx_v_coords;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  Py_ssize_t __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  int64_t __pyx_t_4;
+  int __pyx_t_5;
+  PyObject *__pyx_t_6 = NULL;
+  PyObject *__pyx_t_7 = NULL;
+  int __pyx_t_8;
+  __Pyx_RefNannySetupContext("get_coords");
+  __pyx_v_coords = ((PyObject*)Py_None); __Pyx_INCREF(Py_None);
+
+  /* "imposm/cache/tc.pyx":222
+ *         cdef int ret_size
+ *         cdef int64_t osmid
+ *         coords = list()             # <<<<<<<<<<<<<<
+ *         for osmid in refs:
+ *             value = <coord *>tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)
+ */
+  __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 222; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __Pyx_DECREF(((PyObject *)__pyx_v_coords));
+  __pyx_v_coords = __pyx_t_1;
+  __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":223
+ *         cdef int64_t osmid
+ *         coords = list()
+ *         for osmid in refs:             # <<<<<<<<<<<<<<
+ *             value = <coord *>tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)
+ *             if not value: return
+ */
+  if (PyList_CheckExact(__pyx_v_refs) || PyTuple_CheckExact(__pyx_v_refs)) {
+    __pyx_t_2 = 0; __pyx_t_1 = __pyx_v_refs; __Pyx_INCREF(__pyx_t_1);
+  } else {
+    __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_refs); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 223; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+  }
+  for (;;) {
+    if (likely(PyList_CheckExact(__pyx_t_1))) {
+      if (__pyx_t_2 >= PyList_GET_SIZE(__pyx_t_1)) break;
+      __pyx_t_3 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++;
+    } else if (likely(PyTuple_CheckExact(__pyx_t_1))) {
+      if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
+      __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++;
+    } else {
+      __pyx_t_3 = PyIter_Next(__pyx_t_1);
+      if (!__pyx_t_3) {
+        if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 223; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        break;
+      }
+      __Pyx_GOTREF(__pyx_t_3);
+    }
+    __pyx_t_4 = __Pyx_PyInt_from_py_int64_t(__pyx_t_3); if (unlikely((__pyx_t_4 == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 223; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __pyx_v_osmid = __pyx_t_4;
+
+    /* "imposm/cache/tc.pyx":224
+ *         coords = list()
+ *         for osmid in refs:
+ *             value = <coord *>tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)             # <<<<<<<<<<<<<<
+ *             if not value: return
+ *             coords.append((_uint32_to_coord(value.x), _uint32_to_coord(value.y)))
+ */
+    __pyx_v_value = ((__pyx_t_6imposm_5cache_2tc_coord *)tcbdbget3(((struct __pyx_obj_6imposm_5cache_2tc_CoordDB *)__pyx_v_self)->__pyx_base.db, ((char *)(&__pyx_v_osmid)), (sizeof(int64_t)), (&__pyx_v_ret_size)));
+
+    /* "imposm/cache/tc.pyx":225
+ *         for osmid in refs:
+ *             value = <coord *>tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)
+ *             if not value: return             # <<<<<<<<<<<<<<
+ *             coords.append((_uint32_to_coord(value.x), _uint32_to_coord(value.y)))
+ * 
+ */
+    __pyx_t_5 = (!(__pyx_v_value != 0));
+    if (__pyx_t_5) {
+      __Pyx_XDECREF(__pyx_r);
+      __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+      goto __pyx_L0;
+      goto __pyx_L7;
+    }
+    __pyx_L7:;
+
+    /* "imposm/cache/tc.pyx":226
+ *             value = <coord *>tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)
+ *             if not value: return
+ *             coords.append((_uint32_to_coord(value.x), _uint32_to_coord(value.y)))             # <<<<<<<<<<<<<<
+ * 
+ *         return coords
+ */
+    if (unlikely(__pyx_v_coords == Py_None)) {
+      PyErr_SetString(PyExc_AttributeError, "'NoneType' object has no attribute 'append'"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 226; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 
+    }
+    __pyx_t_3 = PyFloat_FromDouble(__pyx_f_6imposm_5cache_2tc__uint32_to_coord(__pyx_v_value->x)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 226; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_6 = PyFloat_FromDouble(__pyx_f_6imposm_5cache_2tc__uint32_to_coord(__pyx_v_value->y)); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 226; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_6);
+    __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 226; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_7));
+    PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_3);
+    PyTuple_SET_ITEM(__pyx_t_7, 1, __pyx_t_6);
+    __Pyx_GIVEREF(__pyx_t_6);
+    __pyx_t_3 = 0;
+    __pyx_t_6 = 0;
+    __pyx_t_8 = PyList_Append(__pyx_v_coords, ((PyObject *)__pyx_t_7)); if (unlikely(__pyx_t_8 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 226; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(((PyObject *)__pyx_t_7)); __pyx_t_7 = 0;
+  }
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":228
+ *             coords.append((_uint32_to_coord(value.x), _uint32_to_coord(value.y)))
+ * 
+ *         return coords             # <<<<<<<<<<<<<<
+ * 
+ *     cdef object _get_cur(self):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_coords));
+  __pyx_r = ((PyObject *)__pyx_v_coords);
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_XDECREF(__pyx_t_7);
+  __Pyx_AddTraceback("imposm.cache.tc.CoordDB.get_coords");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_coords);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":230
+ *         return coords
+ * 
+ *     cdef object _get_cur(self):             # <<<<<<<<<<<<<<
+ *         cdef int size
+ *         cdef int64_t osmid
+ */
+
+static  PyObject *__pyx_f_6imposm_5cache_2tc_7CoordDB__get_cur(struct __pyx_obj_6imposm_5cache_2tc_CoordDB *__pyx_v_self) {
+  int __pyx_v_size;
+  int64_t __pyx_v_osmid;
+  void *__pyx_v_ret;
+  __pyx_t_6imposm_5cache_2tc_coord *__pyx_v_value;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  __Pyx_RefNannySetupContext("_get_cur");
+
+  /* "imposm/cache/tc.pyx":235
+ *         cdef void *ret
+ *         cdef coord *value
+ *         ret = tcbdbcurkey3(self._cur, &size)             # <<<<<<<<<<<<<<
+ *         osmid = (<int64_t *>ret)[0]
+ *         value = <coord *>tcbdbcurval3(self._cur, &size)
+ */
+  __pyx_v_ret = tcbdbcurkey3(__pyx_v_self->__pyx_base._cur, (&__pyx_v_size));
+
+  /* "imposm/cache/tc.pyx":236
+ *         cdef coord *value
+ *         ret = tcbdbcurkey3(self._cur, &size)
+ *         osmid = (<int64_t *>ret)[0]             # <<<<<<<<<<<<<<
+ *         value = <coord *>tcbdbcurval3(self._cur, &size)
+ *         return osmid, (_uint32_to_coord(value.x), _uint32_to_coord(value.y))
+ */
+  __pyx_v_osmid = (((int64_t *)__pyx_v_ret)[0]);
+
+  /* "imposm/cache/tc.pyx":237
+ *         ret = tcbdbcurkey3(self._cur, &size)
+ *         osmid = (<int64_t *>ret)[0]
+ *         value = <coord *>tcbdbcurval3(self._cur, &size)             # <<<<<<<<<<<<<<
+ *         return osmid, (_uint32_to_coord(value.x), _uint32_to_coord(value.y))
+ * 
+ */
+  __pyx_v_value = ((__pyx_t_6imposm_5cache_2tc_coord *)tcbdbcurval3(__pyx_v_self->__pyx_base._cur, (&__pyx_v_size)));
+
+  /* "imposm/cache/tc.pyx":238
+ *         osmid = (<int64_t *>ret)[0]
+ *         value = <coord *>tcbdbcurval3(self._cur, &size)
+ *         return osmid, (_uint32_to_coord(value.x), _uint32_to_coord(value.y))             # <<<<<<<<<<<<<<
+ * 
+ *     cdef object _obj(self, int64_t osmid, data):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 238; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyFloat_FromDouble(__pyx_f_6imposm_5cache_2tc__uint32_to_coord(__pyx_v_value->x)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 238; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyFloat_FromDouble(__pyx_f_6imposm_5cache_2tc__uint32_to_coord(__pyx_v_value->y)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 238; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 238; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_4));
+  PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2);
+  __Pyx_GIVEREF(__pyx_t_2);
+  PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_3);
+  __Pyx_GIVEREF(__pyx_t_3);
+  __pyx_t_2 = 0;
+  __pyx_t_3 = 0;
+  __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 238; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_3));
+  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1);
+  __Pyx_GIVEREF(__pyx_t_1);
+  PyTuple_SET_ITEM(__pyx_t_3, 1, ((PyObject *)__pyx_t_4));
+  __Pyx_GIVEREF(((PyObject *)__pyx_t_4));
+  __pyx_t_1 = 0;
+  __pyx_t_4 = 0;
+  __pyx_r = ((PyObject *)__pyx_t_3);
+  __pyx_t_3 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("imposm.cache.tc.CoordDB._get_cur");
+  __pyx_r = 0;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":240
+ *         return osmid, (_uint32_to_coord(value.x), _uint32_to_coord(value.y))
+ * 
+ *     cdef object _obj(self, int64_t osmid, data):             # <<<<<<<<<<<<<<
+ *         return osmid, data
+ * 
+ */
+
+static  PyObject *__pyx_f_6imposm_5cache_2tc_7CoordDB__obj(struct __pyx_obj_6imposm_5cache_2tc_CoordDB *__pyx_v_self, int64_t __pyx_v_osmid, PyObject *__pyx_v_data) {
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  __Pyx_RefNannySetupContext("_obj");
+
+  /* "imposm/cache/tc.pyx":241
+ * 
+ *     cdef object _obj(self, int64_t osmid, data):
+ *         return osmid, data             # <<<<<<<<<<<<<<
+ * 
+ * cdef class NodeDB(BDB):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 241; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 241; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1);
+  __Pyx_GIVEREF(__pyx_t_1);
+  __Pyx_INCREF(__pyx_v_data);
+  PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_data);
+  __Pyx_GIVEREF(__pyx_v_data);
+  __pyx_t_1 = 0;
+  __pyx_r = ((PyObject *)__pyx_t_2);
+  __pyx_t_2 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("imposm.cache.tc.CoordDB._obj");
+  __pyx_r = 0;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":244
+ * 
+ * cdef class NodeDB(BDB):
+ *     def put(self, osmid, tags, pos):             # <<<<<<<<<<<<<<
+ *         return self.put_marshaled(osmid, PyMarshal_WriteObjectToString((tags, pos), 2))
+ * 
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_6NodeDB_put(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pf_6imposm_5cache_2tc_6NodeDB_put(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_osmid = 0;
+  PyObject *__pyx_v_tags = 0;
+  PyObject *__pyx_v_pos = 0;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__osmid,&__pyx_n_s__tags,&__pyx_n_s__pos,0};
+  __Pyx_RefNannySetupContext("put");
+  if (unlikely(__pyx_kwds)) {
+    Py_ssize_t kw_args = PyDict_Size(__pyx_kwds);
+    PyObject* values[3] = {0,0,0};
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
+      case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+      case  0: break;
+      default: goto __pyx_L5_argtuple_error;
+    }
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  0:
+      values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__osmid);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__tags);
+      if (likely(values[1])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("put", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 244; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+      case  2:
+      values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__pos);
+      if (likely(values[2])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("put", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 244; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    }
+    if (unlikely(kw_args > 0)) {
+      if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "put") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 244; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_osmid = values[0];
+    __pyx_v_tags = values[1];
+    __pyx_v_pos = values[2];
+  } else if (PyTuple_GET_SIZE(__pyx_args) != 3) {
+    goto __pyx_L5_argtuple_error;
+  } else {
+    __pyx_v_osmid = PyTuple_GET_ITEM(__pyx_args, 0);
+    __pyx_v_tags = PyTuple_GET_ITEM(__pyx_args, 1);
+    __pyx_v_pos = PyTuple_GET_ITEM(__pyx_args, 2);
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("put", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 244; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.NodeDB.put");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+
+  /* "imposm/cache/tc.pyx":245
+ * cdef class NodeDB(BDB):
+ *     def put(self, osmid, tags, pos):
+ *         return self.put_marshaled(osmid, PyMarshal_WriteObjectToString((tags, pos), 2))             # <<<<<<<<<<<<<<
+ * 
+ *     def put_marshaled(self, int64_t osmid, data):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__put_marshaled); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  __Pyx_INCREF(__pyx_v_tags);
+  PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_v_tags);
+  __Pyx_GIVEREF(__pyx_v_tags);
+  __Pyx_INCREF(__pyx_v_pos);
+  PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_pos);
+  __Pyx_GIVEREF(__pyx_v_pos);
+  __pyx_t_3 = PyMarshal_WriteObjectToString(((PyObject *)__pyx_t_2), 2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  __Pyx_INCREF(__pyx_v_osmid);
+  PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_v_osmid);
+  __Pyx_GIVEREF(__pyx_v_osmid);
+  PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_3);
+  __Pyx_GIVEREF(__pyx_t_3);
+  __pyx_t_3 = 0;
+  __pyx_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+  __pyx_r = __pyx_t_3;
+  __pyx_t_3 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("imposm.cache.tc.NodeDB.put");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":247
+ *         return self.put_marshaled(osmid, PyMarshal_WriteObjectToString((tags, pos), 2))
+ * 
+ *     def put_marshaled(self, int64_t osmid, data):             # <<<<<<<<<<<<<<
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>data, len(data))
+ * 
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_6NodeDB_1put_marshaled(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pf_6imposm_5cache_2tc_6NodeDB_1put_marshaled(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  int64_t __pyx_v_osmid;
+  PyObject *__pyx_v_data = 0;
+  PyObject *__pyx_r = NULL;
+  TCBDB *__pyx_t_1;
+  char *__pyx_t_2;
+  size_t __pyx_t_3;
+  char *__pyx_t_4;
+  char *__pyx_t_5;
+  PyObject *__pyx_t_6 = NULL;
+  Py_ssize_t __pyx_t_7;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__osmid,&__pyx_n_s__data,0};
+  __Pyx_RefNannySetupContext("put_marshaled");
+  if (unlikely(__pyx_kwds)) {
+    Py_ssize_t kw_args = PyDict_Size(__pyx_kwds);
+    PyObject* values[2] = {0,0};
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+      case  0: break;
+      default: goto __pyx_L5_argtuple_error;
+    }
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  0:
+      values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__osmid);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__data);
+      if (likely(values[1])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("put_marshaled", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 247; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    }
+    if (unlikely(kw_args > 0)) {
+      if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "put_marshaled") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 247; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_osmid = __Pyx_PyInt_from_py_int64_t(values[0]); if (unlikely((__pyx_v_osmid == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 247; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_data = values[1];
+  } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
+    goto __pyx_L5_argtuple_error;
+  } else {
+    __pyx_v_osmid = __Pyx_PyInt_from_py_int64_t(PyTuple_GET_ITEM(__pyx_args, 0)); if (unlikely((__pyx_v_osmid == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 247; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_data = PyTuple_GET_ITEM(__pyx_args, 1);
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("put_marshaled", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 247; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.NodeDB.put_marshaled");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+
+  /* "imposm/cache/tc.pyx":248
+ * 
+ *     def put_marshaled(self, int64_t osmid, data):
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>data, len(data))             # <<<<<<<<<<<<<<
+ * 
+ *     cdef object _obj(self, int64_t osmid, data):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = ((struct __pyx_obj_6imposm_5cache_2tc_NodeDB *)__pyx_v_self)->__pyx_base.db;
+  __pyx_t_2 = ((char *)(&__pyx_v_osmid));
+  __pyx_t_3 = (sizeof(int64_t));
+  __pyx_t_4 = PyBytes_AsString(__pyx_v_data); if (unlikely((!__pyx_t_4) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 248; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_5 = __pyx_t_4;
+  __pyx_t_6 = __pyx_v_data;
+  __Pyx_INCREF(__pyx_t_6);
+  __pyx_t_7 = PyObject_Length(__pyx_t_6); if (unlikely(__pyx_t_7 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 248; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+  __pyx_t_6 = __Pyx_PyBool_FromLong(tcbdbput(__pyx_t_1, __pyx_t_2, __pyx_t_3, __pyx_t_5, __pyx_t_7)); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 248; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_6);
+  __pyx_r = __pyx_t_6;
+  __pyx_t_6 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_AddTraceback("imposm.cache.tc.NodeDB.put_marshaled");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":250
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>data, len(data))
+ * 
+ *     cdef object _obj(self, int64_t osmid, data):             # <<<<<<<<<<<<<<
+ *         return Node(osmid, data[0], data[1])
+ * 
+ */
+
+static  PyObject *__pyx_f_6imposm_5cache_2tc_6NodeDB__obj(struct __pyx_obj_6imposm_5cache_2tc_NodeDB *__pyx_v_self, int64_t __pyx_v_osmid, PyObject *__pyx_v_data) {
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  PyObject *__pyx_t_5 = NULL;
+  __Pyx_RefNannySetupContext("_obj");
+
+  /* "imposm/cache/tc.pyx":251
+ * 
+ *     cdef object _obj(self, int64_t osmid, data):
+ *         return Node(osmid, data[0], data[1])             # <<<<<<<<<<<<<<
+ * 
+ * cdef class RefTagDB(BDB):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s__Node); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 251; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 251; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_data, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 251; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_data, 1, sizeof(long), PyInt_FromLong); if (!__pyx_t_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 251; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_t_5 = PyTuple_New(3); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 251; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_5));
+  PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_2);
+  __Pyx_GIVEREF(__pyx_t_2);
+  PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_3);
+  __Pyx_GIVEREF(__pyx_t_3);
+  PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_t_4);
+  __Pyx_GIVEREF(__pyx_t_4);
+  __pyx_t_2 = 0;
+  __pyx_t_3 = 0;
+  __pyx_t_4 = 0;
+  __pyx_t_4 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 251; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
+  __pyx_r = __pyx_t_4;
+  __pyx_t_4 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_AddTraceback("imposm.cache.tc.NodeDB._obj");
+  __pyx_r = 0;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":257
+ *     Database for items with references and tags (i.e. ways/relations).
+ *     """
+ *     def put(self, osmid, tags, refs):             # <<<<<<<<<<<<<<
+ *         return self.put_marshaled(osmid, PyMarshal_WriteObjectToString((tags, refs), 2))
+ * 
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_8RefTagDB_put(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pf_6imposm_5cache_2tc_8RefTagDB_put(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_osmid = 0;
+  PyObject *__pyx_v_tags = 0;
+  PyObject *__pyx_v_refs = 0;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__osmid,&__pyx_n_s__tags,&__pyx_n_s__refs,0};
+  __Pyx_RefNannySetupContext("put");
+  if (unlikely(__pyx_kwds)) {
+    Py_ssize_t kw_args = PyDict_Size(__pyx_kwds);
+    PyObject* values[3] = {0,0,0};
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
+      case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+      case  0: break;
+      default: goto __pyx_L5_argtuple_error;
+    }
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  0:
+      values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__osmid);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__tags);
+      if (likely(values[1])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("put", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 257; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+      case  2:
+      values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__refs);
+      if (likely(values[2])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("put", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 257; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    }
+    if (unlikely(kw_args > 0)) {
+      if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "put") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 257; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_osmid = values[0];
+    __pyx_v_tags = values[1];
+    __pyx_v_refs = values[2];
+  } else if (PyTuple_GET_SIZE(__pyx_args) != 3) {
+    goto __pyx_L5_argtuple_error;
+  } else {
+    __pyx_v_osmid = PyTuple_GET_ITEM(__pyx_args, 0);
+    __pyx_v_tags = PyTuple_GET_ITEM(__pyx_args, 1);
+    __pyx_v_refs = PyTuple_GET_ITEM(__pyx_args, 2);
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("put", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 257; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.RefTagDB.put");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+
+  /* "imposm/cache/tc.pyx":258
+ *     """
+ *     def put(self, osmid, tags, refs):
+ *         return self.put_marshaled(osmid, PyMarshal_WriteObjectToString((tags, refs), 2))             # <<<<<<<<<<<<<<
+ * 
+ *     def put_marshaled(self, int64_t osmid, data):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__put_marshaled); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 258; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 258; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  __Pyx_INCREF(__pyx_v_tags);
+  PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_v_tags);
+  __Pyx_GIVEREF(__pyx_v_tags);
+  __Pyx_INCREF(__pyx_v_refs);
+  PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_refs);
+  __Pyx_GIVEREF(__pyx_v_refs);
+  __pyx_t_3 = PyMarshal_WriteObjectToString(((PyObject *)__pyx_t_2), 2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 258; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 258; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  __Pyx_INCREF(__pyx_v_osmid);
+  PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_v_osmid);
+  __Pyx_GIVEREF(__pyx_v_osmid);
+  PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_3);
+  __Pyx_GIVEREF(__pyx_t_3);
+  __pyx_t_3 = 0;
+  __pyx_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 258; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+  __pyx_r = __pyx_t_3;
+  __pyx_t_3 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("imposm.cache.tc.RefTagDB.put");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":260
+ *         return self.put_marshaled(osmid, PyMarshal_WriteObjectToString((tags, refs), 2))
+ * 
+ *     def put_marshaled(self, int64_t osmid, data):             # <<<<<<<<<<<<<<
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>data, len(data))
+ * 
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_8RefTagDB_1put_marshaled(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pf_6imposm_5cache_2tc_8RefTagDB_1put_marshaled(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  int64_t __pyx_v_osmid;
+  PyObject *__pyx_v_data = 0;
+  PyObject *__pyx_r = NULL;
+  TCBDB *__pyx_t_1;
+  char *__pyx_t_2;
+  size_t __pyx_t_3;
+  char *__pyx_t_4;
+  char *__pyx_t_5;
+  PyObject *__pyx_t_6 = NULL;
+  Py_ssize_t __pyx_t_7;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__osmid,&__pyx_n_s__data,0};
+  __Pyx_RefNannySetupContext("put_marshaled");
+  if (unlikely(__pyx_kwds)) {
+    Py_ssize_t kw_args = PyDict_Size(__pyx_kwds);
+    PyObject* values[2] = {0,0};
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+      case  0: break;
+      default: goto __pyx_L5_argtuple_error;
+    }
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  0:
+      values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__osmid);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__data);
+      if (likely(values[1])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("put_marshaled", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 260; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    }
+    if (unlikely(kw_args > 0)) {
+      if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "put_marshaled") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 260; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_osmid = __Pyx_PyInt_from_py_int64_t(values[0]); if (unlikely((__pyx_v_osmid == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 260; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_data = values[1];
+  } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
+    goto __pyx_L5_argtuple_error;
+  } else {
+    __pyx_v_osmid = __Pyx_PyInt_from_py_int64_t(PyTuple_GET_ITEM(__pyx_args, 0)); if (unlikely((__pyx_v_osmid == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 260; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_data = PyTuple_GET_ITEM(__pyx_args, 1);
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("put_marshaled", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 260; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.RefTagDB.put_marshaled");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+
+  /* "imposm/cache/tc.pyx":261
+ * 
+ *     def put_marshaled(self, int64_t osmid, data):
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>data, len(data))             # <<<<<<<<<<<<<<
+ * 
+ * cdef class WayDB(RefTagDB):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = ((struct __pyx_obj_6imposm_5cache_2tc_RefTagDB *)__pyx_v_self)->__pyx_base.db;
+  __pyx_t_2 = ((char *)(&__pyx_v_osmid));
+  __pyx_t_3 = (sizeof(int64_t));
+  __pyx_t_4 = PyBytes_AsString(__pyx_v_data); if (unlikely((!__pyx_t_4) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 261; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_5 = __pyx_t_4;
+  __pyx_t_6 = __pyx_v_data;
+  __Pyx_INCREF(__pyx_t_6);
+  __pyx_t_7 = PyObject_Length(__pyx_t_6); if (unlikely(__pyx_t_7 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 261; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+  __pyx_t_6 = __Pyx_PyBool_FromLong(tcbdbput(__pyx_t_1, __pyx_t_2, __pyx_t_3, __pyx_t_5, __pyx_t_7)); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 261; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_6);
+  __pyx_r = __pyx_t_6;
+  __pyx_t_6 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_AddTraceback("imposm.cache.tc.RefTagDB.put_marshaled");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":264
+ * 
+ * cdef class WayDB(RefTagDB):
+ *     cdef object _obj(self, int64_t osmid, data):             # <<<<<<<<<<<<<<
+ *         return Way(osmid, data[0], data[1])
+ * 
+ */
+
+static  PyObject *__pyx_f_6imposm_5cache_2tc_5WayDB__obj(struct __pyx_obj_6imposm_5cache_2tc_WayDB *__pyx_v_self, int64_t __pyx_v_osmid, PyObject *__pyx_v_data) {
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  PyObject *__pyx_t_5 = NULL;
+  __Pyx_RefNannySetupContext("_obj");
+
+  /* "imposm/cache/tc.pyx":265
+ * cdef class WayDB(RefTagDB):
+ *     cdef object _obj(self, int64_t osmid, data):
+ *         return Way(osmid, data[0], data[1])             # <<<<<<<<<<<<<<
+ * 
+ * cdef class RelationDB(RefTagDB):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s__Way); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 265; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 265; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_data, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 265; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_data, 1, sizeof(long), PyInt_FromLong); if (!__pyx_t_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 265; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_t_5 = PyTuple_New(3); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 265; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_5));
+  PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_2);
+  __Pyx_GIVEREF(__pyx_t_2);
+  PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_3);
+  __Pyx_GIVEREF(__pyx_t_3);
+  PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_t_4);
+  __Pyx_GIVEREF(__pyx_t_4);
+  __pyx_t_2 = 0;
+  __pyx_t_3 = 0;
+  __pyx_t_4 = 0;
+  __pyx_t_4 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 265; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
+  __pyx_r = __pyx_t_4;
+  __pyx_t_4 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_AddTraceback("imposm.cache.tc.WayDB._obj");
+  __pyx_r = 0;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":268
+ * 
+ * cdef class RelationDB(RefTagDB):
+ *     cdef object _obj(self, int64_t osmid, data):             # <<<<<<<<<<<<<<
+ *         return Relation(osmid, data[0], data[1])
+ */
+
+static  PyObject *__pyx_f_6imposm_5cache_2tc_10RelationDB__obj(struct __pyx_obj_6imposm_5cache_2tc_RelationDB *__pyx_v_self, int64_t __pyx_v_osmid, PyObject *__pyx_v_data) {
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  PyObject *__pyx_t_5 = NULL;
+  __Pyx_RefNannySetupContext("_obj");
+
+  /* "imposm/cache/tc.pyx":269
+ * cdef class RelationDB(RefTagDB):
+ *     cdef object _obj(self, int64_t osmid, data):
+ *         return Relation(osmid, data[0], data[1])             # <<<<<<<<<<<<<<
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s__Relation); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 269; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 269; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_data, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 269; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_data, 1, sizeof(long), PyInt_FromLong); if (!__pyx_t_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 269; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_t_5 = PyTuple_New(3); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 269; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_5));
+  PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_2);
+  __Pyx_GIVEREF(__pyx_t_2);
+  PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_3);
+  __Pyx_GIVEREF(__pyx_t_3);
+  PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_t_4);
+  __Pyx_GIVEREF(__pyx_t_4);
+  __pyx_t_2 = 0;
+  __pyx_t_3 = 0;
+  __pyx_t_4 = 0;
+  __pyx_t_4 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 269; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
+  __pyx_r = __pyx_t_4;
+  __pyx_t_4 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_AddTraceback("imposm.cache.tc.RelationDB._obj");
+  __pyx_r = 0;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+static struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB __pyx_vtable_6imposm_5cache_2tc_BDB;
+
+static PyObject *__pyx_tp_new_6imposm_5cache_2tc_BDB(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_6imposm_5cache_2tc_BDB *p;
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  p = ((struct __pyx_obj_6imposm_5cache_2tc_BDB *)o);
+  p->__pyx_vtab = __pyx_vtabptr_6imposm_5cache_2tc_BDB;
+  p->filename = Py_None; Py_INCREF(Py_None);
+  if (__pyx_pf_6imposm_5cache_2tc_3BDB___cinit__(o, a, k) < 0) {
+    Py_DECREF(o); o = 0;
+  }
+  return o;
+}
+
+static void __pyx_tp_dealloc_6imposm_5cache_2tc_BDB(PyObject *o) {
+  struct __pyx_obj_6imposm_5cache_2tc_BDB *p = (struct __pyx_obj_6imposm_5cache_2tc_BDB *)o;
+  {
+    PyObject *etype, *eval, *etb;
+    PyErr_Fetch(&etype, &eval, &etb);
+    ++Py_REFCNT(o);
+    __pyx_pf_6imposm_5cache_2tc_3BDB_9__dealloc__(o);
+    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
+    --Py_REFCNT(o);
+    PyErr_Restore(etype, eval, etb);
+  }
+  Py_XDECREF(p->filename);
+  (*Py_TYPE(o)->tp_free)(o);
+}
+
+static int __pyx_tp_traverse_6imposm_5cache_2tc_BDB(PyObject *o, visitproc v, void *a) {
+  int e;
+  struct __pyx_obj_6imposm_5cache_2tc_BDB *p = (struct __pyx_obj_6imposm_5cache_2tc_BDB *)o;
+  if (p->filename) {
+    e = (*v)(p->filename, a); if (e) return e;
+  }
+  return 0;
+}
+
+static int __pyx_tp_clear_6imposm_5cache_2tc_BDB(PyObject *o) {
+  struct __pyx_obj_6imposm_5cache_2tc_BDB *p = (struct __pyx_obj_6imposm_5cache_2tc_BDB *)o;
+  PyObject* tmp;
+  tmp = ((PyObject*)p->filename);
+  p->filename = Py_None; Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  return 0;
+}
+
+static PyMethodDef __pyx_methods_6imposm_5cache_2tc_BDB[] = {
+  {__Pyx_NAMESTR("_tune_db"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_3BDB_2_tune_db, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("get"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_3BDB_3get, METH_O, __Pyx_DOCSTR(__pyx_doc_6imposm_5cache_2tc_3BDB_3get)},
+  {__Pyx_NAMESTR("__next__"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_3BDB_7__next__, METH_NOARGS|METH_COEXIST, __Pyx_DOCSTR(__pyx_doc_6imposm_5cache_2tc_3BDB_7__next__)},
+  {__Pyx_NAMESTR("close"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_3BDB_8close, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_BDB = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_BDB = {
+  __pyx_pf_6imposm_5cache_2tc_3BDB_6__len__, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  __pyx_pf_6imposm_5cache_2tc_3BDB_5__contains__, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_BDB = {
+  __pyx_pf_6imposm_5cache_2tc_3BDB_6__len__, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_BDB = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_6imposm_5cache_2tc_BDB = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("imposm.cache.tc.BDB"), /*tp_name*/
+  sizeof(struct __pyx_obj_6imposm_5cache_2tc_BDB), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_6imposm_5cache_2tc_BDB, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_BDB, /*tp_as_number*/
+  &__pyx_tp_as_sequence_BDB, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_BDB, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_BDB, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
+  0, /*tp_doc*/
+  __pyx_tp_traverse_6imposm_5cache_2tc_BDB, /*tp_traverse*/
+  __pyx_tp_clear_6imposm_5cache_2tc_BDB, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  __pyx_pf_6imposm_5cache_2tc_3BDB_4__iter__, /*tp_iter*/
+  __pyx_pf_6imposm_5cache_2tc_3BDB_7__next__, /*tp_iternext*/
+  __pyx_methods_6imposm_5cache_2tc_BDB, /*tp_methods*/
+  0, /*tp_members*/
+  0, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  __pyx_pf_6imposm_5cache_2tc_3BDB_1__init__, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_6imposm_5cache_2tc_BDB, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+static struct __pyx_vtabstruct_6imposm_5cache_2tc_CoordDB __pyx_vtable_6imposm_5cache_2tc_CoordDB;
+
+static PyObject *__pyx_tp_new_6imposm_5cache_2tc_CoordDB(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_6imposm_5cache_2tc_CoordDB *p;
+  PyObject *o = __pyx_tp_new_6imposm_5cache_2tc_BDB(t, a, k);
+  if (!o) return 0;
+  p = ((struct __pyx_obj_6imposm_5cache_2tc_CoordDB *)o);
+  p->__pyx_base.__pyx_vtab = (struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB*)__pyx_vtabptr_6imposm_5cache_2tc_CoordDB;
+  return o;
+}
+
+static PyMethodDef __pyx_methods_6imposm_5cache_2tc_CoordDB[] = {
+  {__Pyx_NAMESTR("put"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_7CoordDB_put, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("put_marshaled"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_7CoordDB_1put_marshaled, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("get"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_7CoordDB_2get, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("get_coords"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_7CoordDB_3get_coords, METH_O, __Pyx_DOCSTR(0)},
+  {0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_CoordDB = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_CoordDB = {
+  0, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_CoordDB = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_CoordDB = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_6imposm_5cache_2tc_CoordDB = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("imposm.cache.tc.CoordDB"), /*tp_name*/
+  sizeof(struct __pyx_obj_6imposm_5cache_2tc_CoordDB), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_6imposm_5cache_2tc_BDB, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_CoordDB, /*tp_as_number*/
+  &__pyx_tp_as_sequence_CoordDB, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_CoordDB, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_CoordDB, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
+  0, /*tp_doc*/
+  __pyx_tp_traverse_6imposm_5cache_2tc_BDB, /*tp_traverse*/
+  __pyx_tp_clear_6imposm_5cache_2tc_BDB, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  0, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_6imposm_5cache_2tc_CoordDB, /*tp_methods*/
+  0, /*tp_members*/
+  0, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  0, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_6imposm_5cache_2tc_CoordDB, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+static struct __pyx_vtabstruct_6imposm_5cache_2tc_NodeDB __pyx_vtable_6imposm_5cache_2tc_NodeDB;
+
+static PyObject *__pyx_tp_new_6imposm_5cache_2tc_NodeDB(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_6imposm_5cache_2tc_NodeDB *p;
+  PyObject *o = __pyx_tp_new_6imposm_5cache_2tc_BDB(t, a, k);
+  if (!o) return 0;
+  p = ((struct __pyx_obj_6imposm_5cache_2tc_NodeDB *)o);
+  p->__pyx_base.__pyx_vtab = (struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB*)__pyx_vtabptr_6imposm_5cache_2tc_NodeDB;
+  return o;
+}
+
+static PyMethodDef __pyx_methods_6imposm_5cache_2tc_NodeDB[] = {
+  {__Pyx_NAMESTR("put"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_6NodeDB_put, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("put_marshaled"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_6NodeDB_1put_marshaled, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
+  {0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_NodeDB = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_NodeDB = {
+  0, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_NodeDB = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_NodeDB = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_6imposm_5cache_2tc_NodeDB = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("imposm.cache.tc.NodeDB"), /*tp_name*/
+  sizeof(struct __pyx_obj_6imposm_5cache_2tc_NodeDB), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_6imposm_5cache_2tc_BDB, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_NodeDB, /*tp_as_number*/
+  &__pyx_tp_as_sequence_NodeDB, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_NodeDB, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_NodeDB, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
+  0, /*tp_doc*/
+  __pyx_tp_traverse_6imposm_5cache_2tc_BDB, /*tp_traverse*/
+  __pyx_tp_clear_6imposm_5cache_2tc_BDB, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  0, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_6imposm_5cache_2tc_NodeDB, /*tp_methods*/
+  0, /*tp_members*/
+  0, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  0, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_6imposm_5cache_2tc_NodeDB, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+static struct __pyx_vtabstruct_6imposm_5cache_2tc_RefTagDB __pyx_vtable_6imposm_5cache_2tc_RefTagDB;
+
+static PyObject *__pyx_tp_new_6imposm_5cache_2tc_RefTagDB(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_6imposm_5cache_2tc_RefTagDB *p;
+  PyObject *o = __pyx_tp_new_6imposm_5cache_2tc_BDB(t, a, k);
+  if (!o) return 0;
+  p = ((struct __pyx_obj_6imposm_5cache_2tc_RefTagDB *)o);
+  p->__pyx_base.__pyx_vtab = (struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB*)__pyx_vtabptr_6imposm_5cache_2tc_RefTagDB;
+  return o;
+}
+
+static PyMethodDef __pyx_methods_6imposm_5cache_2tc_RefTagDB[] = {
+  {__Pyx_NAMESTR("put"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_8RefTagDB_put, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("put_marshaled"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_8RefTagDB_1put_marshaled, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
+  {0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_RefTagDB = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_RefTagDB = {
+  0, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_RefTagDB = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_RefTagDB = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_6imposm_5cache_2tc_RefTagDB = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("imposm.cache.tc.RefTagDB"), /*tp_name*/
+  sizeof(struct __pyx_obj_6imposm_5cache_2tc_RefTagDB), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_6imposm_5cache_2tc_BDB, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_RefTagDB, /*tp_as_number*/
+  &__pyx_tp_as_sequence_RefTagDB, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_RefTagDB, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_RefTagDB, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
+  __Pyx_DOCSTR("\n    Database for items with references and tags (i.e. ways/relations).\n    "), /*tp_doc*/
+  __pyx_tp_traverse_6imposm_5cache_2tc_BDB, /*tp_traverse*/
+  __pyx_tp_clear_6imposm_5cache_2tc_BDB, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  0, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_6imposm_5cache_2tc_RefTagDB, /*tp_methods*/
+  0, /*tp_members*/
+  0, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  0, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_6imposm_5cache_2tc_RefTagDB, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+static struct __pyx_vtabstruct_6imposm_5cache_2tc_WayDB __pyx_vtable_6imposm_5cache_2tc_WayDB;
+
+static PyObject *__pyx_tp_new_6imposm_5cache_2tc_WayDB(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_6imposm_5cache_2tc_WayDB *p;
+  PyObject *o = __pyx_tp_new_6imposm_5cache_2tc_BDB(t, a, k);
+  if (!o) return 0;
+  p = ((struct __pyx_obj_6imposm_5cache_2tc_WayDB *)o);
+  p->__pyx_base.__pyx_base.__pyx_vtab = (struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB*)__pyx_vtabptr_6imposm_5cache_2tc_WayDB;
+  return o;
+}
+
+static PyMethodDef __pyx_methods_6imposm_5cache_2tc_WayDB[] = {
+  {0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_WayDB = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_WayDB = {
+  0, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_WayDB = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_WayDB = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_6imposm_5cache_2tc_WayDB = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("imposm.cache.tc.WayDB"), /*tp_name*/
+  sizeof(struct __pyx_obj_6imposm_5cache_2tc_WayDB), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_6imposm_5cache_2tc_BDB, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_WayDB, /*tp_as_number*/
+  &__pyx_tp_as_sequence_WayDB, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_WayDB, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_WayDB, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
+  0, /*tp_doc*/
+  __pyx_tp_traverse_6imposm_5cache_2tc_BDB, /*tp_traverse*/
+  __pyx_tp_clear_6imposm_5cache_2tc_BDB, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  0, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_6imposm_5cache_2tc_WayDB, /*tp_methods*/
+  0, /*tp_members*/
+  0, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  0, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_6imposm_5cache_2tc_WayDB, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+static struct __pyx_vtabstruct_6imposm_5cache_2tc_RelationDB __pyx_vtable_6imposm_5cache_2tc_RelationDB;
+
+static PyObject *__pyx_tp_new_6imposm_5cache_2tc_RelationDB(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_6imposm_5cache_2tc_RelationDB *p;
+  PyObject *o = __pyx_tp_new_6imposm_5cache_2tc_BDB(t, a, k);
+  if (!o) return 0;
+  p = ((struct __pyx_obj_6imposm_5cache_2tc_RelationDB *)o);
+  p->__pyx_base.__pyx_base.__pyx_vtab = (struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB*)__pyx_vtabptr_6imposm_5cache_2tc_RelationDB;
+  return o;
+}
+
+static PyMethodDef __pyx_methods_6imposm_5cache_2tc_RelationDB[] = {
+  {0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_RelationDB = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_RelationDB = {
+  0, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_RelationDB = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_RelationDB = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_6imposm_5cache_2tc_RelationDB = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("imposm.cache.tc.RelationDB"), /*tp_name*/
+  sizeof(struct __pyx_obj_6imposm_5cache_2tc_RelationDB), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_6imposm_5cache_2tc_BDB, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_RelationDB, /*tp_as_number*/
+  &__pyx_tp_as_sequence_RelationDB, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_RelationDB, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_RelationDB, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
+  0, /*tp_doc*/
+  __pyx_tp_traverse_6imposm_5cache_2tc_BDB, /*tp_traverse*/
+  __pyx_tp_clear_6imposm_5cache_2tc_BDB, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  0, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_6imposm_5cache_2tc_RelationDB, /*tp_methods*/
+  0, /*tp_members*/
+  0, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  0, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_6imposm_5cache_2tc_RelationDB, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+
+static PyMethodDef __pyx_methods[] = {
+  {0, 0, 0, 0}
+};
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef __pyx_moduledef = {
+    PyModuleDef_HEAD_INIT,
+    __Pyx_NAMESTR("tc"),
+    0, /* m_doc */
+    -1, /* m_size */
+    __pyx_methods /* m_methods */,
+    NULL, /* m_reload */
+    NULL, /* m_traverse */
+    NULL, /* m_clear */
+    NULL /* m_free */
+};
+#endif
+
+static __Pyx_StringTabEntry __pyx_string_tab[] = {
+  {&__pyx_n_s_1, __pyx_k_1, sizeof(__pyx_k_1), 0, 0, 1, 1},
+  {&__pyx_n_s__IOError, __pyx_k__IOError, sizeof(__pyx_k__IOError), 0, 0, 1, 1},
+  {&__pyx_n_s__Node, __pyx_k__Node, sizeof(__pyx_k__Node), 0, 0, 1, 1},
+  {&__pyx_n_s__Relation, __pyx_k__Relation, sizeof(__pyx_k__Relation), 0, 0, 1, 1},
+  {&__pyx_n_s__StopIteration, __pyx_k__StopIteration, sizeof(__pyx_k__StopIteration), 0, 0, 1, 1},
+  {&__pyx_n_s__Way, __pyx_k__Way, sizeof(__pyx_k__Way), 0, 0, 1, 1},
+  {&__pyx_n_s____main__, __pyx_k____main__, sizeof(__pyx_k____main__), 0, 0, 1, 1},
+  {&__pyx_n_s____test__, __pyx_k____test__, sizeof(__pyx_k____test__), 0, 0, 1, 1},
+  {&__pyx_n_s___cur, __pyx_k___cur, sizeof(__pyx_k___cur), 0, 0, 1, 1},
+  {&__pyx_n_s___get_cur, __pyx_k___get_cur, sizeof(__pyx_k___get_cur), 0, 0, 1, 1},
+  {&__pyx_n_s___modes, __pyx_k___modes, sizeof(__pyx_k___modes), 0, 0, 1, 1},
+  {&__pyx_n_s___obj, __pyx_k___obj, sizeof(__pyx_k___obj), 0, 0, 1, 1},
+  {&__pyx_n_s___opened, __pyx_k___opened, sizeof(__pyx_k___opened), 0, 0, 1, 1},
+  {&__pyx_n_s___put, __pyx_k___put, sizeof(__pyx_k___put), 0, 0, 1, 1},
+  {&__pyx_n_s___tune_db, __pyx_k___tune_db, sizeof(__pyx_k___tune_db), 0, 0, 1, 1},
+  {&__pyx_n_s__append, __pyx_k__append, sizeof(__pyx_k__append), 0, 0, 1, 1},
+  {&__pyx_n_s__data, __pyx_k__data, sizeof(__pyx_k__data), 0, 0, 1, 1},
+  {&__pyx_n_s__db, __pyx_k__db, sizeof(__pyx_k__db), 0, 0, 1, 1},
+  {&__pyx_n_s__estimated_records, __pyx_k__estimated_records, sizeof(__pyx_k__estimated_records), 0, 0, 1, 1},
+  {&__pyx_n_s__filename, __pyx_k__filename, sizeof(__pyx_k__filename), 0, 0, 1, 1},
+  {&__pyx_n_s__mode, __pyx_k__mode, sizeof(__pyx_k__mode), 0, 0, 1, 1},
+  {&__pyx_n_s__osmid, __pyx_k__osmid, sizeof(__pyx_k__osmid), 0, 0, 1, 1},
+  {&__pyx_n_s__pos, __pyx_k__pos, sizeof(__pyx_k__pos), 0, 0, 1, 1},
+  {&__pyx_n_s__put_marshaled, __pyx_k__put_marshaled, sizeof(__pyx_k__put_marshaled), 0, 0, 1, 1},
+  {&__pyx_n_s__r, __pyx_k__r, sizeof(__pyx_k__r), 0, 0, 1, 1},
+  {&__pyx_n_s__refs, __pyx_k__refs, sizeof(__pyx_k__refs), 0, 0, 1, 1},
+  {&__pyx_n_s__tags, __pyx_k__tags, sizeof(__pyx_k__tags), 0, 0, 1, 1},
+  {&__pyx_n_s__w, __pyx_k__w, sizeof(__pyx_k__w), 0, 0, 1, 1},
+  {&__pyx_n_s__x, __pyx_k__x, sizeof(__pyx_k__x), 0, 0, 1, 1},
+  {&__pyx_n_s__y, __pyx_k__y, sizeof(__pyx_k__y), 0, 0, 1, 1},
+  {0, 0, 0, 0, 0, 0, 0}
+};
+static int __Pyx_InitCachedBuiltins(void) {
+  __pyx_builtin_IOError = __Pyx_GetName(__pyx_b, __pyx_n_s__IOError); if (!__pyx_builtin_IOError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 104; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_StopIteration = __Pyx_GetName(__pyx_b, __pyx_n_s__StopIteration); if (!__pyx_builtin_StopIteration) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  return 0;
+  __pyx_L1_error:;
+  return -1;
+}
+
+static int __Pyx_InitCachedConstants(void) {
+  __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants");
+  __Pyx_RefNannyFinishContext();
+  return 0;
+}
+
+static int __Pyx_InitGlobals(void) {
+  if (__Pyx_InitStrings(__pyx_string_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_3 = PyInt_FromLong(3); if (unlikely(!__pyx_int_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_128 = PyInt_FromLong(128); if (unlikely(!__pyx_int_128)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  return 0;
+  __pyx_L1_error:;
+  return -1;
+}
+
+#if PY_MAJOR_VERSION < 3
+PyMODINIT_FUNC inittc(void); /*proto*/
+PyMODINIT_FUNC inittc(void)
+#else
+PyMODINIT_FUNC PyInit_tc(void); /*proto*/
+PyMODINIT_FUNC PyInit_tc(void)
+#endif
+{
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  #if CYTHON_REFNANNY
+  void* __pyx_refnanny = NULL;
+  __Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny");
+  if (!__Pyx_RefNanny) {
+      PyErr_Clear();
+      __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny");
+      if (!__Pyx_RefNanny)
+          Py_FatalError("failed to import 'refnanny' module");
+  }
+  __pyx_refnanny = __Pyx_RefNanny->SetupContext("PyMODINIT_FUNC PyInit_tc(void)", __LINE__, __FILE__);
+  #endif
+  __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  #ifdef __pyx_binding_PyCFunctionType_USED
+  if (__pyx_binding_PyCFunctionType_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  #endif
+  /*--- Library function declarations ---*/
+  /*--- Threads initialization code ---*/
+  #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS
+  #ifdef WITH_THREAD /* Python build with threading support? */
+  PyEval_InitThreads();
+  #endif
+  #endif
+  /*--- Module creation code ---*/
+  #if PY_MAJOR_VERSION < 3
+  __pyx_m = Py_InitModule4(__Pyx_NAMESTR("tc"), __pyx_methods, 0, 0, PYTHON_API_VERSION);
+  #else
+  __pyx_m = PyModule_Create(&__pyx_moduledef);
+  #endif
+  if (!__pyx_m) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  #if PY_MAJOR_VERSION < 3
+  Py_INCREF(__pyx_m);
+  #endif
+  __pyx_b = PyImport_AddModule(__Pyx_NAMESTR(__Pyx_BUILTIN_MODULE_NAME));
+  if (!__pyx_b) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  if (__Pyx_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  /*--- Initialize various global constants etc. ---*/
+  if (unlikely(__Pyx_InitGlobals() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__pyx_module_is_main_imposm__cache__tc) {
+    if (__Pyx_SetAttrString(__pyx_m, "__name__", __pyx_n_s____main__) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  }
+  /*--- Builtin init code ---*/
+  if (unlikely(__Pyx_InitCachedBuiltins() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  /*--- Constants init code ---*/
+  if (unlikely(__Pyx_InitCachedConstants() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  /*--- Global init code ---*/
+  /*--- Function export code ---*/
+  /*--- Type init code ---*/
+  __pyx_vtabptr_6imposm_5cache_2tc_BDB = &__pyx_vtable_6imposm_5cache_2tc_BDB;
+  __pyx_vtable_6imposm_5cache_2tc_BDB._obj = (PyObject *(*)(struct __pyx_obj_6imposm_5cache_2tc_BDB *, int64_t, PyObject *))__pyx_f_6imposm_5cache_2tc_3BDB__obj;
+  __pyx_vtable_6imposm_5cache_2tc_BDB._get_cur = (PyObject *(*)(struct __pyx_obj_6imposm_5cache_2tc_BDB *))__pyx_f_6imposm_5cache_2tc_3BDB__get_cur;
+  if (PyType_Ready(&__pyx_type_6imposm_5cache_2tc_BDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  {
+    PyObject *wrapper = __Pyx_GetAttrString((PyObject *)&__pyx_type_6imposm_5cache_2tc_BDB, "__iter__"); if (unlikely(!wrapper)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (Py_TYPE(wrapper) == &PyWrapperDescr_Type) {
+      __pyx_wrapperbase_6imposm_5cache_2tc_3BDB_4__iter__ = *((PyWrapperDescrObject *)wrapper)->d_base;
+      __pyx_wrapperbase_6imposm_5cache_2tc_3BDB_4__iter__.doc = __pyx_doc_6imposm_5cache_2tc_3BDB_4__iter__;
+      ((PyWrapperDescrObject *)wrapper)->d_base = &__pyx_wrapperbase_6imposm_5cache_2tc_3BDB_4__iter__;
+    }
+  }
+  {
+    PyObject *wrapper = __Pyx_GetAttrString((PyObject *)&__pyx_type_6imposm_5cache_2tc_BDB, "__next__"); if (unlikely(!wrapper)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (Py_TYPE(wrapper) == &PyWrapperDescr_Type) {
+      __pyx_wrapperbase_6imposm_5cache_2tc_3BDB_7__next__ = *((PyWrapperDescrObject *)wrapper)->d_base;
+      __pyx_wrapperbase_6imposm_5cache_2tc_3BDB_7__next__.doc = __pyx_doc_6imposm_5cache_2tc_3BDB_7__next__;
+      ((PyWrapperDescrObject *)wrapper)->d_base = &__pyx_wrapperbase_6imposm_5cache_2tc_3BDB_7__next__;
+    }
+  }
+  if (__Pyx_SetVtable(__pyx_type_6imposm_5cache_2tc_BDB.tp_dict, __pyx_vtabptr_6imposm_5cache_2tc_BDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "BDB", (PyObject *)&__pyx_type_6imposm_5cache_2tc_BDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_6imposm_5cache_2tc_BDB = &__pyx_type_6imposm_5cache_2tc_BDB;
+  __pyx_vtabptr_6imposm_5cache_2tc_CoordDB = &__pyx_vtable_6imposm_5cache_2tc_CoordDB;
+  __pyx_vtable_6imposm_5cache_2tc_CoordDB.__pyx_base = *__pyx_vtabptr_6imposm_5cache_2tc_BDB;
+  __pyx_vtable_6imposm_5cache_2tc_CoordDB.__pyx_base._obj = (PyObject *(*)(struct __pyx_obj_6imposm_5cache_2tc_BDB *, int64_t, PyObject *))__pyx_f_6imposm_5cache_2tc_7CoordDB__obj;
+  __pyx_vtable_6imposm_5cache_2tc_CoordDB.__pyx_base._get_cur = (PyObject *(*)(struct __pyx_obj_6imposm_5cache_2tc_BDB *))__pyx_f_6imposm_5cache_2tc_7CoordDB__get_cur;
+  __pyx_vtable_6imposm_5cache_2tc_CoordDB._put = (int (*)(struct __pyx_obj_6imposm_5cache_2tc_CoordDB *, int64_t, double, double))__pyx_f_6imposm_5cache_2tc_7CoordDB__put;
+  __pyx_type_6imposm_5cache_2tc_CoordDB.tp_base = __pyx_ptype_6imposm_5cache_2tc_BDB;
+  if (PyType_Ready(&__pyx_type_6imposm_5cache_2tc_CoordDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 200; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetVtable(__pyx_type_6imposm_5cache_2tc_CoordDB.tp_dict, __pyx_vtabptr_6imposm_5cache_2tc_CoordDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 200; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "CoordDB", (PyObject *)&__pyx_type_6imposm_5cache_2tc_CoordDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 200; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_6imposm_5cache_2tc_CoordDB = &__pyx_type_6imposm_5cache_2tc_CoordDB;
+  __pyx_vtabptr_6imposm_5cache_2tc_NodeDB = &__pyx_vtable_6imposm_5cache_2tc_NodeDB;
+  __pyx_vtable_6imposm_5cache_2tc_NodeDB.__pyx_base = *__pyx_vtabptr_6imposm_5cache_2tc_BDB;
+  __pyx_vtable_6imposm_5cache_2tc_NodeDB.__pyx_base._obj = (PyObject *(*)(struct __pyx_obj_6imposm_5cache_2tc_BDB *, int64_t, PyObject *))__pyx_f_6imposm_5cache_2tc_6NodeDB__obj;
+  __pyx_type_6imposm_5cache_2tc_NodeDB.tp_base = __pyx_ptype_6imposm_5cache_2tc_BDB;
+  if (PyType_Ready(&__pyx_type_6imposm_5cache_2tc_NodeDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 243; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetVtable(__pyx_type_6imposm_5cache_2tc_NodeDB.tp_dict, __pyx_vtabptr_6imposm_5cache_2tc_NodeDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 243; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "NodeDB", (PyObject *)&__pyx_type_6imposm_5cache_2tc_NodeDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 243; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_6imposm_5cache_2tc_NodeDB = &__pyx_type_6imposm_5cache_2tc_NodeDB;
+  __pyx_vtabptr_6imposm_5cache_2tc_RefTagDB = &__pyx_vtable_6imposm_5cache_2tc_RefTagDB;
+  __pyx_vtable_6imposm_5cache_2tc_RefTagDB.__pyx_base = *__pyx_vtabptr_6imposm_5cache_2tc_BDB;
+  __pyx_type_6imposm_5cache_2tc_RefTagDB.tp_base = __pyx_ptype_6imposm_5cache_2tc_BDB;
+  if (PyType_Ready(&__pyx_type_6imposm_5cache_2tc_RefTagDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 253; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetVtable(__pyx_type_6imposm_5cache_2tc_RefTagDB.tp_dict, __pyx_vtabptr_6imposm_5cache_2tc_RefTagDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 253; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "RefTagDB", (PyObject *)&__pyx_type_6imposm_5cache_2tc_RefTagDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 253; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_6imposm_5cache_2tc_RefTagDB = &__pyx_type_6imposm_5cache_2tc_RefTagDB;
+  __pyx_vtabptr_6imposm_5cache_2tc_WayDB = &__pyx_vtable_6imposm_5cache_2tc_WayDB;
+  __pyx_vtable_6imposm_5cache_2tc_WayDB.__pyx_base = *__pyx_vtabptr_6imposm_5cache_2tc_RefTagDB;
+  __pyx_vtable_6imposm_5cache_2tc_WayDB.__pyx_base.__pyx_base._obj = (PyObject *(*)(struct __pyx_obj_6imposm_5cache_2tc_BDB *, int64_t, PyObject *))__pyx_f_6imposm_5cache_2tc_5WayDB__obj;
+  __pyx_type_6imposm_5cache_2tc_WayDB.tp_base = __pyx_ptype_6imposm_5cache_2tc_RefTagDB;
+  if (PyType_Ready(&__pyx_type_6imposm_5cache_2tc_WayDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 263; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetVtable(__pyx_type_6imposm_5cache_2tc_WayDB.tp_dict, __pyx_vtabptr_6imposm_5cache_2tc_WayDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 263; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "WayDB", (PyObject *)&__pyx_type_6imposm_5cache_2tc_WayDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 263; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_6imposm_5cache_2tc_WayDB = &__pyx_type_6imposm_5cache_2tc_WayDB;
+  __pyx_vtabptr_6imposm_5cache_2tc_RelationDB = &__pyx_vtable_6imposm_5cache_2tc_RelationDB;
+  __pyx_vtable_6imposm_5cache_2tc_RelationDB.__pyx_base = *__pyx_vtabptr_6imposm_5cache_2tc_RefTagDB;
+  __pyx_vtable_6imposm_5cache_2tc_RelationDB.__pyx_base.__pyx_base._obj = (PyObject *(*)(struct __pyx_obj_6imposm_5cache_2tc_BDB *, int64_t, PyObject *))__pyx_f_6imposm_5cache_2tc_10RelationDB__obj;
+  __pyx_type_6imposm_5cache_2tc_RelationDB.tp_base = __pyx_ptype_6imposm_5cache_2tc_RefTagDB;
+  if (PyType_Ready(&__pyx_type_6imposm_5cache_2tc_RelationDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 267; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetVtable(__pyx_type_6imposm_5cache_2tc_RelationDB.tp_dict, __pyx_vtabptr_6imposm_5cache_2tc_RelationDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 267; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "RelationDB", (PyObject *)&__pyx_type_6imposm_5cache_2tc_RelationDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 267; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_6imposm_5cache_2tc_RelationDB = &__pyx_type_6imposm_5cache_2tc_RelationDB;
+  /*--- Type import code ---*/
+  /*--- Function import code ---*/
+  /*--- Execution code ---*/
+
+  /* "imposm/cache/tc.pyx":1
+ * from imposm.base import Node, Way, Relation             # <<<<<<<<<<<<<<
+ * from libc.stdint cimport uint32_t, int64_t
+ * 
+ */
+  __pyx_t_1 = PyList_New(3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __Pyx_INCREF(((PyObject *)__pyx_n_s__Node));
+  PyList_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_n_s__Node));
+  __Pyx_GIVEREF(((PyObject *)__pyx_n_s__Node));
+  __Pyx_INCREF(((PyObject *)__pyx_n_s__Way));
+  PyList_SET_ITEM(__pyx_t_1, 1, ((PyObject *)__pyx_n_s__Way));
+  __Pyx_GIVEREF(((PyObject *)__pyx_n_s__Way));
+  __Pyx_INCREF(((PyObject *)__pyx_n_s__Relation));
+  PyList_SET_ITEM(__pyx_t_1, 2, ((PyObject *)__pyx_n_s__Relation));
+  __Pyx_GIVEREF(((PyObject *)__pyx_n_s__Relation));
+  __pyx_t_2 = __Pyx_Import(((PyObject *)__pyx_n_s_1), ((PyObject *)__pyx_t_1)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+  __pyx_t_1 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__Node); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__Node, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __pyx_t_1 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__Way); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__Way, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __pyx_t_1 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__Relation); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__Relation, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+  /* "imposm/cache/tc.pyx":85
+ *     return p
+ * 
+ * _modes = {             # <<<<<<<<<<<<<<
+ *     'w': BDBOWRITER | BDBOCREAT,
+ *     'r': BDBOREADER | BDBONOLCK,
+ */
+  __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+
+  /* "imposm/cache/tc.pyx":86
+ * 
+ * _modes = {
+ *     'w': BDBOWRITER | BDBOCREAT,             # <<<<<<<<<<<<<<
+ *     'r': BDBOREADER | BDBONOLCK,
+ * }
+ */
+  __pyx_t_1 = PyInt_FromLong((BDBOWRITER | BDBOCREAT)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyDict_SetItem(__pyx_t_2, ((PyObject *)__pyx_n_s__w), __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":87
+ * _modes = {
+ *     'w': BDBOWRITER | BDBOCREAT,
+ *     'r': BDBOREADER | BDBONOLCK,             # <<<<<<<<<<<<<<
+ * }
+ * 
+ */
+  __pyx_t_1 = PyInt_FromLong((BDBOREADER | BDBONOLCK)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 87; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyDict_SetItem(__pyx_t_2, ((PyObject *)__pyx_n_s__r), __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s___modes, ((PyObject *)__pyx_t_2)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+
+  /* "imposm/cache/tc.pyx":1
+ * from imposm.base import Node, Way, Relation             # <<<<<<<<<<<<<<
+ * from libc.stdint cimport uint32_t, int64_t
+ * 
+ */
+  __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s____test__, ((PyObject *)__pyx_t_2)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  if (__pyx_m) {
+    __Pyx_AddTraceback("init imposm.cache.tc");
+    Py_DECREF(__pyx_m); __pyx_m = 0;
+  } else if (!PyErr_Occurred()) {
+    PyErr_SetString(PyExc_ImportError, "init imposm.cache.tc");
+  }
+  __pyx_L0:;
+  __Pyx_RefNannyFinishContext();
+  #if PY_MAJOR_VERSION < 3
+  return;
+  #else
+  return __pyx_m;
+  #endif
+}
+
+/* Runtime support code */
+
+static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) {
+    PyObject *result;
+    result = PyObject_GetAttr(dict, name);
+    if (!result)
+        PyErr_SetObject(PyExc_NameError, name);
+    return result;
+}
+
+static void __Pyx_RaiseDoubleKeywordsError(
+    const char* func_name,
+    PyObject* kw_name)
+{
+    PyErr_Format(PyExc_TypeError,
+        #if PY_MAJOR_VERSION >= 3
+        "%s() got multiple values for keyword argument '%U'", func_name, kw_name);
+        #else
+        "%s() got multiple values for keyword argument '%s'", func_name,
+        PyString_AS_STRING(kw_name));
+        #endif
+}
+
+static int __Pyx_ParseOptionalKeywords(
+    PyObject *kwds,
+    PyObject **argnames[],
+    PyObject *kwds2,
+    PyObject *values[],
+    Py_ssize_t num_pos_args,
+    const char* function_name)
+{
+    PyObject *key = 0, *value = 0;
+    Py_ssize_t pos = 0;
+    PyObject*** name;
+    PyObject*** first_kw_arg = argnames + num_pos_args;
+
+    while (PyDict_Next(kwds, &pos, &key, &value)) {
+        name = first_kw_arg;
+        while (*name && (**name != key)) name++;
+        if (*name) {
+            values[name-argnames] = value;
+        } else {
+            #if PY_MAJOR_VERSION < 3
+            if (unlikely(!PyString_CheckExact(key)) && unlikely(!PyString_Check(key))) {
+            #else
+            if (unlikely(!PyUnicode_CheckExact(key)) && unlikely(!PyUnicode_Check(key))) {
+            #endif
+                goto invalid_keyword_type;
+            } else {
+                for (name = first_kw_arg; *name; name++) {
+                    #if PY_MAJOR_VERSION >= 3
+                    if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) &&
+                        PyUnicode_Compare(**name, key) == 0) break;
+                    #else
+                    if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) &&
+                        _PyString_Eq(**name, key)) break;
+                    #endif
+                }
+                if (*name) {
+                    values[name-argnames] = value;
+                } else {
+                    /* unexpected keyword found */
+                    for (name=argnames; name != first_kw_arg; name++) {
+                        if (**name == key) goto arg_passed_twice;
+                        #if PY_MAJOR_VERSION >= 3
+                        if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) &&
+                            PyUnicode_Compare(**name, key) == 0) goto arg_passed_twice;
+                        #else
+                        if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) &&
+                            _PyString_Eq(**name, key)) goto arg_passed_twice;
+                        #endif
+                    }
+                    if (kwds2) {
+                        if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad;
+                    } else {
+                        goto invalid_keyword;
+                    }
+                }
+            }
+        }
+    }
+    return 0;
+arg_passed_twice:
+    __Pyx_RaiseDoubleKeywordsError(function_name, **name);
+    goto bad;
+invalid_keyword_type:
+    PyErr_Format(PyExc_TypeError,
+        "%s() keywords must be strings", function_name);
+    goto bad;
+invalid_keyword:
+    PyErr_Format(PyExc_TypeError,
+    #if PY_MAJOR_VERSION < 3
+        "%s() got an unexpected keyword argument '%s'",
+        function_name, PyString_AsString(key));
+    #else
+        "%s() got an unexpected keyword argument '%U'",
+        function_name, key);
+    #endif
+bad:
+    return -1;
+}
+
+static void __Pyx_RaiseArgtupleInvalid(
+    const char* func_name,
+    int exact,
+    Py_ssize_t num_min,
+    Py_ssize_t num_max,
+    Py_ssize_t num_found)
+{
+    Py_ssize_t num_expected;
+    const char *number, *more_or_less;
+
+    if (num_found < num_min) {
+        num_expected = num_min;
+        more_or_less = "at least";
+    } else {
+        num_expected = num_max;
+        more_or_less = "at most";
+    }
+    if (exact) {
+        more_or_less = "exactly";
+    }
+    number = (num_expected == 1) ? "" : "s";
+    PyErr_Format(PyExc_TypeError,
+        #if PY_VERSION_HEX < 0x02050000
+            "%s() takes %s %d positional argument%s (%d given)",
+        #else
+            "%s() takes %s %zd positional argument%s (%zd given)",
+        #endif
+        func_name, more_or_less, num_expected, number, num_found);
+}
+
+static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb) {
+    PyObject *tmp_type, *tmp_value, *tmp_tb;
+    PyThreadState *tstate = PyThreadState_GET();
+
+    tmp_type = tstate->curexc_type;
+    tmp_value = tstate->curexc_value;
+    tmp_tb = tstate->curexc_traceback;
+    tstate->curexc_type = type;
+    tstate->curexc_value = value;
+    tstate->curexc_traceback = tb;
+    Py_XDECREF(tmp_type);
+    Py_XDECREF(tmp_value);
+    Py_XDECREF(tmp_tb);
+}
+
+static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb) {
+    PyThreadState *tstate = PyThreadState_GET();
+    *type = tstate->curexc_type;
+    *value = tstate->curexc_value;
+    *tb = tstate->curexc_traceback;
+
+    tstate->curexc_type = 0;
+    tstate->curexc_value = 0;
+    tstate->curexc_traceback = 0;
+}
+
+
+#if PY_MAJOR_VERSION < 3
+static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
+    Py_XINCREF(type);
+    Py_XINCREF(value);
+    Py_XINCREF(tb);
+    /* First, check the traceback argument, replacing None with NULL. */
+    if (tb == Py_None) {
+        Py_DECREF(tb);
+        tb = 0;
+    }
+    else if (tb != NULL && !PyTraceBack_Check(tb)) {
+        PyErr_SetString(PyExc_TypeError,
+            "raise: arg 3 must be a traceback or None");
+        goto raise_error;
+    }
+    /* Next, replace a missing value with None */
+    if (value == NULL) {
+        value = Py_None;
+        Py_INCREF(value);
+    }
+    #if PY_VERSION_HEX < 0x02050000
+    if (!PyClass_Check(type))
+    #else
+    if (!PyType_Check(type))
+    #endif
+    {
+        /* Raising an instance.  The value should be a dummy. */
+        if (value != Py_None) {
+            PyErr_SetString(PyExc_TypeError,
+                "instance exception may not have a separate value");
+            goto raise_error;
+        }
+        /* Normalize to raise <class>, <instance> */
+        Py_DECREF(value);
+        value = type;
+        #if PY_VERSION_HEX < 0x02050000
+            if (PyInstance_Check(type)) {
+                type = (PyObject*) ((PyInstanceObject*)type)->in_class;
+                Py_INCREF(type);
+            }
+            else {
+                type = 0;
+                PyErr_SetString(PyExc_TypeError,
+                    "raise: exception must be an old-style class or instance");
+                goto raise_error;
+            }
+        #else
+            type = (PyObject*) Py_TYPE(type);
+            Py_INCREF(type);
+            if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) {
+                PyErr_SetString(PyExc_TypeError,
+                    "raise: exception class must be a subclass of BaseException");
+                goto raise_error;
+            }
+        #endif
+    }
+
+    __Pyx_ErrRestore(type, value, tb);
+    return;
+raise_error:
+    Py_XDECREF(value);
+    Py_XDECREF(type);
+    Py_XDECREF(tb);
+    return;
+}
+
+#else /* Python 3+ */
+
+static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
+    if (tb == Py_None) {
+        tb = 0;
+    } else if (tb && !PyTraceBack_Check(tb)) {
+        PyErr_SetString(PyExc_TypeError,
+            "raise: arg 3 must be a traceback or None");
+        goto bad;
+    }
+    if (value == Py_None)
+        value = 0;
+
+    if (PyExceptionInstance_Check(type)) {
+        if (value) {
+            PyErr_SetString(PyExc_TypeError,
+                "instance exception may not have a separate value");
+            goto bad;
+        }
+        value = type;
+        type = (PyObject*) Py_TYPE(value);
+    } else if (!PyExceptionClass_Check(type)) {
+        PyErr_SetString(PyExc_TypeError,
+            "raise: exception class must be a subclass of BaseException");
+        goto bad;
+    }
+
+    PyErr_SetObject(type, value);
+
+    if (tb) {
+        PyThreadState *tstate = PyThreadState_GET();
+        PyObject* tmp_tb = tstate->curexc_traceback;
+        if (tb != tmp_tb) {
+            Py_INCREF(tb);
+            tstate->curexc_traceback = tb;
+            Py_XDECREF(tmp_tb);
+        }
+    }
+
+bad:
+    return;
+}
+#endif
+
+static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) {
+    PyErr_Format(PyExc_ValueError,
+        #if PY_VERSION_HEX < 0x02050000
+                 "need more than %d value%s to unpack", (int)index,
+        #else
+                 "need more than %zd value%s to unpack", index,
+        #endif
+                 (index == 1) ? "" : "s");
+}
+
+static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) {
+    PyErr_Format(PyExc_ValueError,
+        #if PY_VERSION_HEX < 0x02050000
+            "too many values to unpack (expected %d)", (int)expected);
+        #else
+            "too many values to unpack (expected %zd)", expected);
+        #endif
+}
+
+static PyObject *__Pyx_UnpackItem(PyObject *iter, Py_ssize_t index) {
+    PyObject *item;
+    if (!(item = PyIter_Next(iter))) {
+        if (!PyErr_Occurred()) {
+            __Pyx_RaiseNeedMoreValuesError(index);
+        }
+    }
+    return item;
+}
+
+static int __Pyx_EndUnpack(PyObject *iter, Py_ssize_t expected) {
+    PyObject *item;
+    if ((item = PyIter_Next(iter))) {
+        Py_DECREF(item);
+        __Pyx_RaiseTooManyValuesError(expected);
+        return -1;
+    }
+    else if (!PyErr_Occurred())
+        return 0;
+    else
+        return -1;
+}
+
+
+static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) {
+    PyObject *py_import = 0;
+    PyObject *empty_list = 0;
+    PyObject *module = 0;
+    PyObject *global_dict = 0;
+    PyObject *empty_dict = 0;
+    PyObject *list;
+    py_import = __Pyx_GetAttrString(__pyx_b, "__import__");
+    if (!py_import)
+        goto bad;
+    if (from_list)
+        list = from_list;
+    else {
+        empty_list = PyList_New(0);
+        if (!empty_list)
+            goto bad;
+        list = empty_list;
+    }
+    global_dict = PyModule_GetDict(__pyx_m);
+    if (!global_dict)
+        goto bad;
+    empty_dict = PyDict_New();
+    if (!empty_dict)
+        goto bad;
+    module = PyObject_CallFunctionObjArgs(py_import,
+        name, global_dict, empty_dict, list, NULL);
+bad:
+    Py_XDECREF(empty_list);
+    Py_XDECREF(py_import);
+    Py_XDECREF(empty_dict);
+    return module;
+}
+
+static CYTHON_INLINE int64_t __Pyx_PyInt_from_py_int64_t(PyObject* x) {
+    const int64_t neg_one = (int64_t)-1, const_zero = (int64_t)0;
+    const int is_unsigned = const_zero < neg_one;
+    if (sizeof(int64_t) == sizeof(char)) {
+        if (is_unsigned)
+            return (int64_t)__Pyx_PyInt_AsUnsignedChar(x);
+        else
+            return (int64_t)__Pyx_PyInt_AsSignedChar(x);
+    } else if (sizeof(int64_t) == sizeof(short)) {
+        if (is_unsigned)
+            return (int64_t)__Pyx_PyInt_AsUnsignedShort(x);
+        else
+            return (int64_t)__Pyx_PyInt_AsSignedShort(x);
+    } else if (sizeof(int64_t) == sizeof(int)) {
+        if (is_unsigned)
+            return (int64_t)__Pyx_PyInt_AsUnsignedInt(x);
+        else
+            return (int64_t)__Pyx_PyInt_AsSignedInt(x);
+    } else if (sizeof(int64_t) == sizeof(long)) {
+        if (is_unsigned)
+            return (int64_t)__Pyx_PyInt_AsUnsignedLong(x);
+        else
+            return (int64_t)__Pyx_PyInt_AsSignedLong(x);
+    } else if (sizeof(int64_t) == sizeof(PY_LONG_LONG)) {
+        if (is_unsigned)
+            return (int64_t)__Pyx_PyInt_AsUnsignedLongLong(x);
+        else
+            return (int64_t)__Pyx_PyInt_AsSignedLongLong(x);
+    }  else {
+        int64_t val;
+        PyObject *v = __Pyx_PyNumber_Int(x);
+        #if PY_VERSION_HEX < 0x03000000
+        if (likely(v) && !PyLong_Check(v)) {
+            PyObject *tmp = v;
+            v = PyNumber_Long(tmp);
+            Py_DECREF(tmp);
+        }
+        #endif
+        if (likely(v)) {
+            int one = 1; int is_little = (int)*(unsigned char *)&one;
+            unsigned char *bytes = (unsigned char *)&val;
+            int ret = _PyLong_AsByteArray((PyLongObject *)v,
+                                          bytes, sizeof(val),
+                                          is_little, !is_unsigned);
+            Py_DECREF(v);
+            if (likely(!ret))
+                return val;
+        }
+        return (int64_t)-1;
+    }
+}
+
+static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_int64_t(int64_t val) {
+    const int64_t neg_one = (int64_t)-1, const_zero = (int64_t)0;
+    const int is_unsigned = const_zero < neg_one;
+    if ((sizeof(int64_t) == sizeof(char))  ||
+        (sizeof(int64_t) == sizeof(short))) {
+        return PyInt_FromLong((long)val);
+    } else if ((sizeof(int64_t) == sizeof(int)) ||
+               (sizeof(int64_t) == sizeof(long))) {
+        if (is_unsigned)
+            return PyLong_FromUnsignedLong((unsigned long)val);
+        else
+            return PyInt_FromLong((long)val);
+    } else if (sizeof(int64_t) == sizeof(PY_LONG_LONG)) {
+        if (is_unsigned)
+            return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)val);
+        else
+            return PyLong_FromLongLong((PY_LONG_LONG)val);
+    } else {
+        int one = 1; int little = (int)*(unsigned char *)&one;
+        unsigned char *bytes = (unsigned char *)&val;
+        return _PyLong_FromByteArray(bytes, sizeof(int64_t), 
+                                     little, !is_unsigned);
+    }
+}
+
+static CYTHON_INLINE unsigned char __Pyx_PyInt_AsUnsignedChar(PyObject* x) {
+    const unsigned char neg_one = (unsigned char)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(unsigned char) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(unsigned char)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to unsigned char" :
+                    "value too large to convert to unsigned char");
+            }
+            return (unsigned char)-1;
+        }
+        return (unsigned char)val;
+    }
+    return (unsigned char)__Pyx_PyInt_AsUnsignedLong(x);
+}
+
+static CYTHON_INLINE unsigned short __Pyx_PyInt_AsUnsignedShort(PyObject* x) {
+    const unsigned short neg_one = (unsigned short)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(unsigned short) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(unsigned short)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to unsigned short" :
+                    "value too large to convert to unsigned short");
+            }
+            return (unsigned short)-1;
+        }
+        return (unsigned short)val;
+    }
+    return (unsigned short)__Pyx_PyInt_AsUnsignedLong(x);
+}
+
+static CYTHON_INLINE unsigned int __Pyx_PyInt_AsUnsignedInt(PyObject* x) {
+    const unsigned int neg_one = (unsigned int)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(unsigned int) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(unsigned int)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to unsigned int" :
+                    "value too large to convert to unsigned int");
+            }
+            return (unsigned int)-1;
+        }
+        return (unsigned int)val;
+    }
+    return (unsigned int)__Pyx_PyInt_AsUnsignedLong(x);
+}
+
+static CYTHON_INLINE char __Pyx_PyInt_AsChar(PyObject* x) {
+    const char neg_one = (char)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(char) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(char)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to char" :
+                    "value too large to convert to char");
+            }
+            return (char)-1;
+        }
+        return (char)val;
+    }
+    return (char)__Pyx_PyInt_AsLong(x);
+}
+
+static CYTHON_INLINE short __Pyx_PyInt_AsShort(PyObject* x) {
+    const short neg_one = (short)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(short) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(short)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to short" :
+                    "value too large to convert to short");
+            }
+            return (short)-1;
+        }
+        return (short)val;
+    }
+    return (short)__Pyx_PyInt_AsLong(x);
+}
+
+static CYTHON_INLINE int __Pyx_PyInt_AsInt(PyObject* x) {
+    const int neg_one = (int)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(int) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(int)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to int" :
+                    "value too large to convert to int");
+            }
+            return (int)-1;
+        }
+        return (int)val;
+    }
+    return (int)__Pyx_PyInt_AsLong(x);
+}
+
+static CYTHON_INLINE signed char __Pyx_PyInt_AsSignedChar(PyObject* x) {
+    const signed char neg_one = (signed char)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(signed char) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(signed char)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to signed char" :
+                    "value too large to convert to signed char");
+            }
+            return (signed char)-1;
+        }
+        return (signed char)val;
+    }
+    return (signed char)__Pyx_PyInt_AsSignedLong(x);
+}
+
+static CYTHON_INLINE signed short __Pyx_PyInt_AsSignedShort(PyObject* x) {
+    const signed short neg_one = (signed short)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(signed short) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(signed short)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to signed short" :
+                    "value too large to convert to signed short");
+            }
+            return (signed short)-1;
+        }
+        return (signed short)val;
+    }
+    return (signed short)__Pyx_PyInt_AsSignedLong(x);
+}
+
+static CYTHON_INLINE signed int __Pyx_PyInt_AsSignedInt(PyObject* x) {
+    const signed int neg_one = (signed int)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(signed int) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(signed int)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to signed int" :
+                    "value too large to convert to signed int");
+            }
+            return (signed int)-1;
+        }
+        return (signed int)val;
+    }
+    return (signed int)__Pyx_PyInt_AsSignedLong(x);
+}
+
+static CYTHON_INLINE int __Pyx_PyInt_AsLongDouble(PyObject* x) {
+    const int neg_one = (int)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(int) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(int)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to int" :
+                    "value too large to convert to int");
+            }
+            return (int)-1;
+        }
+        return (int)val;
+    }
+    return (int)__Pyx_PyInt_AsLong(x);
+}
+
+static CYTHON_INLINE unsigned long __Pyx_PyInt_AsUnsignedLong(PyObject* x) {
+    const unsigned long neg_one = (unsigned long)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+#if PY_VERSION_HEX < 0x03000000
+    if (likely(PyInt_Check(x))) {
+        long val = PyInt_AS_LONG(x);
+        if (is_unsigned && unlikely(val < 0)) {
+            PyErr_SetString(PyExc_OverflowError,
+                            "can't convert negative value to unsigned long");
+            return (unsigned long)-1;
+        }
+        return (unsigned long)val;
+    } else
+#endif
+    if (likely(PyLong_Check(x))) {
+        if (is_unsigned) {
+            if (unlikely(Py_SIZE(x) < 0)) {
+                PyErr_SetString(PyExc_OverflowError,
+                                "can't convert negative value to unsigned long");
+                return (unsigned long)-1;
+            }
+            return PyLong_AsUnsignedLong(x);
+        } else {
+            return PyLong_AsLong(x);
+        }
+    } else {
+        unsigned long val;
+        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        if (!tmp) return (unsigned long)-1;
+        val = __Pyx_PyInt_AsUnsignedLong(tmp);
+        Py_DECREF(tmp);
+        return val;
+    }
+}
+
+static CYTHON_INLINE unsigned PY_LONG_LONG __Pyx_PyInt_AsUnsignedLongLong(PyObject* x) {
+    const unsigned PY_LONG_LONG neg_one = (unsigned PY_LONG_LONG)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+#if PY_VERSION_HEX < 0x03000000
+    if (likely(PyInt_Check(x))) {
+        long val = PyInt_AS_LONG(x);
+        if (is_unsigned && unlikely(val < 0)) {
+            PyErr_SetString(PyExc_OverflowError,
+                            "can't convert negative value to unsigned PY_LONG_LONG");
+            return (unsigned PY_LONG_LONG)-1;
+        }
+        return (unsigned PY_LONG_LONG)val;
+    } else
+#endif
+    if (likely(PyLong_Check(x))) {
+        if (is_unsigned) {
+            if (unlikely(Py_SIZE(x) < 0)) {
+                PyErr_SetString(PyExc_OverflowError,
+                                "can't convert negative value to unsigned PY_LONG_LONG");
+                return (unsigned PY_LONG_LONG)-1;
+            }
+            return PyLong_AsUnsignedLongLong(x);
+        } else {
+            return PyLong_AsLongLong(x);
+        }
+    } else {
+        unsigned PY_LONG_LONG val;
+        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        if (!tmp) return (unsigned PY_LONG_LONG)-1;
+        val = __Pyx_PyInt_AsUnsignedLongLong(tmp);
+        Py_DECREF(tmp);
+        return val;
+    }
+}
+
+static CYTHON_INLINE long __Pyx_PyInt_AsLong(PyObject* x) {
+    const long neg_one = (long)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+#if PY_VERSION_HEX < 0x03000000
+    if (likely(PyInt_Check(x))) {
+        long val = PyInt_AS_LONG(x);
+        if (is_unsigned && unlikely(val < 0)) {
+            PyErr_SetString(PyExc_OverflowError,
+                            "can't convert negative value to long");
+            return (long)-1;
+        }
+        return (long)val;
+    } else
+#endif
+    if (likely(PyLong_Check(x))) {
+        if (is_unsigned) {
+            if (unlikely(Py_SIZE(x) < 0)) {
+                PyErr_SetString(PyExc_OverflowError,
+                                "can't convert negative value to long");
+                return (long)-1;
+            }
+            return PyLong_AsUnsignedLong(x);
+        } else {
+            return PyLong_AsLong(x);
+        }
+    } else {
+        long val;
+        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        if (!tmp) return (long)-1;
+        val = __Pyx_PyInt_AsLong(tmp);
+        Py_DECREF(tmp);
+        return val;
+    }
+}
+
+static CYTHON_INLINE PY_LONG_LONG __Pyx_PyInt_AsLongLong(PyObject* x) {
+    const PY_LONG_LONG neg_one = (PY_LONG_LONG)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+#if PY_VERSION_HEX < 0x03000000
+    if (likely(PyInt_Check(x))) {
+        long val = PyInt_AS_LONG(x);
+        if (is_unsigned && unlikely(val < 0)) {
+            PyErr_SetString(PyExc_OverflowError,
+                            "can't convert negative value to PY_LONG_LONG");
+            return (PY_LONG_LONG)-1;
+        }
+        return (PY_LONG_LONG)val;
+    } else
+#endif
+    if (likely(PyLong_Check(x))) {
+        if (is_unsigned) {
+            if (unlikely(Py_SIZE(x) < 0)) {
+                PyErr_SetString(PyExc_OverflowError,
+                                "can't convert negative value to PY_LONG_LONG");
+                return (PY_LONG_LONG)-1;
+            }
+            return PyLong_AsUnsignedLongLong(x);
+        } else {
+            return PyLong_AsLongLong(x);
+        }
+    } else {
+        PY_LONG_LONG val;
+        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        if (!tmp) return (PY_LONG_LONG)-1;
+        val = __Pyx_PyInt_AsLongLong(tmp);
+        Py_DECREF(tmp);
+        return val;
+    }
+}
+
+static CYTHON_INLINE signed long __Pyx_PyInt_AsSignedLong(PyObject* x) {
+    const signed long neg_one = (signed long)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+#if PY_VERSION_HEX < 0x03000000
+    if (likely(PyInt_Check(x))) {
+        long val = PyInt_AS_LONG(x);
+        if (is_unsigned && unlikely(val < 0)) {
+            PyErr_SetString(PyExc_OverflowError,
+                            "can't convert negative value to signed long");
+            return (signed long)-1;
+        }
+        return (signed long)val;
+    } else
+#endif
+    if (likely(PyLong_Check(x))) {
+        if (is_unsigned) {
+            if (unlikely(Py_SIZE(x) < 0)) {
+                PyErr_SetString(PyExc_OverflowError,
+                                "can't convert negative value to signed long");
+                return (signed long)-1;
+            }
+            return PyLong_AsUnsignedLong(x);
+        } else {
+            return PyLong_AsLong(x);
+        }
+    } else {
+        signed long val;
+        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        if (!tmp) return (signed long)-1;
+        val = __Pyx_PyInt_AsSignedLong(tmp);
+        Py_DECREF(tmp);
+        return val;
+    }
+}
+
+static CYTHON_INLINE signed PY_LONG_LONG __Pyx_PyInt_AsSignedLongLong(PyObject* x) {
+    const signed PY_LONG_LONG neg_one = (signed PY_LONG_LONG)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+#if PY_VERSION_HEX < 0x03000000
+    if (likely(PyInt_Check(x))) {
+        long val = PyInt_AS_LONG(x);
+        if (is_unsigned && unlikely(val < 0)) {
+            PyErr_SetString(PyExc_OverflowError,
+                            "can't convert negative value to signed PY_LONG_LONG");
+            return (signed PY_LONG_LONG)-1;
+        }
+        return (signed PY_LONG_LONG)val;
+    } else
+#endif
+    if (likely(PyLong_Check(x))) {
+        if (is_unsigned) {
+            if (unlikely(Py_SIZE(x) < 0)) {
+                PyErr_SetString(PyExc_OverflowError,
+                                "can't convert negative value to signed PY_LONG_LONG");
+                return (signed PY_LONG_LONG)-1;
+            }
+            return PyLong_AsUnsignedLongLong(x);
+        } else {
+            return PyLong_AsLongLong(x);
+        }
+    } else {
+        signed PY_LONG_LONG val;
+        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        if (!tmp) return (signed PY_LONG_LONG)-1;
+        val = __Pyx_PyInt_AsSignedLongLong(tmp);
+        Py_DECREF(tmp);
+        return val;
+    }
+}
+
+static int __Pyx_SetVtable(PyObject *dict, void *vtable) {
+#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
+    PyObject *ob = PyCapsule_New(vtable, 0, 0);
+#else
+    PyObject *ob = PyCObject_FromVoidPtr(vtable, 0);
+#endif
+    if (!ob)
+        goto bad;
+    if (PyDict_SetItemString(dict, "__pyx_vtable__", ob) < 0)
+        goto bad;
+    Py_DECREF(ob);
+    return 0;
+bad:
+    Py_XDECREF(ob);
+    return -1;
+}
+
+#include "compile.h"
+#include "frameobject.h"
+#include "traceback.h"
+
+static void __Pyx_AddTraceback(const char *funcname) {
+    PyObject *py_srcfile = 0;
+    PyObject *py_funcname = 0;
+    PyObject *py_globals = 0;
+    PyCodeObject *py_code = 0;
+    PyFrameObject *py_frame = 0;
+
+    #if PY_MAJOR_VERSION < 3
+    py_srcfile = PyString_FromString(__pyx_filename);
+    #else
+    py_srcfile = PyUnicode_FromString(__pyx_filename);
+    #endif
+    if (!py_srcfile) goto bad;
+    if (__pyx_clineno) {
+        #if PY_MAJOR_VERSION < 3
+        py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, __pyx_clineno);
+        #else
+        py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, __pyx_clineno);
+        #endif
+    }
+    else {
+        #if PY_MAJOR_VERSION < 3
+        py_funcname = PyString_FromString(funcname);
+        #else
+        py_funcname = PyUnicode_FromString(funcname);
+        #endif
+    }
+    if (!py_funcname) goto bad;
+    py_globals = PyModule_GetDict(__pyx_m);
+    if (!py_globals) goto bad;
+    py_code = PyCode_New(
+        0,            /*int argcount,*/
+        #if PY_MAJOR_VERSION >= 3
+        0,            /*int kwonlyargcount,*/
+        #endif
+        0,            /*int nlocals,*/
+        0,            /*int stacksize,*/
+        0,            /*int flags,*/
+        __pyx_empty_bytes, /*PyObject *code,*/
+        __pyx_empty_tuple,  /*PyObject *consts,*/
+        __pyx_empty_tuple,  /*PyObject *names,*/
+        __pyx_empty_tuple,  /*PyObject *varnames,*/
+        __pyx_empty_tuple,  /*PyObject *freevars,*/
+        __pyx_empty_tuple,  /*PyObject *cellvars,*/
+        py_srcfile,   /*PyObject *filename,*/
+        py_funcname,  /*PyObject *name,*/
+        __pyx_lineno,   /*int firstlineno,*/
+        __pyx_empty_bytes  /*PyObject *lnotab*/
+    );
+    if (!py_code) goto bad;
+    py_frame = PyFrame_New(
+        PyThreadState_GET(), /*PyThreadState *tstate,*/
+        py_code,             /*PyCodeObject *code,*/
+        py_globals,          /*PyObject *globals,*/
+        0                    /*PyObject *locals*/
+    );
+    if (!py_frame) goto bad;
+    py_frame->f_lineno = __pyx_lineno;
+    PyTraceBack_Here(py_frame);
+bad:
+    Py_XDECREF(py_srcfile);
+    Py_XDECREF(py_funcname);
+    Py_XDECREF(py_code);
+    Py_XDECREF(py_frame);
+}
+
+static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
+    while (t->p) {
+        #if PY_MAJOR_VERSION < 3
+        if (t->is_unicode) {
+            *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL);
+        } else if (t->intern) {
+            *t->p = PyString_InternFromString(t->s);
+        } else {
+            *t->p = PyString_FromStringAndSize(t->s, t->n - 1);
+        }
+        #else  /* Python 3+ has unicode identifiers */
+        if (t->is_unicode | t->is_str) {
+            if (t->intern) {
+                *t->p = PyUnicode_InternFromString(t->s);
+            } else if (t->encoding) {
+                *t->p = PyUnicode_Decode(t->s, t->n - 1, t->encoding, NULL);
+            } else {
+                *t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1);
+            }
+        } else {
+            *t->p = PyBytes_FromStringAndSize(t->s, t->n - 1);
+        }
+        #endif
+        if (!*t->p)
+            return -1;
+        ++t;
+    }
+    return 0;
+}
+
+/* Type Conversion Functions */
+
+static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) {
+   int is_true = x == Py_True;
+   if (is_true | (x == Py_False) | (x == Py_None)) return is_true;
+   else return PyObject_IsTrue(x);
+}
+
+static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) {
+  PyNumberMethods *m;
+  const char *name = NULL;
+  PyObject *res = NULL;
+#if PY_VERSION_HEX < 0x03000000
+  if (PyInt_Check(x) || PyLong_Check(x))
+#else
+  if (PyLong_Check(x))
+#endif
+    return Py_INCREF(x), x;
+  m = Py_TYPE(x)->tp_as_number;
+#if PY_VERSION_HEX < 0x03000000
+  if (m && m->nb_int) {
+    name = "int";
+    res = PyNumber_Int(x);
+  }
+  else if (m && m->nb_long) {
+    name = "long";
+    res = PyNumber_Long(x);
+  }
+#else
+  if (m && m->nb_int) {
+    name = "int";
+    res = PyNumber_Long(x);
+  }
+#endif
+  if (res) {
+#if PY_VERSION_HEX < 0x03000000
+    if (!PyInt_Check(res) && !PyLong_Check(res)) {
+#else
+    if (!PyLong_Check(res)) {
+#endif
+      PyErr_Format(PyExc_TypeError,
+                   "__%s__ returned non-%s (type %.200s)",
+                   name, name, Py_TYPE(res)->tp_name);
+      Py_DECREF(res);
+      return NULL;
+    }
+  }
+  else if (!PyErr_Occurred()) {
+    PyErr_SetString(PyExc_TypeError,
+                    "an integer is required");
+  }
+  return res;
+}
+
+static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) {
+  Py_ssize_t ival;
+  PyObject* x = PyNumber_Index(b);
+  if (!x) return -1;
+  ival = PyInt_AsSsize_t(x);
+  Py_DECREF(x);
+  return ival;
+}
+
+static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) {
+#if PY_VERSION_HEX < 0x02050000
+   if (ival <= LONG_MAX)
+       return PyInt_FromLong((long)ival);
+   else {
+       unsigned char *bytes = (unsigned char *) &ival;
+       int one = 1; int little = (int)*(unsigned char*)&one;
+       return _PyLong_FromByteArray(bytes, sizeof(size_t), little, 0);
+   }
+#else
+   return PyInt_FromSize_t(ival);
+#endif
+}
+
+static CYTHON_INLINE size_t __Pyx_PyInt_AsSize_t(PyObject* x) {
+   unsigned PY_LONG_LONG val = __Pyx_PyInt_AsUnsignedLongLong(x);
+   if (unlikely(val == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())) {
+       return (size_t)-1;
+   } else if (unlikely(val != (unsigned PY_LONG_LONG)(size_t)val)) {
+       PyErr_SetString(PyExc_OverflowError,
+                       "value too large to convert to size_t");
+       return (size_t)-1;
+   }
+   return (size_t)val;
+}
+
+
+#endif /* Py_PYTHON_H */
diff --git a/imposm/cache/tc.pyx b/imposm/cache/tc.pyx
new file mode 100644
index 0000000..e9111ae
--- /dev/null
+++ b/imposm/cache/tc.pyx
@@ -0,0 +1,269 @@
+from imposm.base import Node, Way, Relation
+from libc.stdint cimport uint32_t, int64_t
+
+cdef extern from "Python.h":
+    object PyString_FromStringAndSize(char *s, Py_ssize_t len)
+
+cdef extern from "marshal.h":
+    object PyMarshal_ReadObjectFromString(char *string, Py_ssize_t len)
+    object PyMarshal_WriteObjectToString(object value, int version)
+
+cdef extern from "tcutil.h":
+    ctypedef int TCCMP()
+    cdef int tccmpint32()
+    cdef int tccmpint64()
+
+cdef extern from "tcbdb.h":
+    ctypedef enum:
+        BDBFOPEN
+        BDBFFATAL
+
+    ctypedef enum:
+        BDBOREADER = 1 << 0 # /* open as a reader */
+        BDBOWRITER = 1 << 1 # /* open as a writer */
+        BDBOCREAT = 1 << 2  # /* writer creating */
+        BDBOTRUNC = 1 << 3  # /* writer truncating */
+        BDBONOLCK = 1 << 4  # /* open without locking */
+        BDBOLCKNB = 1 << 5  # /* lock without blocking */
+        BDBOTSYNC = 1 << 6  # /* synchronize every transaction */
+
+    ctypedef enum:
+        BDBTLARGE = 1 << 0,  # /* use 64-bit bucket array */
+        BDBTDEFLATE = 1 << 1 # /* compress each page with Deflate */
+        BDBTBZIP = 1 << 2,   # /* compress each record with BZIP2 */
+        BDBTTCBS = 1 << 3,   # /* compress each page with TCBS */
+        BDBTEXCODEC = 1 << 4 # /* compress each record with outer functions */
+
+    ctypedef void TCBDB
+    ctypedef void BDBCUR
+
+    TCBDB *tcbdbnew()
+    void tcbdbdel(TCBDB *)
+    int tcbdbecode(TCBDB *)
+
+    bint tcbdbtune(TCBDB *db, int lmemb, int nmemb,
+                   int bnum, int apow, int fpow, int opts)
+    bint tcbdbsetcache(TCBDB *bdb, int lcnum, int ncnum)
+
+    bint tcbdbsetcmpfunc(TCBDB *bdb, TCCMP cmp, void *cmpop)
+    bint tcbdbsetmutex(TCBDB *bdb)
+
+    bint tcbdbopen(TCBDB *, char *, int)
+    bint tcbdbclose(TCBDB *) nogil
+    bint tcbdbput(TCBDB *, void *, int, void *, int) nogil
+    void *tcbdbget(TCBDB *, void *, int, int *) nogil
+    void *tcbdbget3(TCBDB *bdb, void *kbuf, int ksiz, int *sp) nogil
+
+    long tcbdbrnum(TCBDB *bdb)
+
+    BDBCUR *tcbdbcurnew(TCBDB *bdb)
+    void tcbdbcurdel(BDBCUR *cur)
+    bint tcbdbcurfirst(BDBCUR *cur)
+    bint tcbdbcurnext(BDBCUR *cur)
+    void *tcbdbcurkey3(BDBCUR *cur, int *sp)
+    void *tcbdbcurval3(BDBCUR *cur, int *sp)
+
+
+DEF COORD_FACTOR = 11930464.7083 # ((2<<31)-1)/360.0
+
+cdef uint32_t _coord_to_uint32(double x) nogil:
+    return <uint32_t>((x + 180.0) * COORD_FACTOR)
+
+cdef double _uint32_to_coord(uint32_t x) nogil:
+    return <double>((x / COORD_FACTOR) - 180.0)
+
+ctypedef struct coord:
+    uint32_t x
+    uint32_t y
+
+cdef inline coord coord_struct(double x, double y) nogil:
+    cdef coord p
+    p.x = _coord_to_uint32(x)
+    p.y = _coord_to_uint32(y)
+    return p
+
+_modes = {
+    'w': BDBOWRITER | BDBOCREAT,
+    'r': BDBOREADER | BDBONOLCK,
+}
+
+cdef class BDB:
+    cdef TCBDB *db
+    cdef object filename
+    cdef int _opened
+    cdef BDBCUR *_cur
+    def __cinit__(self, filename, mode='w', estimated_records=0):
+        self.db = tcbdbnew()
+        self._opened = 0
+
+    def __init__(self, filename, mode='w', estimated_records=0):
+        self.filename = filename
+        self._tune_db(estimated_records)
+        tcbdbsetcmpfunc(self.db, tccmpint64, NULL)
+        if not tcbdbopen(self.db, filename, _modes[mode]):
+            raise IOError
+        self._opened = 1
+    
+    def _tune_db(self, estimated_records):
+        if estimated_records:
+            lmemb = 128 # default
+            nmemb = -1
+            fpow = 13 # 2^13 = 8196
+            bnum = int((estimated_records*3)/lmemb)
+            tcbdbtune(self.db, lmemb, nmemb, bnum, 5, fpow, BDBTLARGE | BDBTDEFLATE)
+        else:
+            tcbdbtune(self.db, -1, -1, -1, 5, 13, BDBTLARGE | BDBTDEFLATE)
+    
+    def get(self, int64_t osmid):
+        """
+        Return object with given id.
+        Returns None if id is not stored.
+        """
+        cdef void *ret
+        cdef int ret_size
+        ret = tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)
+        if not ret: return None
+        return self._obj(osmid, PyMarshal_ReadObjectFromString(<char *>ret, ret_size))
+
+    cdef object _obj(self, int64_t osmid, data):
+        """
+        Create an object from the id and unmarshaled data.
+        Should be overridden by subclasses.
+        """
+        pass
+
+    def __iter__(self):
+        """
+        Return an iterator over the database.
+        Resets any existing iterator.
+        """
+        if self._cur:
+            tcbdbcurdel(self._cur)
+        self._cur = tcbdbcurnew(self.db)
+        if not tcbdbcurfirst(self._cur):
+            return iter([])
+        return self
+
+    def __contains__(self, int64_t osmid):
+        cdef void *ret
+        cdef int ret_size
+        ret = tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size);
+        if ret:
+            return 1
+        else:
+            return 0
+    
+    def __len__(self):
+        return tcbdbrnum(self.db)
+    
+    def __next__(self):
+        """
+        Return next item as object.
+        """
+        cdef int64_t osmid
+
+        if not self._cur: raise StopIteration
+
+        osmid, data = self._get_cur()
+
+        # advance cursor, set to NULL if at the end
+        if tcbdbcurnext(self._cur) == 0:
+            tcbdbcurdel(self._cur)
+            self._cur = NULL
+        
+        # return objectified item
+        return self._obj(osmid, data)
+
+    cdef object _get_cur(self):
+        """
+        Return the current object at the current cursor position
+        as a tuple of the id and the unmarshaled data.
+        """
+        cdef int size
+        cdef void *ret
+        ret = tcbdbcurkey3(self._cur, &size)
+        osmid = (<int64_t *>ret)[0]
+        ret = tcbdbcurval3(self._cur, &size)
+        value = PyMarshal_ReadObjectFromString(<char *>ret, size)
+        return osmid, value
+
+    def close(self):
+        if self._opened:
+            tcbdbclose(self.db)
+        self._opened = 0
+    
+    def __dealloc__(self):
+        if self._opened:
+            tcbdbclose(self.db)
+        tcbdbdel(self.db)
+
+cdef class CoordDB(BDB):
+    def put(self, osmid, x, y):
+        return self._put(osmid, x, y)
+    
+    def put_marshaled(self, osmid, x, y):
+        return self._put(osmid, x, y)
+    
+    cdef bint _put(self, int64_t osmid, double x, double y) nogil:
+        cdef coord p = coord_struct(x, y)
+        return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>&p, sizeof(coord))
+
+    def get(self, int64_t osmid):
+        cdef coord *value
+        cdef int ret_size
+        value = <coord *>tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)
+        if not value: return
+        return _uint32_to_coord(value.x), _uint32_to_coord(value.y)
+
+    def get_coords(self, refs):
+        cdef coord *value
+        cdef int ret_size
+        cdef int64_t osmid
+        coords = list()
+        for osmid in refs:
+            value = <coord *>tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)
+            if not value: return
+            coords.append((_uint32_to_coord(value.x), _uint32_to_coord(value.y)))
+        
+        return coords
+
+    cdef object _get_cur(self):
+        cdef int size
+        cdef int64_t osmid
+        cdef void *ret
+        cdef coord *value
+        ret = tcbdbcurkey3(self._cur, &size)
+        osmid = (<int64_t *>ret)[0]
+        value = <coord *>tcbdbcurval3(self._cur, &size)
+        return osmid, (_uint32_to_coord(value.x), _uint32_to_coord(value.y))
+
+    cdef object _obj(self, int64_t osmid, data):
+        return osmid, data
+
+cdef class NodeDB(BDB):
+    def put(self, osmid, tags, pos):
+        return self.put_marshaled(osmid, PyMarshal_WriteObjectToString((tags, pos), 2))
+    
+    def put_marshaled(self, int64_t osmid, data):
+        return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>data, len(data))
+
+    cdef object _obj(self, int64_t osmid, data):
+        return Node(osmid, data[0], data[1])
+
+cdef class RefTagDB(BDB):
+    """
+    Database for items with references and tags (i.e. ways/relations).
+    """
+    def put(self, osmid, tags, refs):
+        return self.put_marshaled(osmid, PyMarshal_WriteObjectToString((tags, refs), 2))
+    
+    def put_marshaled(self, int64_t osmid, data):
+        return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>data, len(data))
+
+cdef class WayDB(RefTagDB):
+    cdef object _obj(self, int64_t osmid, data):
+        return Way(osmid, data[0], data[1])
+
+cdef class RelationDB(RefTagDB):
+    cdef object _obj(self, int64_t osmid, data):
+        return Relation(osmid, data[0], data[1])
diff --git a/imposm/db/__init__.py b/imposm/db/__init__.py
new file mode 100644
index 0000000..14129d9
--- /dev/null
+++ b/imposm/db/__init__.py
@@ -0,0 +1,4 @@
+from . postgis import PostGISDB
+
+def DB(db_conf):
+    return PostGISDB(db_conf)
\ No newline at end of file
diff --git a/imposm/db/postgis.py b/imposm/db/postgis.py
new file mode 100644
index 0000000..5382102
--- /dev/null
+++ b/imposm/db/postgis.py
@@ -0,0 +1,353 @@
+# Copyright 2011 Omniscale (http://omniscale.com)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import time
+
+import psycopg2
+import psycopg2.extensions
+
+import logging
+log = logging.getLogger(__name__)
+
+from imposm.mapping import UnionView, GeneralizedTable, Mapping
+
+class PostGISDB(object):
+    def __init__(self, db_conf):
+        self.db_conf = db_conf
+        self.srid = int(db_conf['proj'].split(':')[1])
+        self._insert_stmts = {}
+        self._connection = None
+        self._cur = None
+
+    @property
+    def table_prefix(self):
+        return self.db_conf.prefix
+
+    def to_tablename(self, name):
+        return self.table_prefix.rstrip('_') + '_' + name.lower()
+
+    @property
+    def connection(self):
+        if not self._connection:
+            self._connection = psycopg2.connect(
+                database=self.db_conf.db,
+                host=self.db_conf.host,
+                user=self.db_conf.user,
+                password=self.db_conf.password,
+                sslmode=self.db_conf.get('sslmode', 'allow'),
+            )
+            self._connection.set_isolation_level(
+                psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED)
+        return self._connection
+    
+    @property
+    def cur(self):
+        if self._cur is None:
+            self._cur = self.connection.cursor()
+        return self._cur
+    
+    def insert(self, mapping, insert_data, tries=0):
+        insert_stmt = self.insert_stmt(mapping)
+        try:
+            if tries:
+                self.reconnect()
+            self.cur.executemany(insert_stmt, insert_data)
+        except psycopg2.OperationalError, ex:
+            if tries >= 8:
+                log.warn('%s, giving up', ex)
+                raise
+            seconds = 2 ** (tries + 1)
+            log.warn('%s, retry in %d', ex, seconds)
+            time.sleep(seconds)
+            self.insert(mapping, insert_data, tries=tries + 1)
+        except psycopg2.Error, ex:
+            self.connection.rollback()
+            for data in insert_data:
+                try:
+                    self.cur.execute(insert_stmt, data)
+                except psycopg2.Error, ex:
+                    log.warn('error while importing "%r": %s', data, ex)
+                    self.connection.rollback()
+                else:
+                    self.connection.commit()
+
+        self.connection.commit()
+    
+    def wkb_wrapper(self, wkb):
+        return psycopg2.Binary(wkb)
+    
+    def reconnect(self):
+        if self._connection:
+            try:
+                self._connection.close()
+            except psycopg2.InterfaceError:
+                pass
+        self._connection = None
+        self._cur = None
+
+    def insert_stmt(self, mapping):
+        if mapping.name not in self._insert_stmts:
+            self._insert_stmts[mapping.name] = self._insert_stmt(mapping)
+
+        return self._insert_stmts[mapping.name]
+
+    def _insert_stmt(self, mapping):
+        extra_arg_names = extra_args = ''
+        if mapping.fields:
+            extra_arg_names = [n for n, t in mapping.fields]
+            extra_args = ', %s' * len(extra_arg_names)
+            extra_arg_names = ', ' + ', '.join('"' + name + '"' for name in extra_arg_names)
+        return """INSERT INTO "%(tablename)s"
+            (osm_id, name, type, geometry %(extra_arg_names)s)
+            VALUES (%%s, %%s, %%s, ST_Transform(ST_GeomFromWKB(%%s, 4326), %(srid)s)
+                %(extra_args)s)
+        """.strip() % dict(tablename=self.table_prefix + mapping.name, srid=self.srid,
+            extra_arg_names=extra_arg_names, extra_args=extra_args)
+
+
+    def create_tables(self, mappings):
+        for mapping in mappings:
+            self.create_table(mapping)
+
+    def create_table(self, mapping):
+        tablename = self.table_prefix + mapping.name
+        cur = self.connection.cursor()
+        cur.execute('SAVEPOINT pre_drop_tables')
+        try:
+            cur.execute('DROP TABLE "' + tablename + '" CASCADE')
+        except psycopg2.ProgrammingError:
+            cur.execute('ROLLBACK TO SAVEPOINT pre_drop_tables')
+
+        extra_fields = ''
+        for n, t in mapping.fields:
+            extra_fields += ', "%s" %s ' % (n, t.column_type)
+
+        cur.execute("""
+            CREATE TABLE "%s" (
+                osm_id INT4 PRIMARY KEY,
+                name VARCHAR(255),
+                type VARCHAR(255)
+                %s
+            );
+        """ % (tablename, extra_fields))
+        cur.execute("""
+            SELECT AddGeometryColumn ('', '%(tablename)s', 'geometry',
+                                      %(srid)s, '%(pg_geometry_type)s', 2)
+        """ % dict(tablename=tablename, srid=self.srid,
+                   pg_geometry_type=mapping.geom_type))
+        cur.execute("""
+            CREATE INDEX "%(tablename)s_geom" ON "%(tablename)s" USING GIST (geometry)
+        """ % dict(tablename=tablename))
+    
+    def swap_tables(self, new_prefix, existing_prefix, backup_prefix):
+        cur = self.connection.cursor()
+
+        self.remove_tables(backup_prefix)
+        
+        cur.execute('SELECT tablename FROM pg_tables WHERE tablename like %s', (existing_prefix + '%', ))
+        existing_tables = []
+        for row in cur:
+            table_name = row[0]
+            if not table_name.startswith((new_prefix, backup_prefix)):
+                existing_tables.append(table_name)
+
+        cur.execute('SELECT indexname FROM pg_indexes WHERE indexname like %s', (existing_prefix + '%', ))
+        existing_indexes = set()
+        for row in cur:
+            index_name = row[0]
+            if not index_name.startswith((new_prefix, backup_prefix)):
+                existing_indexes.add(index_name)
+        
+        cur.execute('SELECT tablename FROM pg_tables WHERE tablename like %s', (new_prefix + '%', ))
+        new_tables = []
+        for row in cur:
+            table_name = row[0]
+            new_tables.append(table_name)
+
+        cur.execute('SELECT indexname FROM pg_indexes WHERE indexname like %s', (new_prefix + '%', ))
+        new_indexes = set()
+        for row in cur:
+            index_name = row[0]
+            new_indexes.add(index_name)
+        
+        if not new_tables:
+            raise RuntimeError('did not found tables to swap')
+        
+        for table_name in existing_tables:
+            rename_to = table_name.replace(existing_prefix, backup_prefix)
+            cur.execute('ALTER TABLE "%s" RENAME TO "%s"' % (table_name, rename_to))
+            if table_name + '_geom' in existing_indexes:
+                cur.execute('ALTER INDEX "%s" RENAME TO "%s"' % (table_name + '_geom', rename_to + '_geom'))
+            if table_name + '_pkey' in existing_indexes:
+                cur.execute('ALTER INDEX "%s" RENAME TO "%s"' % (table_name + '_pkey', rename_to + '_pkey'))
+            cur.execute('UPDATE geometry_columns SET f_table_name = %s WHERE f_table_name = %s', (rename_to, table_name))
+            
+        for table_name in new_tables:
+            rename_to = table_name.replace(new_prefix, existing_prefix)
+            cur.execute('ALTER TABLE "%s" RENAME TO "%s"' % (table_name, rename_to))
+            if table_name + '_geom' in new_indexes:
+                cur.execute('ALTER INDEX "%s" RENAME TO "%s"' % (table_name + '_geom', rename_to + '_geom'))
+            if table_name + '_pkey' in new_indexes:
+                cur.execute('ALTER INDEX "%s" RENAME TO "%s"' % (table_name + '_pkey', rename_to + '_pkey'))
+            cur.execute('UPDATE geometry_columns SET f_table_name = %s WHERE f_table_name = %s', (rename_to, table_name))
+        
+    def remove_tables(self, prefix):
+        cur = self.connection.cursor()
+        cur.execute('SELECT tablename FROM pg_tables WHERE tablename like %s', (prefix + '%', ))
+        remove_tables = [row[0] for row in cur]
+        
+        for table_name in remove_tables:
+            cur.execute("DROP TABLE %s CASCADE" % (table_name, ))
+            cur.execute("DELETE FROM geometry_columns WHERE f_table_name = %s", (table_name, ))
+        
+
+    def remove_views(self, prefix):
+        cur = self.connection.cursor()
+        cur.execute('SELECT viewname FROM pg_views WHERE viewname like %s', (prefix + '%', ))
+        remove_views = [row[0] for row in cur]
+        
+        for view_name in remove_views:
+            cur.execute('DROP VIEW "%s" CASCADE' % (view_name, ))
+            cur.execute("DELETE FROM geometry_columns WHERE f_table_name = %s", (view_name, ))
+        
+    
+    def create_views(self, mappings, ignore_errors=False):
+        for mapping in mappings.values():
+            if isinstance(mapping, UnionView):
+                PostGISUnionView(self, mapping).create(ignore_errors=ignore_errors)
+    
+    def create_generalized_tables(self, mappings):
+        mappings = [m for m in mappings.values() if isinstance(m, GeneralizedTable)]
+        for mapping in sorted(mappings, key=lambda x: x.name, reverse=True):
+            PostGISGeneralizedTable(self, mapping).create()
+
+    def optimize(self, mappings):
+        mappings = [m for m in mappings.values() if isinstance(m, (GeneralizedTable, Mapping))]
+        for mapping in mappings:
+            table_name = self.to_tablename(mapping.name)
+            self.optimize_table(table_name, '%s_geom' % table_name)
+        self.vacuum()
+
+    def optimize_table(self, table_name, idx_name):
+        cur = self.connection.cursor()
+        print 'Clustering table %s' % table_name
+        cur.execute('CLUSTER "%s" ON "%s"' % (idx_name, table_name))
+        self.connection.commit()
+
+    def vacuum(self):
+        old_isolation_level = self.connection.isolation_level
+        self.reconnect()
+        self.connection.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
+        cur = self.connection.cursor()
+        print 'Vacuum analyze'
+        cur.execute("VACUUM ANALYZE")
+        self.connection.set_isolation_level(old_isolation_level)
+
+
+class PostGISUnionView(object):
+    def __init__(self, db, mapping):
+        self.mapping = mapping
+        self.db = db
+        self.view_name = db.to_tablename(mapping.name)
+
+    def _view_stmt(self):
+        selects = []
+        for mapping in self.mapping.mappings:
+            field_str = ', '.join(self._mapping_fields(mapping))
+            selects.append("""SELECT osm_id, name, type, geometry, %s,
+                '%s' as class from "%s" """ % (
+                field_str, mapping.classname or mapping.name, self.db.to_tablename(mapping.name)))
+
+        selects = '\nUNION ALL\n'.join(selects)
+
+        stmt = 'CREATE OR REPLACE VIEW "%s" as (\n%s\n)' % (self.view_name, selects)
+        
+        print stmt
+        return stmt
+
+    def _geom_table_stmt(self):
+        stmt = "insert into geometry_columns values ('', 'public', '%s', 'geometry', 2, %d, 'GEOMETRY')" % (
+            self.view_name, self.db.srid)
+        return stmt
+
+    def _mapping_fields(self, mapping):
+        mapping_fields = set([n for n, t in mapping.fields])
+        fields = []
+        for name, default in self.mapping.fields:
+            if name in mapping_fields:
+                fields.append('"' + name + '"')
+            else:
+                if default is None:
+                    default = 'null'
+                elif isinstance(default, basestring):
+                    default = "'%s'" % default
+                else:
+                    default = str(default)
+                fields.append(default + ' as "' + name + '"')
+        return fields
+
+    def create(self, ignore_errors):
+        cur = self.db.connection.cursor()
+        cur.execute('BEGIN')
+        try:
+            cur.execute('SAVEPOINT pre_create_view')
+            cur.execute(self._view_stmt())
+        except psycopg2.ProgrammingError:
+            cur.execute('ROLLBACK TO SAVEPOINT pre_create_view')
+            if not ignore_errors:
+                raise
+
+        cur.execute('select * from geometry_columns where f_table_name = %s', (self.view_name, ))
+        if not cur.fetchall():
+            cur.execute(self._geom_table_stmt())
+
+
+class PostGISGeneralizedTable(object):
+    def __init__(self, db, mapping):
+        self.db = db
+        self.mapping = mapping
+        self.table_name = db.to_tablename(mapping.name)
+
+    def _idx_stmt(self):
+        return 'CREATE INDEX "%s_geom" ON "%s" USING GIST (geometry)' % (
+            self.table_name, self.table_name)
+
+    def _geom_table_stmt(self):
+        stmt = "insert into geometry_columns values ('', 'public', '%s', 'geometry', 2, %d, 'GEOMETRY')" % (
+            self.table_name, self.db.srid)
+        return stmt
+
+    def _stmt(self):
+        fields = ', '.join([n for n, t in self.mapping.fields])
+        return """CREATE TABLE "%s" AS (SELECT osm_id, name, type, %s,
+            ST_Simplify(geometry, %f) as geometry from "%s")""" % (
+            self.table_name, fields, self.mapping.tolerance, self.db.to_tablename(self.mapping.origin.name))
+
+    def create(self):
+        cur = self.db.connection.cursor()
+        cur.execute('BEGIN')
+        try:
+            cur.execute('SAVEPOINT pre_drop_table')
+            cur.execute('DROP TABLE "%s" CASCADE' % (self.table_name, ))
+        except psycopg2.ProgrammingError:
+            cur.execute('ROLLBACK TO SAVEPOINT pre_drop_table')
+        
+
+        cur.execute(self._stmt())
+        cur.execute(self._idx_stmt())
+
+        cur.execute('select * from geometry_columns where f_table_name = %s', (self.table_name, ))
+        if not cur.fetchall():
+            cur.execute(self._geom_table_stmt())
+
diff --git a/imposm/dbimporter.py b/imposm/dbimporter.py
new file mode 100644
index 0000000..eb76568
--- /dev/null
+++ b/imposm/dbimporter.py
@@ -0,0 +1,185 @@
+# Copyright 2011 Omniscale (http://omniscale.com)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from collections import defaultdict
+from multiprocessing import Process
+
+import threading
+from Queue import Queue 
+
+from imposm.base import OSMElem
+from imposm.geom import IncompletePolygonError
+from imposm.mapping import DropElem
+from imposm.multipolygon import RelationBuilder
+from imposm.util import setproctitle
+
+
+import logging
+log = logging.getLogger(__name__)
+
+class ImporterProcess(Process):
+    name = 'importer'
+
+    def __init__(self, in_queue, db, mapper, osm_cache, dry_run):
+        Process.__init__(self)
+        self.daemon = True
+        setproctitle('imposm %s process' % self.name)
+
+        self.in_queue = in_queue
+        self.mapper = mapper
+        self.osm_cache = osm_cache
+        self.db = db
+        self.dry_run = dry_run
+
+    def run(self):
+        self.setup()
+        # cProfile.runctx('self.doit()', globals(), locals(), 'profile%s.dat' % (self.name,))
+        self.doit()
+        self.teardown()
+
+    def setup(self):
+        self.db_queue = Queue(256)
+        self.db_importer = DBImporter(self.db_queue, self.db, dry_run=self.dry_run)
+        self.db_importer.start()
+
+    def doit(self):
+        pass
+
+    def teardown(self):
+        self.osm_cache.close_all()
+        self.db_queue.put(None)
+        self.db_importer.join()
+
+    def insert(self, mappings, osm_id, geom, tags):
+        inserted = False
+        for type, ms in mappings:
+            for m in ms:
+                osm_elem = OSMElem(osm_id, geom, type, tags)
+                try:
+                    m.name_filter(osm_elem)
+                    m.filter(osm_elem)
+                    m.build_geom(osm_elem)
+                    extra_args = m.field_values(osm_elem)
+                    self.db_queue.put((m, osm_id, osm_elem, extra_args))
+                    inserted = True
+                except DropElem:
+                    pass
+        return inserted
+
+class NodeProcess(ImporterProcess):
+    name = 'node'
+
+    def doit(self):        
+        while True:
+            nodes = self.in_queue.get()
+            if nodes is None:
+                break
+            
+            for node in nodes:
+                mappings = self.mapper.for_nodes(node.tags)
+                if not mappings:
+                    continue
+
+                self.insert(mappings, node.osm_id, node.coord, node.tags)
+
+class WayProcess(ImporterProcess):
+    name = 'way'
+
+    def doit(self):
+        coords_cache = self.osm_cache.coords_cache(mode='r')
+
+        while True:
+            ways = self.in_queue.get()
+            if ways is None:
+                break
+
+            for way in ways:
+                if way.tags.get('_inserted_'):
+                    continue
+                mappings = self.mapper.for_ways(way.tags)
+                if not mappings:
+                    continue
+                
+                coords = coords_cache.get_coords(way.refs)
+                
+                if not coords:
+                    print 'missing coords for way %s' % (way.osm_id, )
+                    continue
+                
+                self.insert(mappings, way.osm_id, coords, way.tags)
+
+
+class RelationProcess(ImporterProcess):
+    name = 'relation'
+
+    def __init__(self, in_queue, db, mapper, osm_cache, dry_run, inserted_way_queue):
+        ImporterProcess.__init__(self, in_queue, db, mapper, osm_cache, dry_run)
+        self.inserted_way_queue = inserted_way_queue
+
+    def doit(self):
+        coords_cache = self.osm_cache.coords_cache(mode='r')
+        ways_cache = self.osm_cache.ways_cache(mode='r')
+
+        while True:
+            relations = self.in_queue.get()
+            if relations is None:
+                break
+            
+            for relation in relations:
+                builder = RelationBuilder(relation, ways_cache, coords_cache)
+                try:
+                    builder.build()
+                except IncompletePolygonError, ex:
+                    if str(ex):
+                        log.debug(ex)
+                    continue
+                mappings = self.mapper.for_ways(relation.tags)
+                if mappings:
+                    inserted = self.insert(mappings, relation.osm_id, relation.geom, relation.tags)
+                    if inserted:
+                        builder.mark_inserted_ways(self.inserted_way_queue)
+
+
+class DBImporter(threading.Thread):
+    def __init__(self, queue, db, dry_run=False):
+        threading.Thread.__init__(self)
+        self.db = db
+        self.db.reconnect()
+        self.queue = queue
+        self.cur = None
+        self.dry_run = dry_run
+        self.mappings = defaultdict(list)
+
+    def run(self):
+        # cProfile.runctx('self.doit()', globals(), locals())
+        # def doit(self):
+        while True:
+            data = self.queue.get()
+            if data is None:
+                break
+
+            mapping, osm_id, osm_elem, extra_args = data
+            insert_data = self.mappings[mapping]
+            insert_data.append((osm_id, osm_elem.name, osm_elem.type, self.db.wkb_wrapper(osm_elem.geom.wkb)) + tuple(extra_args))
+
+            if len(insert_data) >= 128:
+                if not self.dry_run:
+                    self.db.insert(mapping, insert_data)
+                del self.mappings[mapping]
+
+        # flush
+        for mapping, insert_data in self.mappings.iteritems():
+            if not self.dry_run:
+                self.db.insert(mapping, insert_data)
+
diff --git a/imposm/defaultmapping.py b/imposm/defaultmapping.py
new file mode 100644
index 0000000..7168606
--- /dev/null
+++ b/imposm/defaultmapping.py
@@ -0,0 +1,419 @@
+# Copyright 2011 Omniscale (http://omniscale.com)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from imposm.mapping import (
+    Options,
+    Points, LineStrings, Polygons,
+    String, Bool, Integer, OneOfInt,
+    WayZOrder, ZOrder, Direction,
+    GeneralizedTable, UnionView,
+)
+
+db_conf = Options(
+    # db='osm',
+    host='localhost',
+    user='osm',
+    password='osm',
+    sslmode='allow',
+    prefix='osm_new_',
+    proj='epsg:900913',
+)
+
+class Highway(LineStrings):
+    fields = (
+        ('tunnel', Bool()),
+        ('bridge', Bool()),
+        ('oneway', Direction()),
+        ('ref', String()),
+        ('z_order', WayZOrder()),
+    )
+    field_filter = (
+        ('area', Bool()),
+    )
+
+places = Points(
+    name = 'places',
+    mapping = {
+        'place': (
+            'country',
+            'state',
+            'region',
+            'county',
+            'city',
+            'town',
+            'village',
+            'hamlet',
+            'suburb',
+            'locality',
+        ),
+    },
+    fields = (
+        ('z_order', ZOrder([
+            'country',
+            'state',
+            'region',
+            'county',
+            'city',
+            'town',
+            'village',
+            'hamlet',
+            'suburb',
+            'locality',
+        ])),
+        ('population', Integer()),
+    ),
+)
+
+admin = Polygons(
+    name = 'admin',
+    mapping = {
+        'boundary': (
+            'administrative',
+        ),
+    },
+    fields = (
+        ('admin_level', OneOfInt('1 2 3 4 5 6'.split())),
+    ),
+)
+
+motorways = Highway(
+    name = 'motorways',
+    mapping = {
+        'highway': (
+            'motorway',
+            'motorway_link',
+            'trunk',
+            'trunk_link',
+        ),
+    }
+)
+
+mainroads = Highway(
+    name = 'mainroads',
+    mapping = {
+        'highway': (
+            'primary',
+            'primary_link',
+            'secondary',
+            'secondary_link',
+            'tertiary',
+    )}
+)
+
+buildings = Polygons(
+    name = 'buildings',
+    mapping = {
+        'building': (
+            '__any__',
+    )}
+)
+
+minorroads = Highway(
+    name = 'minorroads',
+    mapping = {
+        'highway': (
+            'road',
+            'path',
+            'track',
+            'service',
+            'footway',
+            'bridleway',
+            'cycleway',
+            'steps',
+            'pedestrian',
+            'living_street',
+            'unclassified',
+            'residential',
+    )}
+)
+
+transport_points = Points(
+    name = 'transport_points',
+    fields = (
+        ('ref', String()),
+    ),
+    mapping = {
+        'highway': (
+            'motorway_junction',
+            'turning_circle',
+            'bus_stop',
+        ),
+        'railway': (
+            'station',
+            'halt',
+            'tram_stop',
+            'crossing',
+            'level_crossing',
+            'subway_entrance',
+        ),
+        'aeroway': (
+            'aerodome',
+            'terminal',
+            'helipad',
+            'gate',
+    )}
+)
+
+railways = LineStrings(
+    name = 'railways',
+    fields = (
+        ('tunnel', Bool()),
+        ('bridge', Bool()),
+        # ('ref', String()),
+        ('z_order', WayZOrder()),
+    ),
+    mapping = {
+        'railway': (
+            'rail',
+            'tram',
+            'light_rail',
+            'subway',
+            'narrow_gauge',
+            'preserved',
+            'funicular',
+            'monorail',
+    )}
+)
+
+waterways = LineStrings(
+    name = 'waterways',
+    mapping = {
+        'waterway': (
+            'stream',
+            'river',
+            'canal',
+            'drain',
+    )},
+    field_filter = (
+        ('tunnel', Bool()),
+    ),
+)
+
+waterareas = Polygons(
+    name = 'waterareas',
+    mapping = {
+        'waterway': ('riverbank',),
+        'natural': ('water',),
+        'landuse': ('basin', 'reservoir'),
+})
+
+aeroways = LineStrings(
+    name = 'aeroways',
+    mapping = {
+        'aeroway': (
+            'runway',
+            'taxiway',
+    )}
+)
+
+transport_areas = Polygons(
+    name = 'transport_areas',
+    mapping = {
+        'railway': (
+            'station',
+        ),
+        'aeroway': (
+            'aerodome',
+            'terminal',
+            'helipad',
+            'apron',
+        ),
+})
+
+landusages = Polygons(
+    name = 'landusages',
+    fields = (
+        ('z_order', ZOrder([
+            'pedestrian',
+            'footway',
+            'playground',
+            'park',
+            'forest',
+            'cemetery',
+            'farmyard',
+            'farm',
+            'farmland',
+            'wood',
+            'meadow',
+            'grass',
+            'village_green',
+            'recreation_ground',
+            'garden',
+            'sports_centre',
+            'pitch',
+            'common',
+            'allotments',
+            'golf_course',
+            'university',
+            'school',
+            'college',
+            'library',
+            'fuel',
+            'parking',
+            'nature_reserve',
+            'cinema',
+            'theatre',
+            'place_of_worship',
+            'hospital',
+            'scrub',
+            'quarry',
+            'residential',
+            'retail',
+            'commercial',
+            'industrial',
+            'railway',
+            'land',
+        ])),
+    ),
+    mapping = {
+        'landuse': (
+            'park',
+            'forest',
+            'residential',
+            'retail',
+            'commercial',
+            'industrial',
+            'railway',
+            'cemetery',
+            'grass',
+            'farmyard',
+            'farm',
+            'farmland',
+            'wood',
+            'meadow',
+            'village_green',
+            'recreation_ground',
+            'allotments',
+            'quarry',
+        ),
+        'leisure': (
+            'park',
+            'garden',
+            'playground',
+            'golf_course',
+            'sports_centre',
+            'pitch',
+            'stadium',
+            'common',
+            'nature_reserve',
+        ),
+        'natural': (
+            'wood',
+            'land',
+            'scrub',
+        ),
+        'highway': (
+            'pedestrian',
+            'footway',
+        ),
+        'amenity': (
+            'university',
+            'school',
+            'college',
+            'library',
+            'fuel',
+            'parking',
+            'cinema',
+            'theatre',
+            'place_of_worship',
+            'hospital',
+        ),
+})
+
+amenities = Points(
+    name='amenities',
+    mapping = {
+        'amenity': (
+            'university',
+            'school',
+            'library',
+            'fuel',
+            'hospital',
+            'fire_station',
+            'police',
+            'townhall',
+        ),
+})
+
+motorways_gen1 = GeneralizedTable(
+    name = 'motorways_gen1',
+    tolerance = 50.0,
+    origin = motorways,
+)
+
+mainroads_gen1 = GeneralizedTable(
+    name = 'mainroads_gen1',
+    tolerance = 50.0,
+    origin = mainroads,
+)
+
+railways_gen1 = GeneralizedTable(
+    name = 'railways_gen1',
+    tolerance = 50.0,
+    origin = railways,
+)
+
+motorways_gen0 = GeneralizedTable(
+    name = 'motorways_gen0',
+    tolerance = 200.0,
+    origin = motorways_gen1,
+)
+
+mainroads_gen0 = GeneralizedTable(
+    name = 'mainroads_gen0',
+    tolerance = 200.0,
+    origin = mainroads_gen1,
+)
+
+railways_gen0 = GeneralizedTable(
+    name = 'railways_gen0',
+    tolerance = 200.0,
+    origin = railways_gen1,
+)
+
+roads = UnionView(
+    name = 'roads',
+    fields = (
+        ('bridge', 0),
+        ('ref', None),
+        ('tunnel', 0),
+        ('oneway', 0),
+        ('z_order', 0),
+    ),
+    mappings = [motorways, mainroads, minorroads, railways],
+)
+
+roads_gen1 = UnionView(
+    name = 'roads_gen1',
+    fields = (
+        ('bridge', 0),
+        ('ref', None),
+        ('tunnel', 0),
+        ('oneway', 0),
+        ('z_order', 0),
+    ),
+    mappings = [railways_gen1, mainroads_gen1, motorways_gen1],
+)
+
+roads_gen0 = UnionView(
+    name = 'roads_gen0',
+    fields = (
+        ('bridge', 0),
+        ('ref', None),
+        ('tunnel', 0),
+        ('oneway', 0),
+        ('z_order', 0),
+    ),
+    mappings = [railways_gen0, mainroads_gen0, motorways_gen0],
+)
\ No newline at end of file
diff --git a/imposm/geom.py b/imposm/geom.py
new file mode 100644
index 0000000..da823d6
--- /dev/null
+++ b/imposm/geom.py
@@ -0,0 +1,152 @@
+# Copyright 2011 Omniscale (http://omniscale.com)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from shapely.geometry.base import BaseGeometry
+from shapely import geometry
+from shapely import wkt
+
+import logging
+log = logging.getLogger(__name__)
+
+class InvalidGeometryError(Exception):
+    pass
+
+class IncompletePolygonError(Exception):
+    pass
+
+
+TOLERANCE_DEEGREES = 1e-8
+TOLERANCE_METERS = 1e-3
+
+def validate_and_simplify(geom, meter_units=False):
+    orig_geom = geom
+    if not geom.is_valid:
+        tolerance = TOLERANCE_METERS if meter_units else TOLERANCE_DEEGREES
+        geom = geom.simplify(tolerance, False)
+        if not geom.is_valid:
+            raise InvalidGeometryError('geometry is invalid, could not simplify: %s' %
+                                       orig_geom)
+    return geom
+
+
+class GeomBuilder(object):
+    def build(self, osm_elem):
+        # TODO is this method still in use?
+        try:
+            if isinstance(osm_elem.coords, BaseGeometry):
+                return osm_elem.coords
+            geom_wkt = self.to_wkt(osm_elem.coords)
+            if geom_wkt is not None:
+                geom = wkt.loads(geom_wkt)
+        except Exception, ex:
+            raise InvalidGeometryError('unable to build geometry %s: %s %s' %
+                                       (osm_elem.osm_id, ex, osm_elem.coords))
+        if geom_wkt is None or geom is None:
+            # unable to build valid wkt (non closed polygon, etc)
+            raise InvalidGeometryError()
+        return geom    
+    
+    def check_geom_type(self, geom):
+        return
+
+    def build_geom(self, osm_elem):
+        try:
+            if isinstance(osm_elem.coords, BaseGeometry):
+                if osm_elem.coords.is_empty:
+                    raise InvalidGeometryError('empty geometry')
+                self.check_geom_type(osm_elem.coords)
+                return osm_elem.coords
+            geom = self.to_geom(osm_elem.coords)
+        except InvalidGeometryError, ex:
+            raise InvalidGeometryError('unable to build geometry %s: %s %s' %
+                                       (osm_elem.osm_id, ex, osm_elem.coords))
+        if geom is None:
+            # unable to build valid wkt (non closed polygon, etc)
+            raise InvalidGeometryError()
+        return geom    
+
+class PointBuilder(GeomBuilder):
+    def to_wkt(self, data):
+        if len(data) != 2:
+            return None
+        return 'POINT(%f %f)' % data
+    
+    def to_geom(self, data):
+        if len(data) != 2:
+            return None
+        return geometry.Point(*data)
+    
+    def check_geom_type(self, geom):
+        if geom.type != 'Point':
+            raise InvalidGeometryError('expected Point, got %s' % geom.type)
+    
+    def build_checked_geom(self, osm_elem, validate=False):
+        geom = self.build_geom(osm_elem)
+        if not validate or geom.is_valid:
+            return geom
+        else:
+            raise InvalidGeometryError('invalid geometry for %s: %s, %s' %
+                                       (osm_elem.osm_id, geom, osm_elem.coords))
+
+class PolygonBuilder(GeomBuilder):
+    def to_wkt(self, data):
+        if len(data) >= 4 and data[0] == data[-1]:
+            return 'POLYGON((' + ', '.join('%f %f' % p for p in data) + '))'
+        return None
+    
+    def to_geom(self, data):
+        if len(data) >= 4 and data[0] == data[-1]:
+            return geometry.Polygon(data)
+        return None
+    
+    def check_geom_type(self, geom):
+        if geom.type not in ('Polygon', 'MultiPolygon'):
+            raise InvalidGeometryError('expected Polygon or MultiPolygon, got %s' % geom.type)
+    
+    def build_checked_geom(self, osm_elem, validate=False):
+        geom = self.build_geom(osm_elem)
+        if not validate:
+            return geom
+        try:
+            return validate_and_simplify(geom)
+        except InvalidGeometryError:
+            raise InvalidGeometryError('invalid geometry for %s: %s, %s' %
+                                       (osm_elem.osm_id, geom, osm_elem.coords))
+
+class LineStringBuilder(GeomBuilder):
+    def to_wkt(self, data):
+        if len(data) <= 1:
+            return None
+        if len(data) == 2 and data[0] == data[1]:
+            return None
+        return 'LINESTRING(' + ', '.join('%f %f' % p for p in data) + ')'
+
+    def check_geom_type(self, geom):
+        if geom.type != 'LineString':
+            raise InvalidGeometryError('expected LineString, got %s' % geom.type)
+
+    def to_geom(self, data):
+        if len(data) <= 1:
+            return None
+        if len(data) == 2 and data[0] == data[1]:
+            return None
+        return geometry.LineString(data)
+
+    def build_checked_geom(self, osm_elem, validate=False):
+        geom = self.build_geom(osm_elem)
+        if not validate or geom.is_valid:
+            return geom
+        else:
+            raise InvalidGeometryError('invalid geometry for %s: %s, %s' %
+                                       (osm_elem.osm_id, geom, osm_elem.coords))
diff --git a/imposm/mapping.py b/imposm/mapping.py
new file mode 100644
index 0000000..6a7de02
--- /dev/null
+++ b/imposm/mapping.py
@@ -0,0 +1,416 @@
+# -:- encoding: UTF8 -:-
+# Copyright 2011 Omniscale (http://omniscale.com)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import imposm.geom
+
+ANY = '__any__'
+
+__all__ = [
+    'LineStrings',
+    'Polygons',
+    'Points',
+    'Options',
+    'PolygonTable',
+    'ZOrder',
+    'PointTable',
+    'String',
+    'LineStringTable',
+    'Direction',
+    'OneOfInt',
+    'Integer',
+    'WayZOrder',
+    'Bool',
+    'GeneralizedTable',
+    'UnionView',
+]
+
+
+class Mapping(object):
+    table = None
+    fields = ()
+    field_filter = ()
+    classname = None
+    _insert_stmt = None
+    
+    filter_out_names = set((
+        'fixme', 'fix me', 'fix-me!',
+        'kein name', 'kein',
+        'unbenannt', 'unbekannt',
+        'noch unbekannt', 'noch ohne namen',
+        'noname', 'unnamed', 'namenlos', 'no_name', 'no name',
+    ))
+    
+    def __init__(self, name, mapping, fields=None, field_filter=None):
+        self.name = name
+        self.mapping = mapping
+        if fields:
+            self.fields = fields
+        if field_filter:
+            self.field_filter = field_filter
+        
+    @property
+    def insert_stmt(self):
+        if not self._insert_stmt:
+            self._insert_stmt = self.table('osm_' + self.name, self).insert_stmt
+        return self._insert_stmt
+    
+    def name_filter(self, osm_elem):
+        if osm_elem.name and osm_elem.name.lower() in self.filter_out_names:
+            osm_elem.name = ''
+    
+    def extra_field_names(self):
+        return [n for n,_ in self.fields] + [n for n,_ in self.field_filter]
+    
+    def build_geom(self, osm_elem):
+        try:
+            geom = self.geom_builder.build_checked_geom(osm_elem)
+            osm_elem.geom = geom
+        except imposm.geom.InvalidGeometryError, ex:
+            raise DropElem('invalid geometry: %s' % (ex, ))
+    
+    def field_values(self, osm_elem):
+        return [t.value(osm_elem.tags.get(n), osm_elem) for n, t in self.fields]
+    
+    def filter(self, osm_elem):
+        [t.filter(osm_elem.tags.get(n), osm_elem) for n, t in self.field_filter]
+    
+    def __repr__(self):
+        return '<Mapping for %s>' % self.name
+
+
+class TagMapper(object):
+    def __init__(self, mappings):
+        self.mappings = mappings
+        self._init_map()
+
+    def _init_map(self):
+        self.points = {}
+        self.lines = {}
+        self.polygons = {}
+        self.nodes_tags = set()
+        self.ways_tags = set()
+
+        for mapping in self.mappings:
+            if mapping.table is PointTable:
+                tags = self.nodes_tags
+                add_to = self.points
+            elif mapping.table is LineStringTable:
+                tags = self.ways_tags
+                add_to = self.lines
+            elif mapping.table is PolygonTable:
+                tags = self.ways_tags
+                add_to = self.polygons
+
+            tags.update(mapping.extra_field_names())
+
+            for tag, types in mapping.mapping.iteritems():
+                add_to.setdefault(tag, {})
+                tags.add(tag)
+                for type in types:
+                    add_to[tag].setdefault(type, [])
+                    add_to[tag][type].append(mapping)
+
+    def for_nodes(self, tags):
+        return self._mapping_for_tags(self.points, tags)
+
+    def for_ways(self, tags):
+        return (self._mapping_for_tags(self.lines, tags) + 
+                self._mapping_for_tags(self.polygons, tags))
+
+    def _tag_filter(self, filter_tags):
+        filter_tags.add('name')
+        def filter(tags):
+            for k in tags.keys():
+                if k not in filter_tags:
+                    del tags[k]
+            if 'name' in tags and len(tags) == 1:
+                del tags['name']
+        return filter
+
+    def tag_filter_for_nodes(self):
+        return self._tag_filter(self.nodes_tags)
+
+    def tag_filter_for_ways(self):
+        return self._tag_filter(self.ways_tags)
+
+    def tag_filter_for_relations(self):
+        relation_tags = set(self.ways_tags)
+        relation_tags.add('type')  # for type=multipolygon
+        _rel_filter = self._tag_filter(relation_tags)
+        def rel_filter(tags):
+            if tags.get('type') != 'multipolygon':
+                tags.clear()
+                return
+            _rel_filter(tags)
+        return rel_filter
+
+    def _mapping_for_tags(self, tag_map, tags):
+        result = []
+        mapping_set = set()
+        def add_mappings(mappings, tag_name, tag_value):
+            new_mappings = []
+            for proc in mappings:
+                if proc not in mapping_set:
+                    mapping_set.add(proc)
+                    new_mappings.append(proc)
+            result.append(((tag_name, tag_value), tuple(new_mappings)))
+
+        for tag_name in tag_map:
+            if tag_name in tags:
+                tag_value = tags[tag_name]
+                if tag_value in tag_map[tag_name]:
+                    add_mappings(tag_map[tag_name][tag_value], tag_name, tag_value)
+                if ANY in tag_map[tag_name]:
+                    add_mappings(tag_map[tag_name][ANY], tag_name, tag_value)
+
+        return result
+
+
+# marker classes
+class PointTable(object):
+    pass
+class LineStringTable(object):
+    pass
+class PolygonTable(object):
+    pass
+
+class Points(Mapping):
+    """
+    Table class for point features.
+    
+    :PostGIS datatype: POINT (for multi-polygon support)
+    """
+    table = PointTable
+    geom_builder = imposm.geom.PointBuilder()
+    geom_type = 'POINT'
+
+class LineStrings(Mapping):
+    """
+    Table class for line string features.
+    
+    :PostGIS datatype: LINESTRING (for multi-polygon support)
+    """
+    table = LineStringTable
+    geom_builder = imposm.geom.LineStringBuilder()
+    geom_type = 'LINESTRING'
+
+class Polygons(Mapping):
+    """
+    Table class for polygon features.
+    
+    :PostGIS datatype: GEOMETRY (for multi-polygon support)
+    """
+    table = PolygonTable
+    geom_builder = imposm.geom.PolygonBuilder()
+    geom_type = 'GEOMETRY' # for multipolygon support
+
+
+class GeneralizedTable(object):
+    def __init__(self, name, tolerance, origin):
+        self.name = name
+        self.tolerance = tolerance
+        self.origin = origin
+        self.classname = origin.name
+        self.fields = self.origin.fields
+
+class UnionView(object):
+    def __init__(self, name, mappings, fields):
+        self.name = name
+        self.mappings = mappings
+        self.fields = fields
+
+class DropElem(Exception):
+    pass
+
+
+class FieldType(object):
+    def value(self, val, osm_elem):
+        return val
+
+class String(FieldType):
+    """
+    Field for string values.
+    
+    :PostgreSQL datatype: VARCHAR(255)
+    """
+    column_type = "VARCHAR(255)"
+
+class Bool(FieldType):
+    """
+    Field for boolean values.
+    Converts false, no, 0 to False and true, yes, 1 to True.
+    
+    :PostgreSQL datatype: SMALLINT
+    """
+    # there was a reason this is not BOOL
+    # something didn't supported it, cascadenik? don't remember
+    column_type = "SMALLINT"
+
+    aliases = {
+        True: set(['false', 'no', '0', 'undefined']),
+        False: set(['true', 'yes', '1', 'undefined']),
+    }
+
+    def __init__(self, default=True, neg_aliases=None):
+        self.default = default
+        self.neg_aliases = neg_aliases or self.aliases[default]
+
+    def value(self, val, osm_elem):
+        if val is None or val.strip().lower() in self.neg_aliases:
+            return 0  # not self.default
+        return 1  # self.default
+
+    def filter(self, val, osm_elem):
+        if self.value(val, osm_elem):
+            raise DropElem
+
+class Direction(FieldType):
+    """
+    Field type for one-way directions.
+    Converts `yes`, `true` and `1` to ``1`` for one ways in the direction of
+    the way, `-1` to ``-1`` for one ways against the direction of the way and
+    ``0`` for all other values.
+    
+    :PostgreSQL datatype: SMALLINT
+    """
+    column_type = "SMALLINT"
+    def value(self, value, osm_elem):
+        if value:
+            value = value.strip().lower()
+            if value in ('yes', 'true', '1'):
+                return 1
+            if value == '-1':
+                return -1
+        return 0
+
+class OneOfInt(FieldType):
+    """
+    Field type for integer values.
+    Converts values to integers, drops element if is not included in
+    ``values``.
+    
+    :PostgreSQL datatype: SMALLINT
+    """
+    column_type = "SMALLINT"
+
+    def __init__(self, values):
+        self.values = set(values)
+
+    def value(self, value, osm_elem):
+        if value in self.values:
+            return int(value)
+        raise DropElem
+
+class Integer(FieldType):
+    """
+    Field type for integer values.
+    Converts values to integers, defaults to ``NULL``.
+    
+    :PostgreSQL datatype: INTEGER
+    """
+    column_type = "INTEGER"
+
+    def value(self, value, osm_elem):
+        try:
+            return int(value)
+        except:
+            return None
+
+class ZOrder(FieldType):
+    """
+    Field type for z-ordering based on the feature type.
+    
+    :param types: list of mapped feature types,
+        from highest to lowest ranking
+    :PostgreSQL datatype: SMALLINT
+    """
+    
+    column_type = "SMALLINT"
+
+    def __init__(self, types):
+        self.rank = {}
+        for i, t in enumerate(types[::-1]):
+            self.rank[t] = i
+
+    def value(self, val, osm_elem):
+        return self.rank.get(osm_elem.type, 0)
+
+
+class WayZOrder(FieldType):
+    """
+    Field type for z-ordered based on highway types.
+    
+    Ordering based on the osm2pgsql z-ordering:
+    From ``roads`` = 3 to ``motorways`` = 9, ``railway`` = 7 and unknown = 0.
+    Ordering changes with ``tunnels`` by -10, ``bridges`` by +10 and
+    ``layer`` by 10 * ``layer``.
+    
+    :PostgreSQL datatype: SMALLINT
+    """
+
+    column_type = "SMALLINT"
+
+    rank = {
+     'minor': 3,
+     'road': 3,
+     'unclassified': 3,
+     'residential': 3,
+     'tertiary_link': 3,
+     'tertiary': 4,
+     'secondary_link': 3,
+     'secondary': 5,
+     'primary_link': 3,
+     'primary': 6,
+     'trunk_link': 3,
+     'trunk': 8,
+     'motorway_link': 3,
+     'motorway': 9,
+    }
+
+    brunnel_bool = Bool()
+
+    def value(self, val, osm_elem):
+        tags = osm_elem.tags
+        z_order = 0
+        l = self.layer(tags)
+        z_order += l * 10
+        r = self.rank.get(osm_elem.type, 0)
+        if not r:
+            r = 7 if 'railway' in tags else 0
+        z_order += r
+
+        if self.brunnel_bool.value(tags.get('tunnel'), {}):
+            z_order -= 10
+
+        if self.brunnel_bool.value(tags.get('bridge'), {}):
+            z_order += 10
+
+        return z_order
+
+    def layer(self, tags):
+        l = tags.get('layer', 0)
+        try:
+            return int(l)
+        except ValueError:
+            return 0
+
+class Options(dict):
+    def __setattr__(self, name, value):
+        self[name] = value
+    def __getattr__(self, name):
+        try:
+            return self[name]
+        except KeyError:
+            raise AttributeError('%s not in %r' % (name, self))
diff --git a/imposm/merge.py b/imposm/merge.py
new file mode 100644
index 0000000..3e0ce74
--- /dev/null
+++ b/imposm/merge.py
@@ -0,0 +1,93 @@
+# Copyright 2011 Omniscale (http://omniscale.com)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import difflib
+
+def merge(a, b):
+    sqm = difflib.SequenceMatcher(None, a, b)
+    matching_blocks = sqm.get_matching_blocks()
+    matching_blocks.pop(-1)
+    
+    if not matching_blocks:
+        return None
+    
+    a_idx = b_idx = 0
+    result = []
+
+    for block in matching_blocks:
+        if a_idx < block[0]:
+            result.extend(a[a_idx:block[0]])
+        if b_idx < block[1]:
+            result.extend(b[b_idx:block[1]])
+        a_idx = block[0]+block[-1]
+        b_idx = block[1]+block[-1]
+        result.extend(a[block[0]:block[0]+block[-1]])
+
+    if a_idx < len(a):
+        result.extend(a[a_idx:])
+    if b_idx < len(b):
+        result.extend(b[b_idx:])
+        
+    return result
+
+
+def multimerge(candidates, merge_func=merge):
+    candidates = list(candidates)
+    while len(candidates) > 1:
+        a, b, res = multimerge_(candidates, merge_func)
+        if res is None:
+            return candidates
+        candidates.remove(b)
+        if a is not res:
+            candidates.remove(a)
+            candidates.append(res)
+        # else: in place merge
+    return candidates[0]
+
+def multimerge_(candidates, merge_func):
+    for a, b in permutations(candidates, 2):
+        res = merge_func(a, b)
+        if res is not None:
+            return a, b, res
+    return None, None, None
+
+
+try:
+    from itertools import permutations
+    permutations # prevent warning
+except ImportError:
+    def permutations(iterable, r=None):
+        # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
+        # permutations(range(3)) --> 012 021 102 120 201 210
+        pool = tuple(iterable)
+        n = len(pool)
+        r = n if r is None else r
+        if r > n:
+            return
+        indices = range(n)
+        cycles = range(n, n-r, -1)
+        yield tuple(pool[i] for i in indices[:r])
+        while n:
+            for i in reversed(range(r)):
+                cycles[i] -= 1
+                if cycles[i] == 0:
+                    indices[i:] = indices[i+1:] + indices[i:i+1]
+                    cycles[i] = n - i
+                else:
+                    j = cycles[i]
+                    indices[i], indices[-j] = indices[-j], indices[i]
+                    yield tuple(pool[i] for i in indices[:r])
+                    break
+            else:
+                return
\ No newline at end of file
diff --git a/imposm/multipolygon.py b/imposm/multipolygon.py
new file mode 100644
index 0000000..e26294a
--- /dev/null
+++ b/imposm/multipolygon.py
@@ -0,0 +1,306 @@
+# Copyright 2011 Omniscale (http://omniscale.com)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import division
+import os
+import time
+
+from imposm.geom import (
+    PolygonBuilder,
+    LineStringBuilder,
+    InvalidGeometryError,
+    IncompletePolygonError,
+)
+from imposm.merge import merge
+
+import imposm.base
+import imposm.geom
+import shapely.geometry
+import shapely.ops
+import shapely.geos
+import shapely.prepared
+
+
+import logging
+log = logging.getLogger(__name__)
+
+IMPOSM_MULTIPOLYGON_REPORT = float(os.environ.get('IMPOSM_MULTIPOLYGON_REPORT', 60))
+IMPOSM_MULTIPOLYGON_MAX_RING = int(os.environ.get('IMPOSM_MULTIPOLYGON_MAX_RING', 1000))
+
+class RelationBuilder(object):
+    def __init__(self, relation, ways_cache, coords_cache):
+        self.relation = relation
+        self.polygon_builder = PolygonBuilder()
+        self.linestring_builder = LineStringBuilder()
+        self.ways_cache = ways_cache
+        self.coords_cache = coords_cache
+    
+    def fetch_ways(self):
+        ways = []
+        for member in self.relation.members:
+            # skip label nodes, relations of relations, etc
+            if member[1] != 'way': continue
+            way = self.ways_cache.get(member[0])
+            if way is None:
+                log.debug('way not found %s:%s', self.relation.osm_id, member[0])
+                raise IncompletePolygonError('way not found %s:%s' % (self.relation.osm_id, member[0]))
+            if way.partial_refs:
+                log.warn('multiple linestrings in way %s (relation %s)',
+                       member[0], self.relation.osm_id)
+                raise IncompletePolygonError()
+            
+            way.coords = self.fetch_way_coords(way)
+            ways.append(way)
+        return ways
+    
+    def build_rings(self, ways):
+        rings = []
+        incomplete_rings = []
+        
+        for ring in (Ring(w) for w in ways):
+            if ring.is_closed():
+                ring.geom = self.polygon_builder.build_checked_geom(ring, validate=True)
+                rings.append(ring)
+            else:
+                incomplete_rings.append(ring)
+        
+        merged_rings = self.build_ring_from_incomplete(incomplete_rings)
+        
+        return rings + merged_rings
+        
+    def build_ring_from_incomplete(self, incomplete_rings):
+        
+        rings = merge_rings(incomplete_rings)
+        for ring in rings:
+            if not ring.is_closed():
+                raise InvalidGeometryError('linestrings from relation %s do not form a ring' %
+                        self.relation.osm_id)
+            
+            ring.geom = self.polygon_builder.build_checked_geom(ring, validate=True)
+        return rings
+    
+    def fetch_way_coords(self, way):
+        """
+        Fetch all coordinates of way.refs.
+        """
+        coords = self.coords_cache.get_coords(way.refs)
+        if coords is None:
+            log.debug('missing coord from way %s in relation %s',
+                way.osm_id, self.relation.osm_id)
+            raise IncompletePolygonError()
+        
+        return coords
+    
+    def build_relation_geometry(self, rings):
+        """
+        Build relation geometry from rings.
+        """
+        rings.sort(key=lambda x: x.geom.area, reverse=True)
+        
+        # add/subtract all rings from largest
+        polygon = rings.pop(0)
+        polygon.inserted = True
+        rel_tags = relation_tags(self.relation.tags, polygon.tags)
+        
+        geom = polygon.geom
+        for r in rings:
+            if geom.contains(r.geom):
+                # inside -> hole -> subtract
+                geom = geom.difference(r.geom)
+                if tags_same_or_empty(rel_tags, r.tags):
+                    r.inserted = True
+                else:
+                    r.inserted = False
+            else:
+                # outside or overlap -> merge(union) to multipolygon or to polygon
+                try:
+                    geom = geom.union(r.geom)
+                except shapely.geos.TopologicalError:
+                    raise InvalidGeometryError('multipolygon relation (%s) result is invalid'
+                                               ' (topological error)' % self.relation.osm_id)
+                r.inserted = True
+        if not geom.is_valid:
+            raise InvalidGeometryError('multipolygon relation (%s) result is invalid' %
+                                       self.relation.osm_id)
+        
+        self.relation.geom = geom
+        self.relation.tags = rel_tags
+        all_ways = polygon.ways
+        for r in rings:
+            all_ways.extend(r.ways)
+        self.relation.ways = all_ways
+    
+    def mark_inserted_ways(self, inserted_ways_queue):
+        for w in self.relation.ways:
+            if w.inserted:
+                inserted_ways_queue.put(w.osm_id)
+    
+    def build(self):
+        try:
+            time_start = time.time()
+            ways = self.fetch_ways()
+            time_ways = time.time() - time_start
+            if not ways:
+                raise IncompletePolygonError('no ways found')
+            time_start = time.time()
+            rings = self.build_rings(ways)
+            time_rings = time.time() - time_start
+
+            if len(rings) > IMPOSM_MULTIPOLYGON_MAX_RING:
+                log.warn('skipping relation %d with %d ways (%.1fms) and %d rings (%.1fms): too many rings',
+                    self.relation.osm_id, len(ways), time_ways*1000, len(rings), time_rings*1000)
+            
+            time_start = time.time()
+            self.build_relation_geometry(rings)
+            time_relations = time.time() - time_start
+            
+            if time_ways + time_rings + time_relations > IMPOSM_MULTIPOLYGON_REPORT:
+                log.warn('building relation %d with %d ways (%.1fms) and %d rings (%.1fms) took %.1fms',
+                    self.relation.osm_id, len(ways), time_ways*1000, len(rings), time_rings*1000, time_relations*1000)
+        except InvalidGeometryError, ex:
+            log.debug(ex)
+            raise IncompletePolygonError(ex)
+        except IncompletePolygonError:
+            raise
+        except Exception, ex:
+            log.warn('error while building multipolygon:')
+            log.exception(ex)
+            raise IncompletePolygonError(ex)
+
+def relation_tags(rel_tags, way_tags):
+    result = dict(rel_tags)
+    
+    if 'type' in result: del result['type']
+    if 'name' in result: del result['name']
+    
+    if not result:
+        # use way_tags
+        result.update(way_tags)
+    else:
+        if 'name' in rel_tags:
+            # put back name
+            result['name'] = rel_tags['name']
+        
+    return result
+
+def tags_differ(a, b):
+    a_ = dict(a)
+    a_.pop('name', None)
+    b_ = dict(b)
+    b_.pop('name', None)
+    return a_ != b_
+
+def tags_same_or_empty(a, b):
+    return (
+        not b or
+        not tags_differ(a, b)
+    )
+
+def merge_rings(rings):
+    """
+    Merge rings at the endpoints.
+    """
+    endpoints = {}
+    for ring in rings:
+        left = ring.refs[0]
+        right = ring.refs[-1]
+        orig_ring = None
+        insert_endpoint = None
+        if left in endpoints:
+            orig_ring = endpoints.pop(left)
+            if left == orig_ring.refs[-1]:
+                orig_ring.refs = orig_ring.refs + ring.refs[1:]
+                orig_ring.coords = orig_ring.coords + ring.coords[1:]
+            else:
+                orig_ring.refs = orig_ring.refs[::-1] + ring.refs[1:]
+                orig_ring.coords = orig_ring.coords[::-1] + ring.coords[1:]
+            orig_ring.ways.extend(ring.ways)
+            orig_ring.tags.update(ring.tags)
+            if right in endpoints and endpoints[right] is not orig_ring:
+                # close gap
+                ring = endpoints.pop(right)
+                if right == ring.refs[0]:
+                    orig_ring.refs = orig_ring.refs + ring.refs[1:]
+                    orig_ring.coords = orig_ring.coords + ring.coords[1:]
+                else:
+                    orig_ring.refs = orig_ring.refs[:-1] + ring.refs[::-1]
+                    orig_ring.coords = orig_ring.coords[:-1] + ring.coords[::-1]
+                orig_ring.ways.extend(ring.ways)
+                orig_ring.tags.update(ring.tags)
+                right  = orig_ring.refs[-1]
+                endpoints[right] = orig_ring
+            else:
+                endpoints[right] = orig_ring
+        elif right in endpoints:
+            orig_ring = endpoints.pop(right)
+            if right == orig_ring.refs[0]:
+                orig_ring.refs = ring.refs[:-1] + orig_ring.refs
+                orig_ring.coords = ring.coords[:-1] + orig_ring.coords
+            else:
+                orig_ring.refs = orig_ring.refs[:-1] + ring.refs[::-1]
+                orig_ring.coords = orig_ring.coords[:-1] + ring.coords[::-1]
+            orig_ring.ways.extend(ring.ways)
+            orig_ring.tags.update(ring.tags)
+            endpoints[left] = orig_ring
+        else:
+            endpoints[left] = ring
+            endpoints[right] = ring
+    return list(set(endpoints.values()))
+
+class Ring(object):
+    """
+    Represents a ring (i.e. polygon without holes) build from one
+    or more ways. Stores references to the building ways.
+    """
+    def __init__(self, way):
+        self.ways = [way]
+        self.osm_id = way.osm_id
+        self.refs = way.refs
+        self.coords = way.coords
+        self.tags = dict(way.tags)
+        self._inserted = way
+    
+    def __repr__(self):
+        return 'Ring(%r, %r, %r)' % (self.osm_id, self.tags, self.ways)
+    
+    def merge(self, ring, without_refs=False):
+        """
+        Try to merge `ring.refs` with this ring.
+        Returns `self` on success, else `None`.
+        """
+        if without_refs:
+            result = None
+        else:
+            result = merge(self.refs, ring.refs)
+            if result is None:
+                return None
+        
+        self.ways.extend(ring.ways)
+        self.refs = [result]
+        self.tags.update(ring.tags)
+        return self
+    
+    def is_closed(self):
+        return len(self.refs) >= 4 and self.refs[0] == self.refs[-1]
+    
+    def _set_inserted(self, value):
+        for w in self.ways:
+            w.inserted = value
+        self._inserted = value
+    
+    def _get_inserted(self):
+        return self._inserted
+    
+    # propagate inserted to ways
+    inserted = property(_get_inserted, _set_inserted)
diff --git a/imposm/psqldb.py b/imposm/psqldb.py
new file mode 100644
index 0000000..5c7359c
--- /dev/null
+++ b/imposm/psqldb.py
@@ -0,0 +1,100 @@
+# Copyright 2011 Omniscale (http://omniscale.com)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import optparse
+import string
+from os.path import join, dirname, exists
+
+db_create_template = """
+# run this as postgres user, eg:
+# imposm-pgsql > create_db.sh; sudo su postgres; sh ./create_db.sh
+set -xe
+createuser --no-superuser --no-createrole --createdb ${user}
+createdb -E UTF8 -O ${user} ${dbname}
+createlang plpgsql ${dbname}
+psql -d ${dbname} -f ${postgis_sql}
+psql -d ${dbname} -f ${spatial_ref_sys_sql}
+psql -d ${dbname} -f ${epsg900913_sql}
+echo "ALTER TABLE geometry_columns OWNER TO ${user}; ALTER TABLE spatial_ref_sys OWNER TO ${user};" | psql -d ${dbname}
+echo "ALTER USER ${user} WITH PASSWORD '${password}';" |psql -d ${dbname}
+echo "host\t${dbname}\t${user}\t127.0.0.1/32\tmd5" >> ${pg_hba}
+set +x
+echo "Done. Don't forget to restart postgresql!"
+""".strip()
+
+def find_sql_files(version, mapping):
+    
+    pg_hba = '/path/to/pg_hba.conf \t\t# <- CHANGE THIS PATH'
+    postgis_sql = '/path/to/postgis.sql \t\t# <- CHANGE THIS PATH'
+    spatial_ref_sys_sql = '/path/to/spatial_ref_sys.sql \t# <- CHANGE THIS PATH' 
+    
+    if version in ('8.3', 'auto'):
+        p = '/usr/share/postgresql-8.3-postgis/lwpostgis.sql'
+        if exists(p):
+            postgis_sql = p
+        p = '/usr/share/postgresql-8.3-postgis/spatial_ref_sys.sql'
+        if exists(p):
+            spatial_ref_sys = p
+        p = '/etc/postgresql/8.3/main/pg_hba.conf'
+        if exists(p):
+            pg_hba = p
+    
+    if version in ('8.4', 'auto'):
+        p = '/usr/share/postgresql/8.4/contrib/postgis.sql'
+        if exists(p):
+            postgis_sql = p
+        p = '/usr/share/postgresql/8.4/contrib/postgis-1.5/postgis.sql'
+        if exists(p):
+            postgis_sql = p
+        p = '/usr/share/postgresql/8.4/contrib/spatial_ref_sys.sql'
+        if exists(p):
+            spatial_ref_sys_sql = p
+        p = '/usr/share/postgresql/8.4/contrib/postgis-1.5/spatial_ref_sys.sql'
+        if exists(p):
+            spatial_ref_sys_sql = p
+        p = '/etc/postgresql/8.4/main/pg_hba.conf'
+        if exists(p):
+            pg_hba = p
+    
+    mapping['postgis_sql'] = postgis_sql
+    mapping['spatial_ref_sys_sql'] = spatial_ref_sys_sql
+    mapping['pg_hba'] = pg_hba
+
+def main():
+    usage = '%prog [options]'
+    desc = 'Outputs shell commands to create a PostGIS database.'
+    parser = optparse.OptionParser(usage=usage, description=desc)
+    parser.add_option('--database', dest='dbname', metavar='osm', default='osm')
+    parser.add_option('--user', dest='user', metavar='osm', default='osm')
+    parser.add_option('--password', dest='password', metavar='osm', default='osm')
+    parser.add_option('--pg-version', dest='pg_version', metavar='8.3|8.4|auto', default='auto')
+    
+    (options, args) = parser.parse_args()
+
+    mapping = {
+        'user': options.user,
+        'dbname': options.dbname,
+        'password': options.password,
+    }
+    
+    mapping['epsg900913_sql'] = join(dirname(__file__), '900913.sql')
+    find_sql_files(options.pg_version, mapping)
+    
+    template = string.Template(db_create_template)
+    print template.substitute(mapping)
+
+
+
+if __name__ == '__main__':
+    main()
diff --git a/imposm/reader.py b/imposm/reader.py
new file mode 100644
index 0000000..9768571
--- /dev/null
+++ b/imposm/reader.py
@@ -0,0 +1,142 @@
+# Copyright 2011 Omniscale (http://omniscale.com)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from functools import partial
+from multiprocessing import Process, JoinableQueue
+
+from imposm.parser import OSMParser
+from imposm.util import ParserProgress, setproctitle
+
+class ImposmReader(object):
+    def __init__(self, mapping, cache, pool_size=2, merge=False, logger=None):
+        self.pool_size = pool_size
+        self.mapper = mapping
+        self.merge = merge
+        self.cache = cache
+        self.reader = None
+        self.logger = logger
+        self.estimated_coords = 0
+
+    def read(self, filename):
+        nodes_queue = JoinableQueue(128)
+        coords_queue = JoinableQueue(512)
+        ways_queue = JoinableQueue(128)
+        relations_queue = JoinableQueue(128)
+        
+        log_proc = ParserProgress()
+        log_proc.start()
+        
+        marshal = True
+        if self.merge:
+            # merging needs access to unmarshaled data
+            marshal = False
+        
+        estimates = {
+            'coords': self.estimated_coords,
+            'nodes': self.estimated_coords//50,
+            'ways': self.estimated_coords//7,
+            'relations': self.estimated_coords//1000,
+        }
+        
+        coords_writer = CacheWriterProcess(coords_queue, self.cache.coords_cache,
+            estimates['coords'], log=partial(log_proc.log, 'coords'),
+            marshaled_data=marshal)
+        coords_writer.start()
+
+        nodes_writer = CacheWriterProcess(nodes_queue, self.cache.nodes_cache,
+            estimates['nodes'], log=partial(log_proc.log, 'nodes'),
+            marshaled_data=marshal)
+        nodes_writer.start()
+
+
+        ways_writer = CacheWriterProcess(ways_queue, self.cache.ways_cache,
+            estimates['ways'], merge=self.merge, log=partial(log_proc.log, 'ways'),
+            marshaled_data=marshal)
+        ways_writer.start()
+        
+        relations_writer = CacheWriterProcess(relations_queue, self.cache.relations_cache,
+            estimates['relations'], merge=self.merge, log=partial(log_proc.log, 'relations'),
+            marshaled_data=marshal)
+        relations_writer.start()
+        
+        log_proc.message('coords: %dk nodes: %dk ways: %dk relations: %dk (estimated)' % (
+            estimates['coords']/1000, estimates['nodes']/1000, estimates['ways']/1000,
+            estimates['relations']/1000)
+        )
+        
+        # keep one CPU free for writer proc on hosts with 4 or more CPUs
+        pool_size = self.pool_size if self.pool_size < 4 else self.pool_size - 1
+        
+        parser = OSMParser(pool_size, nodes_callback=nodes_queue.put, coords_callback=coords_queue.put,
+            ways_callback=ways_queue.put, relations_callback=relations_queue.put, marshal_elem_data=marshal)
+
+        parser.nodes_tag_filter = self.mapper.tag_filter_for_nodes()
+        parser.ways_tag_filter = self.mapper.tag_filter_for_ways()
+        parser.relations_tag_filter = self.mapper.tag_filter_for_relations()
+        
+        parser.parse(filename)
+
+        coords_queue.put(None)
+        nodes_queue.put(None)
+        ways_queue.put(None)
+        relations_queue.put(None)
+        coords_writer.join()
+        nodes_writer.join()
+        ways_writer.join()
+        relations_writer.join()
+        log_proc.stop()
+        log_proc.join()
+
+
+class CacheWriterProcess(Process):
+    def __init__(self, queue, cache, estimated_records=None, merge=False, log=None,
+        marshaled_data=False):
+        Process.__init__(self)
+        self.daemon = True
+        setproctitle('imposm writer')
+        self.queue = queue
+        self.cache = cache
+        self.merge = merge
+        self.log = log
+        self.marshaled_data = marshaled_data
+        self.estimated_records = estimated_records
+    
+    def run(self):
+        # print 'creating %s (%d)' % (self.filename, self.estimated_records or 0)
+        cache = self.cache(mode='w', estimated_records=self.estimated_records)
+        if self.marshaled_data:
+            cache_put = cache.put_marshaled
+        else:
+            cache_put = cache.put
+        while True:
+            data = self.queue.get()
+            if data is None: 
+                self.queue.task_done()
+                break
+            if self.merge:
+                for d in data:
+                    if d[0] in cache:
+                        elem = cache.get(d[0])
+                        elem.merge(*d[1:])
+                        d = elem.to_tuple()
+                    cache_put(*d)
+            else:
+                for d in data:
+                    cache_put(*d)
+            if self.log:
+                self.log(len(data))
+            self.queue.task_done()
+        cache.close()
+
+
diff --git a/imposm/test/__init__.py b/imposm/test/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/imposm/test/test_cache.py b/imposm/test/test_cache.py
new file mode 100644
index 0000000..02a3e6e
--- /dev/null
+++ b/imposm/test/test_cache.py
@@ -0,0 +1,93 @@
+# Copyright 2011 Omniscale (http://omniscale.com)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import tempfile
+from imposm.cache.tc import NodeDB, CoordDB
+
+from nose.tools import eq_, assert_almost_equal
+
+
+class TestNodeDB(object):
+    def setup(self):
+        fd_, self.fname = tempfile.mkstemp('.db')
+        self.db = NodeDB(self.fname)
+    
+    def test_insert(self):
+        assert self.db.put(1000, {'foo': 2}, (123, 456))
+        
+        nd = self.db.get(1000)
+        eq_(nd.osm_id, 1000)
+        eq_(nd.tags, {'foo': 2})
+        eq_(nd.coord, (123, 456))
+    
+    def test_read_only(self):
+        assert self.db.put(1000, {'foo': 2}, (123, 456))
+        self.db.close()
+        self.db = NodeDB(self.fname, 'r')
+        
+        nd = self.db.get(1000)
+        eq_(nd.osm_id, 1000)
+        eq_(nd.tags, {'foo': 2})
+        eq_(nd.coord, (123, 456))
+        
+        assert not self.db.put(1001, {'foo': 2}, (123, 456))
+        assert not self.db.get(1001)
+
+    def test_iter(self):
+        assert self.db.put(1000, {'foo': 2}, (123, 456))
+        
+        nds = list(self.db)
+        eq_(len(nds), 1)
+        
+        nd = nds[0]
+        eq_(nd.osm_id, 1000)
+        eq_(nd.tags, {'foo': 2})
+        eq_(nd.coord, (123, 456))
+        
+class TestCoordDB(object):
+    def setup(self):
+        fd_, self.fname = tempfile.mkstemp('.db')
+        self.db = CoordDB(self.fname)
+    
+    def test_insert(self):
+        assert self.db.put(1000, 123, 179.123456789)
+        
+        pos = self.db.get(1000)
+        assert_almost_equal(pos[0], 123.0, 7)
+        assert_almost_equal(pos[1], 179.123456789, 7)
+    
+    def test_read_only(self):
+        assert self.db.put(1000, 123, 456)
+        self.db.close()
+        self.db = CoordDB(self.fname, 'r')
+        
+        pos = self.db.get(1000)
+        assert_almost_equal(pos[0], 123.0, 7)
+        assert_almost_equal(pos[1], 456.0, 7)
+        
+        assert not self.db.put(1001, 123, 456)
+        assert not self.db.get(1001)
+
+    def test_iter(self):
+        assert self.db.put(1000, 123, 456)
+        
+        coords = list(self.db)
+        eq_(len(coords), 1)
+        
+        osm_id, pos = coords[0]
+        
+        eq_(osm_id, 1000)
+        assert_almost_equal(pos[0], 123.0, 7)
+        assert_almost_equal(pos[1], 456.0, 7)
+        
\ No newline at end of file
diff --git a/imposm/test/test_multipolygon.py b/imposm/test/test_multipolygon.py
new file mode 100644
index 0000000..3463ffc
--- /dev/null
+++ b/imposm/test/test_multipolygon.py
@@ -0,0 +1,127 @@
+# Copyright 2011 Omniscale (http://omniscale.com)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from imposm.base import Relation, Way
+from imposm.multipolygon import RelationBuilder, Ring, merge_rings
+
+from nose.tools import eq_
+
+def test_simple_polygon_w_hole():
+    w1 = Way(1, {}, [1, 2, 3, 4, 1])
+    w1.coords = [(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)]
+    w2 = Way(2, {}, [5, 6, 7, 8, 5])
+    w2.coords = [(2, 2), (8, 2), (8, 8), (2, 8), (2, 2)]
+    
+    r = Relation(1, {}, [(1, 'way', 'outer'), (2, 'way', 'inner')])
+    builder = RelationBuilder(r, None, None)
+    rings = builder.build_rings([w1, w2])
+    eq_(len(rings), 2)
+    eq_(rings[0].geom.area, 100)
+    eq_(rings[1].geom.area, 36)
+    
+    builder.build_relation_geometry(rings)
+    
+    eq_(r.geom.area, 100-36)
+
+def test_simple_polygon_from_two_lines():
+    w1 = Way(1, {}, [1, 2, 3])
+    w1.coords = [(0, 0), (10, 0), (10, 10)]
+    w2 = Way(2, {}, [3, 4, 1])
+    w2.coords = [(10, 10), (0, 10), (0, 0)]
+    
+    r = Relation(1, {}, [(1, 'way', 'outer'), (2, 'way', 'inner')])
+    builder = RelationBuilder(r, None, None)
+    rings = builder.build_rings([w1, w2])
+    eq_(len(rings), 1)
+    eq_(rings[0].geom.area, 100)
+    
+    builder.build_relation_geometry(rings)
+    
+    eq_(r.geom.area, 100)
+
+
+def test_merge_rings():
+    w1 = Way(1, {}, [1, 2, 3])
+    w1.coords = [(0, 0), (10, 0), (10, 10)]
+    r1 = Ring(w1)
+    w2 = Way(2, {}, [3, 4, 1])
+    w2.coords = [(10, 10), (0, 10), (0, 0)]
+    r2 = Ring(w2)
+    
+    rings = merge_rings([r1, r2])
+    eq_(len(rings), 1)
+    r = rings[0]
+    eq_(r.is_closed(), True)
+    # eq_(r.ways, [w1, w2])
+
+def test_merge_rings_reverse_endpoint():
+    w1 = Way(1, {'name': 'foo'}, [1, 2, 3, 4])
+    w1.coords = []
+    r1 = Ring(w1)
+    w2 = Way(2, {'building': 'true'}, [6, 5, 4])
+    w2.coords = []
+    r2 = Ring(w2)
+    w3 = Way(3, {}, [1, 7, 6])
+    w3.coords = []
+    r3 = Ring(w3)
+    
+    rings = merge_rings([r1, r2, r3])
+    eq_(len(rings), 1)
+    r = rings[0]
+    eq_(r.tags, {'name': 'foo', 'building': 'true'})
+    eq_(r.is_closed(), True)
+    # eq_(r.ways, [w1, w2, w3])
+
+
+class W(Way):
+    # way without coords
+    coords = []
+
+from imposm.merge import permutations
+
+def test_merge_rings_permutations():
+    """
+    Test all possible permutations of 4 ring segments.
+    """
+    for i in range(16):
+        # test each segment in both directions
+        f1 = i & 1 == 0
+        f2 = i & 2 == 0
+        f3 = i & 4 == 0
+        f4 = i & 8 == 0
+        for i1, i2, i3, i4 in permutations([0, 1, 2, 3]):
+            ways = [
+                W(1, {}, [1, 2, 3, 4] if f1 else [4, 3, 2, 1]),
+                W(2, {}, [4, 5, 6, 7] if f2 else [7, 6, 5, 4]),
+                W(3, {}, [7, 8, 9, 10] if f3 else [10, 9, 8, 7]),
+                W(4, {}, [10, 11, 12, 1] if f4 else [1, 12, 11, 10]),
+            ]
+            ways = [ways[i1], ways[i2], ways[i3], ways[i4]]
+            rings = [Ring(w) for w in ways]
+            
+            merged_rings = merge_rings(rings)
+            eq_(len(merged_rings), 1)
+            r = merged_rings[0]
+            eq_(r.is_closed(), True, (ways, r.refs))
+            eq_(set(r.ways), set(ways))
+
+            # check order of refs
+            prev_x = r.refs[0]
+            for x in r.refs[1:]:
+                if not abs(prev_x - x) == 1:
+                    assert (
+                        (prev_x == 1 and x == 12) or 
+                        (prev_x == 12 and x == 1)
+                    ), 'not in order %r' % r.refs
+                prev_x = x
\ No newline at end of file
diff --git a/imposm/util.py b/imposm/util.py
new file mode 100644
index 0000000..0d95bd2
--- /dev/null
+++ b/imposm/util.py
@@ -0,0 +1,237 @@
+# Copyright 2011 Omniscale (http://omniscale.com)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import sys
+import time
+import datetime
+import mmap
+import multiprocessing
+
+from multiprocessing import JoinableQueue
+from Queue import Empty
+
+import logging
+log = logging.getLogger(__name__)
+
+try:
+    from setproctitle import setproctitle
+    setproctitle
+except ImportError:
+    setproctitle = lambda x: None
+
+class Timer(object):
+    def __init__(self, title, logger):
+        self.title = title
+        self.logger = logger
+        self.start_time = time.time()
+    def stop(self):
+        seconds = time.time() - self.start_time
+        self.logger.message('%s took %s' % (self.title, format_total_time(seconds)))
+
+class ParserProgress(multiprocessing.Process):
+    def __init__(self):
+        self.queue = multiprocessing.Queue()
+        multiprocessing.Process.__init__(self)
+        
+    def run(self):
+        counters = {'coords': 0, 'nodes':0, 'ways':0, 'relations':0}
+        while True:
+            log_statement = self.queue.get()
+            if log_statement is None:
+                break
+            
+            log_type, incr = log_statement
+            counters[log_type] += incr
+            self.print_log(counters)
+        
+    @staticmethod
+    def message(msg):
+        print >>sys.stderr, "[%s] %s" % (timestamp(), msg)
+        sys.stderr.flush()
+
+    def print_log(self, counters):
+        print >>sys.stderr, "[%s] coords: %dk nodes: %dk ways: %dk relations: %dk\r" % (
+            timestamp(),
+            int(counters['coords']/1000),
+            int(counters['nodes']/1000),
+            int(counters['ways']/1000),
+            int(counters['relations']/1000)
+        ),
+        sys.stderr.flush()
+    
+    def log(self, log_type, incr):
+        self.queue.put((log_type, incr))
+    
+    def stop(self):
+        sys.stderr.write('\n')
+        sys.stderr.flush()
+        self.queue.put(None)
+
+class ProgressLog(object):
+    def __init__(self, title=None, total=None):
+        self.count = 0
+        self.total = total
+        self._total = '/%dk' % (total/1000) if total else ''
+        self.title = title
+        self.start_time = time.time()
+        self.print_log()
+    
+    @staticmethod
+    def message(msg):
+        print >>sys.stderr, "[%s] %s" % (timestamp(), msg)
+        sys.stderr.flush()
+    
+    def log(self, value=None, step=1):
+        before = self.count//1000
+        if value:
+            self.count = value
+        else:
+            self.count += step
+        if self.count//1000 > before:
+            self.print_log()
+    
+    def print_log(self):
+        print >>sys.stderr, "[%s] %s: %dk%s\r" % (
+            timestamp(), self.title,
+            int(self.count/1000), self._total,
+        ),
+        sys.stderr.flush()
+    
+    def stop(self):
+        print >>sys.stderr
+        seconds = time.time() - self.start_time
+        total_time = format_total_time(seconds)
+        print >>sys.stderr, "[%s] %s: total time %s for %d (%d/s)" % (
+            timestamp(), self.title, total_time, self.count, self.count/seconds)
+        sys.stderr.flush()
+
+def timestamp():
+    return datetime.datetime.now().strftime('%H:%M:%S')
+    
+def format_total_time(seconds):
+    h, m, s = seconds_to_hms(seconds)
+    res = '%-02ds' % s
+    if h or m:
+        res = '%-02dm ' % m + res
+        if h:
+            res = '%-02dh ' % h + res
+    return res
+
+def seconds_to_hms(seconds):
+    h, s = divmod(seconds, 60*60)
+    m, s = divmod(s, 60)
+    return h, m, s
+
+class NullLog(object):
+    def log_node(self):
+        pass
+    node = log_node
+    
+    def log_way(self):
+        pass
+    way = log_way
+    
+    def log_relation(self):
+        pass
+    relation = log_relation
+
+
+class MMapReader(object):
+    def __init__(self, m, size):
+        self.m = m
+        self.m.seek(0)
+        self.size = size
+    
+    def read(self, size=None):
+        if size is None:
+            size = self.size - self.m.tell()
+        else:
+            size = min(self.size - self.m.tell(), size)
+        return self.m.read(size)
+        
+    def readline(self):
+        cur_pos = self.m.tell()
+        if cur_pos >= self.size:
+            return
+        nl_pos = self.m.find('\n')
+        self.m.seek(cur_pos)
+        return self.m.read(nl_pos-cur_pos)
+    
+    def seek(self, n):
+        self.m.seek(n)
+
+class MMapPool(object):
+    def __init__(self, n, mmap_size):
+        self.n = n
+        self.mmap_size = mmap_size
+        self.pool = [mmap.mmap(-1, mmap_size) for _ in range(n)]
+        self.free_mmaps = set(range(n))
+        self.free_queue = JoinableQueue()
+        
+    def new(self):
+        if not self.free_mmaps:
+            self.free_mmaps.add(self.free_queue.get())
+            self.free_queue.task_done()
+        while True:
+            try:
+                self.free_mmaps.add(self.free_queue.get_nowait())
+                self.free_queue.task_done()
+            except Empty:
+                break
+        mmap_idx = self.free_mmaps.pop()
+        return mmap_idx, self.pool[mmap_idx]
+    
+    def join(self):
+        while len(self.free_mmaps) < self.n:
+            self.free_mmaps.add(self.free_queue.get())
+            self.free_queue.task_done()
+
+    def get(self, idx):
+        return self.pool[idx]
+
+    def free(self, idx):
+        self.free_queue.put(idx)
+
+
+def create_pool(creator, size):
+    pool = []
+    for i in xrange(size):
+        proc = creator()
+        proc.start()
+        pool.append(proc)
+    return pool
+
+def shutdown_pool(procs, queue=None, sentinel=None):
+    if queue:
+        for _ in range(len(procs)):
+            queue.put(sentinel)
+    for p in procs:
+        p.join(timeout=10*60) # 10 min
+        if p.is_alive():
+            log.warn('could not join process %r, terminating process', p)
+            p.terminate()
+
+def estimate_records(files):
+    records = 0
+    for f in files:
+        fsize = os.path.getsize(f)
+        if f.endswith('.bz2'):
+            fsize *= 11 # observed bzip2 compression factor on osm data
+        if f.endswith('.pbf'):
+            fsize *= 15 # observed pbf compression factor on osm data
+        records += fsize/200
+    
+    return int(records)
+    
\ No newline at end of file
diff --git a/imposm/version.py b/imposm/version.py
new file mode 100644
index 0000000..b70c049
--- /dev/null
+++ b/imposm/version.py
@@ -0,0 +1,15 @@
+# Copyright 2011 Omniscale (http://omniscale.com)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+__version__ = '2.1.3'
diff --git a/imposm/writer.py b/imposm/writer.py
new file mode 100644
index 0000000..37aec0f
--- /dev/null
+++ b/imposm/writer.py
@@ -0,0 +1,104 @@
+# Copyright 2011 Omniscale (http://omniscale.com)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import array
+
+from multiprocessing import Process, JoinableQueue
+
+from imposm.dbimporter import NodeProcess, WayProcess, RelationProcess
+from imposm.util import create_pool, shutdown_pool
+from imposm.cache import OSMCache
+
+class ImposmWriter(object):
+    def __init__(self, mapping, db, cache, pool_size=2, logger=None, dry_run=False):
+        self.mapping = mapping
+        self.db = db
+        self.mapper = mapping
+        self.cache = cache
+        self.pool_size = pool_size
+        self.logger = logger
+        self.dry_run = dry_run
+
+    def _write_elem(self, proc, elem_cache, log, pool_size, proc_args=[]):
+        queue = JoinableQueue(16)
+
+        importer = lambda: proc(queue, self.db, self.mapper, self.cache, self.dry_run, *proc_args)
+        pool = create_pool(importer, pool_size)
+
+        data = []
+        for i, elem in enumerate(elem_cache):
+            if elem.tags:
+                data.append(elem)
+            if len(data) >= 128:
+                queue.put(data)
+                log.log(i)
+                data = []
+        queue.put(data)
+
+        shutdown_pool(pool, queue)
+        log.stop()
+        self.cache.close_all()
+
+    def relations(self):
+        cache = self.cache.relations_cache()
+        log = self.logger('relations', len(cache))
+        inserted_way_queue = JoinableQueue()
+        way_marker = WayMarkerProcess(inserted_way_queue, self.cache, self.logger)
+        way_marker.start()
+
+        self._write_elem(RelationProcess, cache, log, self.pool_size, [inserted_way_queue])
+
+        inserted_way_queue.put(None)
+        way_marker.join()
+
+    def ways(self):
+        cache = self.cache.ways_cache()
+        log = self.logger('ways', len(cache))
+        self._write_elem(WayProcess, cache, log, self.pool_size)
+
+    def nodes(self):
+        cache = self.cache.nodes_cache()
+        log = self.logger('nodes', len(cache))
+        self._write_elem(NodeProcess, cache, log, self.pool_size)
+        
+
+class WayMarkerProcess(Process):
+    def __init__(self, queue, cache, logger):
+        Process.__init__(self)
+        self.daemon = True
+        self.queue = queue
+        self.cache = cache
+        self.logger = logger
+    
+    def run(self):
+        inserted_ways = array.array('I')
+        while True:
+            osmid = self.queue.get()
+            if osmid is None:
+                break
+            inserted_ways.append(osmid)
+
+        self.update_inserted_ways(inserted_ways)
+
+    def update_inserted_ways(self, inserted_ways):
+        log = self.logger('marking inserted ways', len(inserted_ways))
+        cache = self.cache.ways_cache(mode='w')
+        for i, osmid in enumerate(inserted_ways):
+            way = cache.get(osmid)
+            way.tags['_inserted_'] = True
+            cache.put(osmid, way.tags, way.refs)
+            if i % 100 == 0:
+                log.log(i)
+        cache.close()
+        log.stop()
\ No newline at end of file
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..655015c
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,11 @@
+[nosetests]
+cover-erase = 1
+verbosity = 2
+doctest-tests = 1
+with-doctest = 1
+
+[egg_info]
+tag_date = 0
+tag_build = 
+tag_svn_revision = 0
+
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..1b1d5ab
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,88 @@
+import os
+import errno
+import subprocess
+import sys
+from setuptools import setup, find_packages
+from setuptools.extension import Extension
+from setuptools.command.build_ext import build_ext
+from distutils.errors import DistutilsPlatformError
+
+install_requires = [
+    'imposm.parser',
+    'psycopg2',
+    'Shapely',
+]
+
+if sys.version_info < (2, 6):
+    install_requires.append('multiprocessing')
+
+class build_ext_with_cython(build_ext):
+    def generate_c_file(self):
+        try:
+            print 'creating imposm/cache/tc.c'
+            proc = subprocess.Popen(
+                ['cython', 'imposm/cache/tc.pyx'],
+                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        except OSError, ex:
+            if ex.errno == errno.ENOENT:
+                print "Could not find cython command."
+                raise DistutilsPlatformError("Failed to generate "
+                    "C files with cython.")
+            else:
+                raise
+        out = proc.communicate()[0]
+        result = proc.wait()
+        if result != 0:
+            print "Error during C files generation with cython:"
+            print out
+            raise DistutilsPlatformError("Failed to generate "
+                "C files with cython.")
+    def run(self):
+        try:
+            self.generate_c_file()
+        except DistutilsPlatformError:
+            if os.path.exists('imposm/cache/tc.c'):
+                print 'Found existing C file. Ignoring previous error.'
+            else:
+                raise
+        build_ext.run(self)
+
+import imposm.version
+version = imposm.version.__version__
+
+setup(
+    name = "imposm",
+    version = version,
+    description='OpenStreetMap importer for PostGIS.',
+    long_description=open('README').read() + open('CHANGES').read(),
+    author = "Oliver Tonnhofer",
+    author_email = "olt at omniscale.de",
+    url='http://imposm.org/',
+    license='Apache Software License 2.0',
+    packages=find_packages(),
+    namespace_packages = ['imposm'],
+    include_package_data=True,
+    package_data = {'': ['*.xml']},
+    install_requires=install_requires,
+    classifiers=[
+        "Development Status :: 4 - Beta",
+        "License :: OSI Approved :: Apache Software License",
+        "Operating System :: OS Independent",
+        "Programming Language :: C",
+        "Programming Language :: C++",
+        "Programming Language :: Python :: 2.5",
+        "Programming Language :: Python :: 2.6",
+        "Programming Language :: Python :: 2.7",
+        "Topic :: Scientific/Engineering :: GIS",
+    ],
+    ext_modules=[
+        Extension("imposm.cache.tc", ["imposm/cache/tc.c"], libraries = ["tokyocabinet"]),
+    ],
+    entry_points = {
+        'console_scripts': [
+            'imposm = imposm.app:main',
+            'imposm-psqldb = imposm.psqldb:main',
+        ],
+    },
+    cmdclass={'build_ext':build_ext_with_cython},
+)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/imposm.git



More information about the Pkg-grass-devel mailing list