[imposm] 05/47: Imported Upstream version 2.3.2

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Fri Mar 13 19:07:36 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 e3b372ec43ddc6609206fb3b72974e3652dd08a8
Author: David Paleino <dapal at debian.org>
Date:   Tue Oct 11 23:07:41 2011 +0200

    Imported Upstream version 2.3.2
---
 CHANGES                          |   43 +
 MANIFEST.in                      |    3 +
 PKG-INFO                         |   45 +-
 imposm.egg-info/PKG-INFO         |   45 +-
 imposm.egg-info/SOURCES.txt      |    9 +-
 imposm/app.py                    |  105 +-
 imposm/base.py                   |    2 +-
 imposm/cache/internal.cc         |  717 ++++++
 imposm/cache/osm.py              |   26 +-
 imposm/cache/tc.c                | 5063 ++++++++++++++++++++++++++++++++++----
 imposm/cache/tc.pyx              |  187 +-
 imposm/{version.py => config.py} |   12 +-
 imposm/db/__init__.py            |    4 -
 imposm/db/config.py              |   73 +
 imposm/db/postgis.py             |   62 +-
 imposm/dbimporter.py             |   26 +-
 imposm/defaultmapping.py         |   63 +-
 imposm/geom.py                   |    9 +-
 imposm/mapping.py                |  316 ++-
 imposm/multipolygon.py           |  222 +-
 imposm/psqldb.py                 |    2 +-
 imposm/test/test_cache.py        |   57 +-
 imposm/test/test_field_types.py  |   49 +
 imposm/test/test_imported.py     |  108 +
 imposm/test/test_multipolygon.py |  294 ++-
 imposm/test/test_tag_mapper.py   |  140 ++
 imposm/version.py                |    2 +-
 imposm/writer.py                 |   30 +-
 internal.proto                   |   11 +
 setup.py                         |   31 +
 30 files changed, 7066 insertions(+), 690 deletions(-)

diff --git a/CHANGES b/CHANGES
index 57a2c24..833eec8 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,49 @@
 Changelog
 ---------
 
+2.3.2 2011-09-05
+~~~~~~~~~~~~~~~~
+
+- fixed --table-prefix
+- add --debug option for more verbose output
+- fixed way merging
+- fixed default_name_fields for UnionViews
+- improved (contains) relation builder
+
+2.3.1 2011-07-05
+~~~~~~~~~~~~~~~~
+
+- DROP views instead of REPLACE to prevent errors
+  when columns changed
+
+2.3.0 2011-07-05
+~~~~~~~~~~~~~~~~
+
+- new PseudoArea field type
+- new Name and LocalizedName field type
+- update SRS in GeneralizedTables and UnionTables
+- new waterareas_gen0|1 in default style
+- new area field in landusages table
+- new meter_to_mapunit function to use same mapping 
+  for EPSG:4326 and projected SRS
+
+2.2.0 2011-06-01
+~~~~~~~~~~~~~~~~
+
+- support for Shapely speedups (>=1.2.10)
+- new --port option for PostgreSQL port
+- reduced size of nodes cache by ~40%
+- store inserted ways in extra cache
+- support for relations type=boundary
+- new faster relation builder that supports
+  relations with >1000 rings
+- set import options in mapping file
+
+  - import_partial_relations=True/False
+  - relation_builder=contains(new)/union(old)
+  - imposm_multipolygon_report=60(seconds)
+  - imposm_multipolygon_max_ring=0
+
 2.1.3 2011-04-19
 ~~~~~~~~~~~~~~~~
 
diff --git a/MANIFEST.in b/MANIFEST.in
index 101809a..0411940 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -4,3 +4,6 @@ include CHANGES
 include imposm/900913.sql
 include imposm/cache/tc.c
 include imposm/cache/tc.pyx
+include internal.proto
+include imposm/cache/internal.cc
+exclude imposm/cache/internal.pb.cc
diff --git a/PKG-INFO b/PKG-INFO
index 7576020..34f7d5e 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: imposm
-Version: 2.1.3
+Version: 2.3.2
 Summary: OpenStreetMap importer for PostGIS.
 Home-page: http://imposm.org/
 Author: Oliver Tonnhofer
@@ -23,6 +23,49 @@ Description: .. # -*- restructuredtext -*-
         Changelog
         ---------
         
+        2.3.2 2011-09-05
+        ~~~~~~~~~~~~~~~~
+        
+        - fixed --table-prefix
+        - add --debug option for more verbose output
+        - fixed way merging
+        - fixed default_name_fields for UnionViews
+        - improved (contains) relation builder
+        
+        2.3.1 2011-07-05
+        ~~~~~~~~~~~~~~~~
+        
+        - DROP views instead of REPLACE to prevent errors
+          when columns changed
+        
+        2.3.0 2011-07-05
+        ~~~~~~~~~~~~~~~~
+        
+        - new PseudoArea field type
+        - new Name and LocalizedName field type
+        - update SRS in GeneralizedTables and UnionTables
+        - new waterareas_gen0|1 in default style
+        - new area field in landusages table
+        - new meter_to_mapunit function to use same mapping 
+          for EPSG:4326 and projected SRS
+        
+        2.2.0 2011-06-01
+        ~~~~~~~~~~~~~~~~
+        
+        - support for Shapely speedups (>=1.2.10)
+        - new --port option for PostgreSQL port
+        - reduced size of nodes cache by ~40%
+        - store inserted ways in extra cache
+        - support for relations type=boundary
+        - new faster relation builder that supports
+          relations with >1000 rings
+        - set import options in mapping file
+        
+          - import_partial_relations=True/False
+          - relation_builder=contains(new)/union(old)
+          - imposm_multipolygon_report=60(seconds)
+          - imposm_multipolygon_max_ring=0
+        
         2.1.3 2011-04-19
         ~~~~~~~~~~~~~~~~
         
diff --git a/imposm.egg-info/PKG-INFO b/imposm.egg-info/PKG-INFO
index 7576020..34f7d5e 100644
--- a/imposm.egg-info/PKG-INFO
+++ b/imposm.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: imposm
-Version: 2.1.3
+Version: 2.3.2
 Summary: OpenStreetMap importer for PostGIS.
 Home-page: http://imposm.org/
 Author: Oliver Tonnhofer
@@ -23,6 +23,49 @@ Description: .. # -*- restructuredtext -*-
         Changelog
         ---------
         
+        2.3.2 2011-09-05
+        ~~~~~~~~~~~~~~~~
+        
+        - fixed --table-prefix
+        - add --debug option for more verbose output
+        - fixed way merging
+        - fixed default_name_fields for UnionViews
+        - improved (contains) relation builder
+        
+        2.3.1 2011-07-05
+        ~~~~~~~~~~~~~~~~
+        
+        - DROP views instead of REPLACE to prevent errors
+          when columns changed
+        
+        2.3.0 2011-07-05
+        ~~~~~~~~~~~~~~~~
+        
+        - new PseudoArea field type
+        - new Name and LocalizedName field type
+        - update SRS in GeneralizedTables and UnionTables
+        - new waterareas_gen0|1 in default style
+        - new area field in landusages table
+        - new meter_to_mapunit function to use same mapping 
+          for EPSG:4326 and projected SRS
+        
+        2.2.0 2011-06-01
+        ~~~~~~~~~~~~~~~~
+        
+        - support for Shapely speedups (>=1.2.10)
+        - new --port option for PostgreSQL port
+        - reduced size of nodes cache by ~40%
+        - store inserted ways in extra cache
+        - support for relations type=boundary
+        - new faster relation builder that supports
+          relations with >1000 rings
+        - set import options in mapping file
+        
+          - import_partial_relations=True/False
+          - relation_builder=contains(new)/union(old)
+          - imposm_multipolygon_report=60(seconds)
+          - imposm_multipolygon_max_ring=0
+        
         2.1.3 2011-04-19
         ~~~~~~~~~~~~~~~~
         
diff --git a/imposm.egg-info/SOURCES.txt b/imposm.egg-info/SOURCES.txt
index d2cdc80..746c491 100644
--- a/imposm.egg-info/SOURCES.txt
+++ b/imposm.egg-info/SOURCES.txt
@@ -2,12 +2,14 @@ CHANGES
 LICENSE
 MANIFEST.in
 README
+internal.proto
 setup.cfg
 setup.py
 imposm/900913.sql
 imposm/__init__.py
 imposm/app.py
 imposm/base.py
+imposm/config.py
 imposm/dbimporter.py
 imposm/defaultmapping.py
 imposm/geom.py
@@ -27,11 +29,16 @@ imposm.egg-info/namespace_packages.txt
 imposm.egg-info/requires.txt
 imposm.egg-info/top_level.txt
 imposm/cache/__init__.py
+imposm/cache/internal.cc
 imposm/cache/osm.py
 imposm/cache/tc.c
 imposm/cache/tc.pyx
 imposm/db/__init__.py
+imposm/db/config.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
+imposm/test/test_field_types.py
+imposm/test/test_imported.py
+imposm/test/test_multipolygon.py
+imposm/test/test_tag_mapper.py
\ No newline at end of file
diff --git a/imposm/app.py b/imposm/app.py
index 33c3b1d..f42c472 100644
--- a/imposm/app.py
+++ b/imposm/app.py
@@ -23,18 +23,24 @@ import multiprocessing
 from imposm.util import setproctitle
 
 try:
-    import shapely_speedups
+    import shapely.speedups
+    if shapely.speedups.available:
+        print 'Enabling Shapely speedups.'
+        shapely.speedups.enable()
 except ImportError:
-    pass
-else:
-    print 'patching shapely'
-    shapely_speedups.patch_shapely()
+    try:
+        import shapely_speedups
+        print 'Patching Shapely.'
+        shapely_speedups.patch_shapely()
+    except ImportError:
+        pass
 
+import imposm.config
 import imposm.mapping
 import imposm.util
 import imposm.version
 from imposm.writer import ImposmWriter
-from imposm.db import DB
+from imposm.db.config import DB
 from imposm.cache import OSMCache
 from imposm.reader import ImposmReader
 from imposm.mapping import TagMapper
@@ -44,9 +50,9 @@ try:
 except NotImplementedError:
     n_cpu = 2
 
-def setup_logging():
+def setup_logging(debug=False):
     imposm_log = logging.getLogger('imposm')
-    imposm_log.setLevel(logging.INFO)
+    imposm_log.setLevel(logging.DEBUG if debug else logging.INFO)
 
     ch = logging.StreamHandler(sys.stdout)
     ch.setLevel(logging.DEBUG)
@@ -57,21 +63,25 @@ def setup_logging():
 
 __version__ = imposm.version.__version__
 
-def main():
+def main(argv=None):
     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('--debug', action='store_true',
+        default=False, help='show debug information')
+    
     parser.add_option('-m', '--mapping-file', dest='mapping_file',
         metavar='<file>')
     parser.add_option('-h', '--host', dest='host', metavar='<host>')
+    parser.add_option('-p', '--port', dest='port', metavar='<port>')
     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('--connection', dest='connection')
     
     parser.add_option('-c', '--concurrency', dest='concurrency', metavar='N',
                       type='int', default=n_cpu)
@@ -85,7 +95,7 @@ def main():
     
     
     parser.add_option('--table-prefix',
-        dest='table_prefix', default='osm_new_', metavar='osm_new_',
+        dest='table_prefix', default=None, metavar='osm_new_',
         help='prefix for imported tables')
     parser.add_option('--table-prefix-production',
         dest='table_prefix_production', default='osm_', metavar='osm_',
@@ -115,12 +125,25 @@ def main():
     parser.add_option('-n', '--dry-run', dest='dry_run', default=False,
         action='store_true')
 
-    (options, args) = parser.parse_args()
+    (options, args) = parser.parse_args(argv)
+
+    setup_logging(debug=options.debug)
+
+    if (argv and len(argv) == 0) or len(sys.argv) == 1:
+        options.help = True
 
     if options.help:
         parser.print_help()
         sys.exit(1)
-
+    
+    if options.proj:
+        if ':' not in options.proj:
+            print 'ERROR: --proj should be in EPSG:00000 format'
+            sys.exit(1)
+        # check proj if meter_to_mapunit needs to do anything
+        if options.proj.lower() == 'epsg:4326':
+            imposm.mapping.import_srs_is_geographic = True
+    
     mapping_file = os.path.join(os.path.dirname(__file__),
         'defaultmapping.py')
     if options.mapping_file:
@@ -132,23 +155,35 @@ def main():
     tag_mapping = TagMapper([m for n, m in mappings.iteritems() 
         if isinstance(m, imposm.mapping.Mapping)])
 
+    if 'IMPOSM_MULTIPOLYGON_REPORT' in os.environ:
+        imposm.config.imposm_multipolygon_report = float(os.environ['IMPOSM_MULTIPOLYGON_REPORT'])
+    if 'IMPOSM_MULTIPOLYGON_MAX_RING' in os.environ:
+        imposm.config.imposm_multipolygon_max_ring = int(os.environ['IMPOSM_MULTIPOLYGON_MAX_RING'])
+
     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.table_prefix:
+            db_conf.prefix = options.table_prefix
+        else:
+            options.table_prefix = db_conf.prefix
+        
+        if options.connection:
+            from imposm.db.config import db_conf_from_string
+            db_conf = db_conf_from_string(options.connection, db_conf)
+        else:
+            db_conf.host = options.host or db_conf.host
+            db_conf.port = options.port or getattr(db_conf, 'port', None) #backw. compat
+            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
+            if options.proj:
+                db_conf.proj = options.proj
     
     logger = imposm.util.ProgressLog
     
@@ -180,7 +215,6 @@ def main():
             for arg in args:
                 logger.message('## reading %s' % arg)
                 reader.read(arg)
-        
         read_timer.stop()
 
     if options.write:
@@ -196,7 +230,7 @@ def main():
         # errors for missing tables (i.e. generalized tables)
         if not options.dry_run:
             db.create_views(mappings, ignore_errors=True)
-            db.connection.commit()
+            db.commit()
 
         writer = ImposmWriter(tag_mapping, db, cache=cache, 
             pool_size=options.concurrency, logger=logger,
@@ -207,9 +241,18 @@ def main():
 
         if not options.dry_run:
             db = DB(db_conf)
+
+            logger.message('## creating generalized tables')
+            generalized_timer = imposm.util.Timer('generalizing tables', logger)
             db.create_generalized_tables(mappings)
+            generalized_timer.stop()
+            
+            logger.message('## creating union views')
+            view_timer = imposm.util.Timer('creating views', logger)
             db.create_views(mappings)
-            db.connection.commit()
+            view_timer.stop()
+
+            db.commit()
         
         write_timer.stop()
 
@@ -233,12 +276,12 @@ def main():
         db.remove_views(options.table_prefix)
         db.db_conf.prefix = options.table_prefix_production
         db.create_views(mappings)
-        db.connection.commit()
+        db.commit()
     
     if options.remove_backup_tables:
         db = DB(db_conf)
         db.remove_tables(options.table_prefix_backup)
-        db.connection.commit()
+        db.commit()
     
     imposm_timer.stop()
 
diff --git a/imposm/base.py b/imposm/base.py
index ce2a7aa..bfc080d 100644
--- a/imposm/base.py
+++ b/imposm/base.py
@@ -59,7 +59,7 @@ class Way(object):
                 merge_refs = []
                 merge_refs.extend(self.partial_refs)
             else:
-                merge_refs = self.refs
+                merge_refs = [self.refs]
             merge_refs.append(refs)
             result = multimerge(merge_refs)
             if result is None:
diff --git a/imposm/cache/internal.cc b/imposm/cache/internal.cc
new file mode 100644
index 0000000..76b69ae
--- /dev/null
+++ b/imposm/cache/internal.cc
@@ -0,0 +1,717 @@
+#include <Python.h>
+#include <string>
+#include "structmember.h"
+#include "internal.pb.h"
+
+
+static PyObject *
+fastpb_convert5(::google::protobuf::int32 value)
+{
+    return PyLong_FromLong(value);
+}
+
+static PyObject *
+fastpb_convert3(::google::protobuf::int64 value)
+{
+    return PyLong_FromLongLong(value);
+}
+
+static PyObject *
+fastpb_convert18(::google::protobuf::int64 value)
+{
+    return PyLong_FromLongLong(value);
+}
+
+static PyObject *
+fastpb_convert17(::google::protobuf::int32 value)
+{
+    return PyLong_FromLong(value);
+}
+
+static PyObject *
+fastpb_convert13(::google::protobuf::uint32 value)
+{
+    return PyLong_FromUnsignedLong(value);
+}
+
+static PyObject *
+fastpb_convert4(::google::protobuf::uint64 value)
+{
+    return PyLong_FromUnsignedLong(value);
+}
+
+static PyObject *
+fastpb_convert1(double value)
+{
+    return PyFloat_FromDouble(value);
+}
+
+static PyObject *
+fastpb_convert2(float value)
+{
+   return PyFloat_FromDouble(value);
+}
+
+static PyObject *
+fastpb_convert9(const ::std::string &value)
+{
+    return PyUnicode_Decode(value.data(), value.length(), "utf-8", NULL);
+}
+
+static PyObject *
+fastpb_convert12(const ::std::string &value)
+{
+    return PyString_FromStringAndSize(value.data(), value.length());
+}
+
+static PyObject *
+fastpb_convert8(bool value)
+{
+    return PyBool_FromLong(value ? 1 : 0);
+}
+
+static PyObject *
+fastpb_convert14(int value)
+{
+    // TODO(robbyw): Check EnumName_IsValid(value)
+    return PyLong_FromLong(value);
+}
+
+
+
+
+  typedef struct {
+      PyObject_HEAD
+
+      imposm::cache::internal::DeltaCoords *protobuf;
+  } DeltaCoords;
+
+  static void
+  DeltaCoords_dealloc(DeltaCoords* self)
+  {
+      self->ob_type->tp_free((PyObject*)self);
+
+      delete self->protobuf;
+  }
+
+  static PyObject *
+  DeltaCoords_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+  {
+      DeltaCoords *self;
+
+      self = (DeltaCoords *)type->tp_alloc(type, 0);
+
+      self->protobuf = new imposm::cache::internal::DeltaCoords();
+
+      return (PyObject *)self;
+  }
+
+  static PyObject *
+  DeltaCoords_SerializeToString(DeltaCoords* self)
+  {
+      std::string result;
+      self->protobuf->SerializeToString(&result);
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  static PyObject *
+  DeltaCoords_ParseFromString(DeltaCoords* self, PyObject *value)
+  {
+      std::string serialized(PyString_AsString(value), PyString_Size(value));
+      self->protobuf->ParseFromString(serialized);
+      Py_RETURN_NONE;
+  }
+
+
+  
+    
+
+    static PyObject *
+    DeltaCoords_getids(DeltaCoords *self, void *closure)
+    {
+        
+          int len = self->protobuf->ids_size();
+          PyObject *tuple = PyTuple_New(len);
+          for (int i = 0; i < len; ++i) {
+            PyObject *value =
+                fastpb_convert18(
+                    self->protobuf->ids(i));
+            PyTuple_SetItem(tuple, i, value);
+          }
+          return tuple;
+
+        
+    }
+
+    static int
+    DeltaCoords_setids(DeltaCoords *self, PyObject *input, void *closure)
+    {
+      if (input == NULL || input == Py_None) {
+        self->protobuf->clear_ids();
+        return 0;
+      }
+
+      
+        if (PyString_Check(input)) {
+          PyErr_SetString(PyExc_TypeError, "The ids attribute value must be a sequence");
+          return -1;
+        }
+        PyObject *sequence = PySequence_Fast(input, "The ids attribute value must be a sequence");
+        self->protobuf->clear_ids();
+        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
+
+      
+
+      
+        ::google::protobuf::int64 protoValue;
+
+        // int64
+        if (PyInt_Check(value)) {
+          protoValue = PyInt_AsLong(value);
+        } else if (PyLong_Check(value)) {
+          protoValue = PyLong_AsLongLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The ids attribute value must be an integer");
+          return -1;
+        }
+
+      
+
+      
+          
+            self->protobuf->add_ids(protoValue);
+          
+        }
+
+        Py_XDECREF(sequence);
+      
+
+      return 0;
+    }
+  
+    
+
+    static PyObject *
+    DeltaCoords_getlats(DeltaCoords *self, void *closure)
+    {
+        
+          int len = self->protobuf->lats_size();
+          PyObject *tuple = PyTuple_New(len);
+          for (int i = 0; i < len; ++i) {
+            PyObject *value =
+                fastpb_convert18(
+                    self->protobuf->lats(i));
+            PyTuple_SetItem(tuple, i, value);
+          }
+          return tuple;
+
+        
+    }
+
+    static int
+    DeltaCoords_setlats(DeltaCoords *self, PyObject *input, void *closure)
+    {
+      if (input == NULL || input == Py_None) {
+        self->protobuf->clear_lats();
+        return 0;
+      }
+
+      
+        if (PyString_Check(input)) {
+          PyErr_SetString(PyExc_TypeError, "The lats attribute value must be a sequence");
+          return -1;
+        }
+        PyObject *sequence = PySequence_Fast(input, "The lats attribute value must be a sequence");
+        self->protobuf->clear_lats();
+        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
+
+      
+
+      
+        ::google::protobuf::int64 protoValue;
+
+        // int64
+        if (PyInt_Check(value)) {
+          protoValue = PyInt_AsLong(value);
+        } else if (PyLong_Check(value)) {
+          protoValue = PyLong_AsLongLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The lats attribute value must be an integer");
+          return -1;
+        }
+
+      
+
+      
+          
+            self->protobuf->add_lats(protoValue);
+          
+        }
+
+        Py_XDECREF(sequence);
+      
+
+      return 0;
+    }
+  
+    
+
+    static PyObject *
+    DeltaCoords_getlons(DeltaCoords *self, void *closure)
+    {
+        
+          int len = self->protobuf->lons_size();
+          PyObject *tuple = PyTuple_New(len);
+          for (int i = 0; i < len; ++i) {
+            PyObject *value =
+                fastpb_convert18(
+                    self->protobuf->lons(i));
+            PyTuple_SetItem(tuple, i, value);
+          }
+          return tuple;
+
+        
+    }
+
+    static int
+    DeltaCoords_setlons(DeltaCoords *self, PyObject *input, void *closure)
+    {
+      if (input == NULL || input == Py_None) {
+        self->protobuf->clear_lons();
+        return 0;
+      }
+
+      
+        if (PyString_Check(input)) {
+          PyErr_SetString(PyExc_TypeError, "The lons attribute value must be a sequence");
+          return -1;
+        }
+        PyObject *sequence = PySequence_Fast(input, "The lons attribute value must be a sequence");
+        self->protobuf->clear_lons();
+        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
+
+      
+
+      
+        ::google::protobuf::int64 protoValue;
+
+        // int64
+        if (PyInt_Check(value)) {
+          protoValue = PyInt_AsLong(value);
+        } else if (PyLong_Check(value)) {
+          protoValue = PyLong_AsLongLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The lons attribute value must be an integer");
+          return -1;
+        }
+
+      
+
+      
+          
+            self->protobuf->add_lons(protoValue);
+          
+        }
+
+        Py_XDECREF(sequence);
+      
+
+      return 0;
+    }
+  
+
+  static int
+  DeltaCoords_init(DeltaCoords *self, PyObject *args, PyObject *kwds)
+  {
+      
+        
+          PyObject *ids = NULL;
+        
+          PyObject *lats = NULL;
+        
+          PyObject *lons = NULL;
+        
+
+        static char *kwlist[] = {
+          
+            (char *) "ids",
+          
+            (char *) "lats",
+          
+            (char *) "lons",
+          
+          NULL
+        };
+
+        if (! PyArg_ParseTupleAndKeywords(
+            args, kwds, "|OOO", kwlist,
+            &ids,&lats,&lons))
+          return -1;
+
+        
+          if (ids) {
+            if (DeltaCoords_setids(self, ids, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+          if (lats) {
+            if (DeltaCoords_setlats(self, lats, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+          if (lons) {
+            if (DeltaCoords_setlons(self, lons, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+      
+
+      return 0;
+  }
+
+  static PyMemberDef DeltaCoords_members[] = {
+      {NULL}  // Sentinel
+  };
+
+
+  static PyGetSetDef DeltaCoords_getsetters[] = {
+    
+      {(char *)"ids",
+       (getter)DeltaCoords_getids, (setter)DeltaCoords_setids,
+       (char *)"",
+       NULL},
+    
+      {(char *)"lats",
+       (getter)DeltaCoords_getlats, (setter)DeltaCoords_setlats,
+       (char *)"",
+       NULL},
+    
+      {(char *)"lons",
+       (getter)DeltaCoords_getlons, (setter)DeltaCoords_setlons,
+       (char *)"",
+       NULL},
+    
+      {NULL}  // Sentinel
+  };
+
+
+  static PyMethodDef DeltaCoords_methods[] = {
+      {"SerializeToString", (PyCFunction)DeltaCoords_SerializeToString, METH_NOARGS,
+       "Serializes the protocol buffer to a string."
+      },
+      {"ParseFromString", (PyCFunction)DeltaCoords_ParseFromString, METH_O,
+       "Parses the protocol buffer from a string."
+      },
+      {NULL}  // Sentinel
+  };
+
+
+  static PyTypeObject DeltaCoordsType = {
+      PyObject_HEAD_INIT(NULL)
+      0,                                      /*ob_size*/
+      "imposm.cache.internal.DeltaCoords",  /*tp_name*/
+      sizeof(DeltaCoords),             /*tp_basicsize*/
+      0,                                      /*tp_itemsize*/
+      (destructor)DeltaCoords_dealloc, /*tp_dealloc*/
+      0,                                      /*tp_print*/
+      0,                                      /*tp_getattr*/
+      0,                                      /*tp_setattr*/
+      0,                                      /*tp_compare*/
+      0,                                      /*tp_repr*/
+      0,                                      /*tp_as_number*/
+      0,                                      /*tp_as_sequence*/
+      0,                                      /*tp_as_mapping*/
+      0,                                      /*tp_hash */
+      0,                                      /*tp_call*/
+      0,                                      /*tp_str*/
+      0,                                      /*tp_getattro*/
+      0,                                      /*tp_setattro*/
+      0,                                      /*tp_as_buffer*/
+      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+      "DeltaCoords objects",           /* tp_doc */
+      0,                                      /* tp_traverse */
+      0,                                      /* tp_clear */
+      0,                   	 	                /* tp_richcompare */
+      0,	   	                                /* tp_weaklistoffset */
+      0,                   		                /* tp_iter */
+      0,		                                  /* tp_iternext */
+      DeltaCoords_methods,             /* tp_methods */
+      DeltaCoords_members,             /* tp_members */
+      DeltaCoords_getsetters,          /* tp_getset */
+      0,                                      /* tp_base */
+      0,                                      /* tp_dict */
+      0,                                      /* tp_descr_get */
+      0,                                      /* tp_descr_set */
+      0,                                      /* tp_dictoffset */
+      (initproc)DeltaCoords_init,      /* tp_init */
+      0,                                      /* tp_alloc */
+      DeltaCoords_new,                 /* tp_new */
+  };
+
+
+  typedef struct {
+      PyObject_HEAD
+
+      imposm::cache::internal::DeltaList *protobuf;
+  } DeltaList;
+
+  static void
+  DeltaList_dealloc(DeltaList* self)
+  {
+      self->ob_type->tp_free((PyObject*)self);
+
+      delete self->protobuf;
+  }
+
+  static PyObject *
+  DeltaList_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+  {
+      DeltaList *self;
+
+      self = (DeltaList *)type->tp_alloc(type, 0);
+
+      self->protobuf = new imposm::cache::internal::DeltaList();
+
+      return (PyObject *)self;
+  }
+
+  static PyObject *
+  DeltaList_SerializeToString(DeltaList* self)
+  {
+      std::string result;
+      self->protobuf->SerializeToString(&result);
+      return PyString_FromStringAndSize(result.data(), result.length());
+  }
+
+
+  static PyObject *
+  DeltaList_ParseFromString(DeltaList* self, PyObject *value)
+  {
+      std::string serialized(PyString_AsString(value), PyString_Size(value));
+      self->protobuf->ParseFromString(serialized);
+      Py_RETURN_NONE;
+  }
+
+
+  
+    
+
+    static PyObject *
+    DeltaList_getids(DeltaList *self, void *closure)
+    {
+        
+          int len = self->protobuf->ids_size();
+          PyObject *tuple = PyTuple_New(len);
+          for (int i = 0; i < len; ++i) {
+            PyObject *value =
+                fastpb_convert18(
+                    self->protobuf->ids(i));
+            PyTuple_SetItem(tuple, i, value);
+          }
+          return tuple;
+
+        
+    }
+
+    static int
+    DeltaList_setids(DeltaList *self, PyObject *input, void *closure)
+    {
+      if (input == NULL || input == Py_None) {
+        self->protobuf->clear_ids();
+        return 0;
+      }
+
+      
+        if (PyString_Check(input)) {
+          PyErr_SetString(PyExc_TypeError, "The ids attribute value must be a sequence");
+          return -1;
+        }
+        PyObject *sequence = PySequence_Fast(input, "The ids attribute value must be a sequence");
+        self->protobuf->clear_ids();
+        for (Py_ssize_t i = 0, len = PySequence_Length(sequence); i < len; ++i) {
+          PyObject *value = PySequence_Fast_GET_ITEM(sequence, i);
+
+      
+
+      
+        ::google::protobuf::int64 protoValue;
+
+        // int64
+        if (PyInt_Check(value)) {
+          protoValue = PyInt_AsLong(value);
+        } else if (PyLong_Check(value)) {
+          protoValue = PyLong_AsLongLong(value);
+        } else {
+          PyErr_SetString(PyExc_TypeError,
+                          "The ids attribute value must be an integer");
+          return -1;
+        }
+
+      
+
+      
+          
+            self->protobuf->add_ids(protoValue);
+          
+        }
+
+        Py_XDECREF(sequence);
+      
+
+      return 0;
+    }
+  
+
+  static int
+  DeltaList_init(DeltaList *self, PyObject *args, PyObject *kwds)
+  {
+      
+        
+          PyObject *ids = NULL;
+        
+
+        static char *kwlist[] = {
+          
+            (char *) "ids",
+          
+          NULL
+        };
+
+        if (! PyArg_ParseTupleAndKeywords(
+            args, kwds, "|O", kwlist,
+            &ids))
+          return -1;
+
+        
+          if (ids) {
+            if (DeltaList_setids(self, ids, NULL) < 0) {
+              return -1;
+            }
+          }
+        
+      
+
+      return 0;
+  }
+
+  static PyMemberDef DeltaList_members[] = {
+      {NULL}  // Sentinel
+  };
+
+
+  static PyGetSetDef DeltaList_getsetters[] = {
+    
+      {(char *)"ids",
+       (getter)DeltaList_getids, (setter)DeltaList_setids,
+       (char *)"",
+       NULL},
+    
+      {NULL}  // Sentinel
+  };
+
+
+  static PyMethodDef DeltaList_methods[] = {
+      {"SerializeToString", (PyCFunction)DeltaList_SerializeToString, METH_NOARGS,
+       "Serializes the protocol buffer to a string."
+      },
+      {"ParseFromString", (PyCFunction)DeltaList_ParseFromString, METH_O,
+       "Parses the protocol buffer from a string."
+      },
+      {NULL}  // Sentinel
+  };
+
+
+  static PyTypeObject DeltaListType = {
+      PyObject_HEAD_INIT(NULL)
+      0,                                      /*ob_size*/
+      "imposm.cache.internal.DeltaList",  /*tp_name*/
+      sizeof(DeltaList),             /*tp_basicsize*/
+      0,                                      /*tp_itemsize*/
+      (destructor)DeltaList_dealloc, /*tp_dealloc*/
+      0,                                      /*tp_print*/
+      0,                                      /*tp_getattr*/
+      0,                                      /*tp_setattr*/
+      0,                                      /*tp_compare*/
+      0,                                      /*tp_repr*/
+      0,                                      /*tp_as_number*/
+      0,                                      /*tp_as_sequence*/
+      0,                                      /*tp_as_mapping*/
+      0,                                      /*tp_hash */
+      0,                                      /*tp_call*/
+      0,                                      /*tp_str*/
+      0,                                      /*tp_getattro*/
+      0,                                      /*tp_setattro*/
+      0,                                      /*tp_as_buffer*/
+      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+      "DeltaList objects",           /* tp_doc */
+      0,                                      /* tp_traverse */
+      0,                                      /* tp_clear */
+      0,                   	 	                /* tp_richcompare */
+      0,	   	                                /* tp_weaklistoffset */
+      0,                   		                /* tp_iter */
+      0,		                                  /* tp_iternext */
+      DeltaList_methods,             /* tp_methods */
+      DeltaList_members,             /* tp_members */
+      DeltaList_getsetters,          /* tp_getset */
+      0,                                      /* tp_base */
+      0,                                      /* tp_dict */
+      0,                                      /* tp_descr_get */
+      0,                                      /* tp_descr_set */
+      0,                                      /* tp_dictoffset */
+      (initproc)DeltaList_init,      /* tp_init */
+      0,                                      /* tp_alloc */
+      DeltaList_new,                 /* tp_new */
+  };
+
+
+
+static PyMethodDef module_methods[] = {
+    {NULL}  // Sentinel
+};
+
+#ifndef PyMODINIT_FUNC	// Declarations for DLL import/export.
+#define PyMODINIT_FUNC void
+#endif
+PyMODINIT_FUNC
+initinternal(void)
+{
+    GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+    PyObject* m;
+
+    
+
+    
+      if (PyType_Ready(&DeltaCoordsType) < 0)
+          return;
+    
+      if (PyType_Ready(&DeltaListType) < 0)
+          return;
+    
+
+    m = Py_InitModule3("internal", module_methods,
+                       "");
+
+    if (m == NULL)
+      return;
+
+    
+
+    
+      Py_INCREF(&DeltaCoordsType);
+      PyModule_AddObject(m, "DeltaCoords", (PyObject *)&DeltaCoordsType);
+    
+      Py_INCREF(&DeltaListType);
+      PyModule_AddObject(m, "DeltaList", (PyObject *)&DeltaListType);
+    
+}
\ No newline at end of file
diff --git a/imposm/cache/osm.py b/imposm/cache/osm.py
index 2f7e194..d697723 100644
--- a/imposm/cache/osm.py
+++ b/imposm/cache/osm.py
@@ -14,17 +14,18 @@
 
 import os
 
-from . tc import CoordDB, NodeDB, WayDB, RelationDB
+from . tc import DeltaCoordsDB, NodeDB, WayDB, InsertedWayDB, RelationDB
 
 class OSMCache(object):
-    def __init__(self, path, suffix='imposm_', prefix='.cache'):
+    def __init__(self, path, prefix='imposm_', suffix='.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.suffix = suffix
+        self.coords_fname = os.path.join(path, prefix + 'coords' + suffix) 
+        self.nodes_fname = os.path.join(path, prefix + 'nodes' + suffix) 
+        self.ways_fname = os.path.join(path, prefix + 'ways' + suffix) 
+        self.inserted_ways_fname = os.path.join(path, prefix + 'inserted_ways' + suffix) 
+        self.relations_fname = os.path.join(path, prefix + 'relations' + suffix) 
         self.caches = {}
 
     def close_all(self):
@@ -33,7 +34,7 @@ class OSMCache(object):
         self.caches = {}
 
     def coords_cache(self, mode='r', estimated_records=None):
-        return self._x_cache(self.coords_fname, CoordDB, mode, estimated_records)
+        return self._x_cache(self.coords_fname, DeltaCoordsDB, mode, estimated_records)
 
     def nodes_cache(self, mode='r', estimated_records=None):
         return self._x_cache(self.nodes_fname, NodeDB, mode, estimated_records)
@@ -41,6 +42,13 @@ class OSMCache(object):
     def ways_cache(self, mode='r', estimated_records=None):
         return self._x_cache(self.ways_fname, WayDB, mode, estimated_records)
 
+    def inserted_ways_cache(self, mode='r', estimated_records=None):
+        return self._x_cache(self.inserted_ways_fname, InsertedWayDB, mode, estimated_records)
+
+    def remove_inserted_way_cache(self):
+        if os.path.exists(self.inserted_ways_fname):
+            os.unlink(self.inserted_ways_fname)
+
     def relations_cache(self, mode='r', estimated_records=None):
         return self._x_cache(self.relations_fname, RelationDB, mode, estimated_records)
 
@@ -54,4 +62,4 @@ class OSMCache(object):
         cache = x_class(x, mode, estimated_records=estimated_records)
         self.caches[x] = mode, cache
 
-        return cache
\ No newline at end of file
+        return cache
diff --git a/imposm/cache/tc.c b/imposm/cache/tc.c
index 4c5659d..701fde7 100644
--- a/imposm/cache/tc.c
+++ b/imposm/cache/tc.c
@@ -1,4 +1,4 @@
-/* Generated by Cython 0.14.1 on Wed Apr 13 15:39:58 2011 */
+/* Generated by Cython 0.14.1 on Mon May 23 09:29:44 2011 */
 
 #define PY_SSIZE_T_CLEAN
 #include "Python.h"
@@ -337,7 +337,19 @@ struct __pyx_obj_6imposm_5cache_2tc_BDB {
   BDBCUR *_cur;
 };
 
-/* "imposm/cache/tc.pyx":200
+/* "imposm/cache/tc.pyx":270
+ *         return Node(osmid, data[0], data[1])
+ * 
+ * cdef class InsertedWayDB(BDB):             # <<<<<<<<<<<<<<
+ *     def put(self, int64_t osmid):
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), 'x', 1);
+ */
+
+struct __pyx_obj_6imposm_5cache_2tc_InsertedWayDB {
+  struct __pyx_obj_6imposm_5cache_2tc_BDB __pyx_base;
+};
+
+/* "imposm/cache/tc.pyx":217
  *         tcbdbdel(self.db)
  * 
  * cdef class CoordDB(BDB):             # <<<<<<<<<<<<<<
@@ -349,8 +361,8 @@ 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])
+/* "imposm/cache/tc.pyx":294
+ *         return osmid
  * 
  * cdef class RefTagDB(BDB):             # <<<<<<<<<<<<<<
  *     """
@@ -361,7 +373,7 @@ struct __pyx_obj_6imposm_5cache_2tc_RefTagDB {
   struct __pyx_obj_6imposm_5cache_2tc_BDB __pyx_base;
 };
 
-/* "imposm/cache/tc.pyx":263
+/* "imposm/cache/tc.pyx":304
  *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>data, len(data))
  * 
  * cdef class WayDB(RefTagDB):             # <<<<<<<<<<<<<<
@@ -373,7 +385,7 @@ struct __pyx_obj_6imposm_5cache_2tc_WayDB {
   struct __pyx_obj_6imposm_5cache_2tc_RefTagDB __pyx_base;
 };
 
-/* "imposm/cache/tc.pyx":267
+/* "imposm/cache/tc.pyx":308
  *         return Way(osmid, data[0], data[1])
  * 
  * cdef class RelationDB(RefTagDB):             # <<<<<<<<<<<<<<
@@ -385,7 +397,7 @@ struct __pyx_obj_6imposm_5cache_2tc_RelationDB {
   struct __pyx_obj_6imposm_5cache_2tc_RefTagDB __pyx_base;
 };
 
-/* "imposm/cache/tc.pyx":243
+/* "imposm/cache/tc.pyx":260
  *         return osmid, data
  * 
  * cdef class NodeDB(BDB):             # <<<<<<<<<<<<<<
@@ -413,7 +425,7 @@ struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB {
 static struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB *__pyx_vtabptr_6imposm_5cache_2tc_BDB;
 
 
-/* "imposm/cache/tc.pyx":200
+/* "imposm/cache/tc.pyx":217
  *         tcbdbdel(self.db)
  * 
  * cdef class CoordDB(BDB):             # <<<<<<<<<<<<<<
@@ -428,7 +440,7 @@ struct __pyx_vtabstruct_6imposm_5cache_2tc_CoordDB {
 static struct __pyx_vtabstruct_6imposm_5cache_2tc_CoordDB *__pyx_vtabptr_6imposm_5cache_2tc_CoordDB;
 
 
-/* "imposm/cache/tc.pyx":243
+/* "imposm/cache/tc.pyx":260
  *         return osmid, data
  * 
  * cdef class NodeDB(BDB):             # <<<<<<<<<<<<<<
@@ -442,8 +454,8 @@ struct __pyx_vtabstruct_6imposm_5cache_2tc_NodeDB {
 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])
+/* "imposm/cache/tc.pyx":294
+ *         return osmid
  * 
  * cdef class RefTagDB(BDB):             # <<<<<<<<<<<<<<
  *     """
@@ -456,7 +468,7 @@ struct __pyx_vtabstruct_6imposm_5cache_2tc_RefTagDB {
 static struct __pyx_vtabstruct_6imposm_5cache_2tc_RefTagDB *__pyx_vtabptr_6imposm_5cache_2tc_RefTagDB;
 
 
-/* "imposm/cache/tc.pyx":267
+/* "imposm/cache/tc.pyx":308
  *         return Way(osmid, data[0], data[1])
  * 
  * cdef class RelationDB(RefTagDB):             # <<<<<<<<<<<<<<
@@ -470,7 +482,21 @@ struct __pyx_vtabstruct_6imposm_5cache_2tc_RelationDB {
 static struct __pyx_vtabstruct_6imposm_5cache_2tc_RelationDB *__pyx_vtabptr_6imposm_5cache_2tc_RelationDB;
 
 
-/* "imposm/cache/tc.pyx":263
+/* "imposm/cache/tc.pyx":270
+ *         return Node(osmid, data[0], data[1])
+ * 
+ * cdef class InsertedWayDB(BDB):             # <<<<<<<<<<<<<<
+ *     def put(self, int64_t osmid):
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), 'x', 1);
+ */
+
+struct __pyx_vtabstruct_6imposm_5cache_2tc_InsertedWayDB {
+  struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB __pyx_base;
+};
+static struct __pyx_vtabstruct_6imposm_5cache_2tc_InsertedWayDB *__pyx_vtabptr_6imposm_5cache_2tc_InsertedWayDB;
+
+
+/* "imposm/cache/tc.pyx":304
  *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>data, len(data))
  * 
  * cdef class WayDB(RefTagDB):             # <<<<<<<<<<<<<<
@@ -625,12 +651,56 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i)
     return r;
 }
 
+static CYTHON_INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) {
+    if (likely(PyList_CheckExact(L))) {
+        if (PyList_Append(L, x) < 0) return NULL;
+        Py_INCREF(Py_None);
+        return Py_None; /* this is just to have an accurate signature */
+    }
+    else {
+        PyObject *r, *m;
+        m = __Pyx_GetAttrString(L, "append");
+        if (!m) return NULL;
+        r = PyObject_CallFunctionObjArgs(m, x, NULL);
+        Py_DECREF(m);
+        return r;
+    }
+}
+
+static CYTHON_INLINE long __Pyx_NegateNonNeg(long b) { return unlikely(b < 0) ? b : !b; }
+static CYTHON_INLINE PyObject* __Pyx_PyBoolOrNull_FromLong(long b) {
+    return unlikely(b < 0) ? NULL : __Pyx_PyBool_FromLong(b);
+}
+
 static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/
 
-static CYTHON_INLINE int64_t __Pyx_PyInt_from_py_int64_t(PyObject *);
+static PyObject *__Pyx_FindPy2Metaclass(PyObject *bases); /*proto*/
+
+static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name,
+                                   PyObject *modname); /*proto*/
+
+#define __pyx_binding_PyCFunctionType_USED 1
+
+typedef struct {
+    PyCFunctionObject func;
+} __pyx_binding_PyCFunctionType_object;
+
+static PyTypeObject __pyx_binding_PyCFunctionType_type;
+static PyTypeObject *__pyx_binding_PyCFunctionType = NULL;
+
+static PyObject *__pyx_binding_PyCFunctionType_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module); /* proto */
+#define __pyx_binding_PyCFunctionType_New(ml, self) __pyx_binding_PyCFunctionType_NewEx(ml, self, NULL)
+
+static int __pyx_binding_PyCFunctionType_init(void); /* proto */
 
 static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_int64_t(int64_t);
 
+static CYTHON_INLINE int64_t __Pyx_PyInt_from_py_int64_t(PyObject *);
+
+static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_uint32_t(uint32_t);
+
+static CYTHON_INLINE uint32_t __Pyx_PyInt_from_py_uint32_t(PyObject *);
+
 static CYTHON_INLINE unsigned char __Pyx_PyInt_AsUnsignedChar(PyObject *);
 
 static CYTHON_INLINE unsigned short __Pyx_PyInt_AsUnsignedShort(PyObject *);
@@ -675,80 +745,173 @@ static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/
 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_InsertedWayDB = 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*/
+static PyObject *__pyx_f_6imposm_5cache_2tc_unzip_nodes(PyObject *); /*proto*/
+static PyObject *__pyx_f_6imposm_5cache_2tc_zip_nodes(PyObject *, PyObject *, PyObject *); /*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_object;
 static PyObject *__pyx_builtin_IOError;
 static PyObject *__pyx_builtin_StopIteration;
-static char __pyx_k_1[] = "imposm.base";
+static PyObject *__pyx_builtin_range;
+static char __pyx_k_1[] = "delta_nodes_cache_size";
+static char __pyx_k_2[] = "imposm.base";
+static char __pyx_k_3[] = "imposm.cache.internal";
+static char __pyx_k_4[] = "imposm.cache.tc";
 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__add[] = "add";
+static char __pyx_k__get[] = "get";
+static char __pyx_k__ids[] = "ids";
+static char __pyx_k__lat[] = "lat";
+static char __pyx_k__lon[] = "lon";
+static char __pyx_k__pop[] = "pop";
 static char __pyx_k__pos[] = "pos";
+static char __pyx_k__put[] = "put";
 static char __pyx_k__Node[] = "Node";
 static char __pyx_k___cur[] = "_cur";
+static char __pyx_k___get[] = "_get";
 static char __pyx_k___obj[] = "_obj";
 static char __pyx_k___put[] = "_put";
 static char __pyx_k__data[] = "data";
+static char __pyx_k__lats[] = "lats";
+static char __pyx_k__lons[] = "lons";
 static char __pyx_k__mode[] = "mode";
 static char __pyx_k__refs[] = "refs";
+static char __pyx_k__self[] = "self";
 static char __pyx_k__tags[] = "tags";
+static char __pyx_k__close[] = "close";
+static char __pyx_k__deque[] = "deque";
+static char __pyx_k__nodes[] = "nodes";
 static char __pyx_k__osmid[] = "osmid";
+static char __pyx_k__range[] = "range";
 static char __pyx_k___modes[] = "_modes";
 static char __pyx_k__append[] = "append";
+static char __pyx_k__bisect[] = "bisect";
+static char __pyx_k__insort[] = "insort";
+static char __pyx_k__object[] = "object";
+static char __pyx_k__osmids[] = "osmids";
 static char __pyx_k__IOError[] = "IOError";
 static char __pyx_k___opened[] = "_opened";
+static char __pyx_k__changed[] = "changed";
+static char __pyx_k__get_raw[] = "get_raw";
+static char __pyx_k__popleft[] = "popleft";
 static char __pyx_k__Relation[] = "Relation";
+static char __pyx_k____init__[] = "__init__";
 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__delta_id[] = "delta_id";
 static char __pyx_k__filename[] = "filename";
+static char __pyx_k__iteritems[] = "iteritems";
+static char __pyx_k__serialize[] = "serialize";
+static char __pyx_k__DeltaNodes[] = "DeltaNodes";
+static char __pyx_k__delta_node[] = "delta_node";
+static char __pyx_k__get_coords[] = "get_coords";
+static char __pyx_k__DeltaCoords[] = "DeltaCoords";
+static char __pyx_k__collections[] = "collections";
+static char __pyx_k__delta_nodes[] = "delta_nodes";
+static char __pyx_k__deserialize[] = "deserialize";
+static char __pyx_k___DeltaCoords[] = "_DeltaCoords";
+static char __pyx_k__DeltaCoordsDB[] = "DeltaCoordsDB";
 static char __pyx_k__StopIteration[] = "StopIteration";
 static char __pyx_k__put_marshaled[] = "put_marshaled";
+static char __pyx_k__delta_node_ids[] = "delta_node_ids";
+static char __pyx_k__ParseFromString[] = "ParseFromString";
+static char __pyx_k__delta_nodes_size[] = "delta_nodes_size";
+static char __pyx_k__fetch_delta_node[] = "fetch_delta_node";
+static char __pyx_k__SerializeToString[] = "SerializeToString";
 static char __pyx_k__estimated_records[] = "estimated_records";
 static PyObject *__pyx_n_s_1;
+static PyObject *__pyx_n_s_2;
+static PyObject *__pyx_n_s_3;
+static PyObject *__pyx_n_s_4;
+static PyObject *__pyx_n_s__DeltaCoords;
+static PyObject *__pyx_n_s__DeltaCoordsDB;
+static PyObject *__pyx_n_s__DeltaNodes;
 static PyObject *__pyx_n_s__IOError;
 static PyObject *__pyx_n_s__Node;
+static PyObject *__pyx_n_s__ParseFromString;
 static PyObject *__pyx_n_s__Relation;
+static PyObject *__pyx_n_s__SerializeToString;
 static PyObject *__pyx_n_s__StopIteration;
 static PyObject *__pyx_n_s__Way;
+static PyObject *__pyx_n_s___DeltaCoords;
+static PyObject *__pyx_n_s____init__;
 static PyObject *__pyx_n_s____main__;
 static PyObject *__pyx_n_s____test__;
 static PyObject *__pyx_n_s___cur;
+static PyObject *__pyx_n_s___get;
 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__add;
 static PyObject *__pyx_n_s__append;
+static PyObject *__pyx_n_s__bisect;
+static PyObject *__pyx_n_s__changed;
+static PyObject *__pyx_n_s__close;
+static PyObject *__pyx_n_s__collections;
 static PyObject *__pyx_n_s__data;
 static PyObject *__pyx_n_s__db;
+static PyObject *__pyx_n_s__delta_id;
+static PyObject *__pyx_n_s__delta_node;
+static PyObject *__pyx_n_s__delta_node_ids;
+static PyObject *__pyx_n_s__delta_nodes;
+static PyObject *__pyx_n_s__delta_nodes_size;
+static PyObject *__pyx_n_s__deque;
+static PyObject *__pyx_n_s__deserialize;
 static PyObject *__pyx_n_s__estimated_records;
+static PyObject *__pyx_n_s__fetch_delta_node;
 static PyObject *__pyx_n_s__filename;
+static PyObject *__pyx_n_s__get;
+static PyObject *__pyx_n_s__get_coords;
+static PyObject *__pyx_n_s__get_raw;
+static PyObject *__pyx_n_s__ids;
+static PyObject *__pyx_n_s__insort;
+static PyObject *__pyx_n_s__iteritems;
+static PyObject *__pyx_n_s__lat;
+static PyObject *__pyx_n_s__lats;
+static PyObject *__pyx_n_s__lon;
+static PyObject *__pyx_n_s__lons;
 static PyObject *__pyx_n_s__mode;
+static PyObject *__pyx_n_s__nodes;
+static PyObject *__pyx_n_s__object;
 static PyObject *__pyx_n_s__osmid;
+static PyObject *__pyx_n_s__osmids;
+static PyObject *__pyx_n_s__pop;
+static PyObject *__pyx_n_s__popleft;
 static PyObject *__pyx_n_s__pos;
+static PyObject *__pyx_n_s__put;
 static PyObject *__pyx_n_s__put_marshaled;
 static PyObject *__pyx_n_s__r;
+static PyObject *__pyx_n_s__range;
 static PyObject *__pyx_n_s__refs;
+static PyObject *__pyx_n_s__self;
+static PyObject *__pyx_n_s__serialize;
 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_6;
+static PyObject *__pyx_int_100;
 static PyObject *__pyx_int_128;
 
 /* "imposm/cache/tc.pyx":69
@@ -1055,7 +1218,7 @@ static int __pyx_pf_6imposm_5cache_2tc_3BDB_1__init__(PyObject *__pyx_v_self, Py
  *         self._tune_db(estimated_records)
  *         tcbdbsetcmpfunc(self.db, tccmpint64, NULL)             # <<<<<<<<<<<<<<
  *         if not tcbdbopen(self.db, filename, _modes[mode]):
- *             raise IOError
+ *             raise IOError(tcbdbecode(self.db))
  */
   tcbdbsetcmpfunc(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->db, tccmpint64, NULL);
 
@@ -1063,7 +1226,7 @@ static int __pyx_pf_6imposm_5cache_2tc_3BDB_1__init__(PyObject *__pyx_v_self, Py
  *         self._tune_db(estimated_records)
  *         tcbdbsetcmpfunc(self.db, tccmpint64, NULL)
  *         if not tcbdbopen(self.db, filename, _modes[mode]):             # <<<<<<<<<<<<<<
- *             raise IOError
+ *             raise IOError(tcbdbecode(self.db))
  *         self._opened = 1
  */
   __pyx_t_4 = ((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->db;
@@ -1081,11 +1244,22 @@ static int __pyx_pf_6imposm_5cache_2tc_3BDB_1__init__(PyObject *__pyx_v_self, Py
     /* "imposm/cache/tc.pyx":104
  *         tcbdbsetcmpfunc(self.db, tccmpint64, NULL)
  *         if not tcbdbopen(self.db, filename, _modes[mode]):
- *             raise IOError             # <<<<<<<<<<<<<<
+ *             raise IOError(tcbdbecode(self.db))             # <<<<<<<<<<<<<<
  *         self._opened = 1
  * 
  */
-    __Pyx_Raise(__pyx_builtin_IOError, 0, 0);
+    __pyx_t_2 = PyInt_FromLong(tcbdbecode(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->db)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 104; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 104; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_3));
+    PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
+    __Pyx_GIVEREF(__pyx_t_2);
+    __pyx_t_2 = 0;
+    __pyx_t_2 = PyObject_Call(__pyx_builtin_IOError, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 104; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+    __Pyx_Raise(__pyx_t_2, 0, 0);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
     {__pyx_filename = __pyx_f[0]; __pyx_lineno = 104; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     goto __pyx_L6;
   }
@@ -1093,7 +1267,7 @@ static int __pyx_pf_6imposm_5cache_2tc_3BDB_1__init__(PyObject *__pyx_v_self, Py
 
   /* "imposm/cache/tc.pyx":105
  *         if not tcbdbopen(self.db, filename, _modes[mode]):
- *             raise IOError
+ *             raise IOError(tcbdbecode(self.db))
  *         self._opened = 1             # <<<<<<<<<<<<<<
  * 
  *     def _tune_db(self, estimated_records):
@@ -1304,7 +1478,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_3get(PyObject *__pyx_v_self, P
  *         if not ret: return None
  *         return self._obj(osmid, PyMarshal_ReadObjectFromString(<char *>ret, ret_size))             # <<<<<<<<<<<<<<
  * 
- *     cdef object _obj(self, int64_t osmid, data):
+ *     def get_raw(self, int64_t osmid):
  */
   __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;}
@@ -1332,118 +1506,76 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_3get(PyObject *__pyx_v_self, P
 /* "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):             # <<<<<<<<<<<<<<
+ *     def get_raw(self, int64_t osmid):             # <<<<<<<<<<<<<<
  *         """
- *         Return an iterator over the database.
+ *         Return object with given id.
  */
 
-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) {
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_4get_raw(PyObject *__pyx_v_self, PyObject *__pyx_arg_osmid); /*proto*/
+static char __pyx_doc_6imposm_5cache_2tc_3BDB_4get_raw[] = "\n        Return object with given id.\n        Returns None if id is not stored.\n        ";
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_4get_raw(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("__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_RefNannySetupContext("get_raw");
+  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 = 128; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   }
-  __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);
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.BDB.get_raw");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
 
-  /* "imposm/cache/tc.pyx":143
- *             tcbdbcurdel(self._cur)
- *         self._cur = tcbdbcurnew(self.db)
- *         if not tcbdbcurfirst(self._cur):             # <<<<<<<<<<<<<<
- *             return iter([])
- *         return self
+  /* "imposm/cache/tc.pyx":135
+ *         cdef void *ret
+ *         cdef int ret_size
+ *         ret = tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)             # <<<<<<<<<<<<<<
+ *         if not ret: return None
+ *         return PyString_FromStringAndSize(<char *>ret, ret_size)
  */
-  __pyx_t_1 = (!tcbdbcurfirst(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->_cur));
-  if (__pyx_t_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":144
- *         self._cur = tcbdbcurnew(self.db)
- *         if not tcbdbcurfirst(self._cur):
- *             return iter([])             # <<<<<<<<<<<<<<
- *         return self
+  /* "imposm/cache/tc.pyx":136
+ *         cdef int ret_size
+ *         ret = tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)
+ *         if not ret: return None             # <<<<<<<<<<<<<<
+ *         return PyString_FromStringAndSize(<char *>ret, ret_size)
  * 
  */
+  __pyx_t_1 = (!(__pyx_v_ret != 0));
+  if (__pyx_t_1) {
     __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;
+    __Pyx_INCREF(Py_None);
+    __pyx_r = Py_None;
     goto __pyx_L0;
-    goto __pyx_L6;
+    goto __pyx_L5;
   }
-  __pyx_L6:;
+  __pyx_L5:;
 
-  /* "imposm/cache/tc.pyx":145
- *         if not tcbdbcurfirst(self._cur):
- *             return iter([])
- *         return self             # <<<<<<<<<<<<<<
+  /* "imposm/cache/tc.pyx":137
+ *         ret = tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)
+ *         if not ret: return None
+ *         return PyString_FromStringAndSize(<char *>ret, ret_size)             # <<<<<<<<<<<<<<
  * 
- *     def __contains__(self, int64_t osmid):
+ *     def put(self, int64_t osmid, data):
  */
   __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(__pyx_v_self);
-  __pyx_r = __pyx_v_self;
+  __pyx_t_2 = PyString_FromStringAndSize(((char *)__pyx_v_ret), __pyx_v_ret_size); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 137; __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_AddTraceback("imposm.cache.tc.BDB.__iter__");
+  __Pyx_AddTraceback("imposm.cache.tc.BDB.get_raw");
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_XGIVEREF(__pyx_r);
@@ -1451,65 +1583,406 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_4__iter__(PyObject *__pyx_v_se
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":147
- *         return self
+/* "imposm/cache/tc.pyx":139
+ *         return PyString_FromStringAndSize(<char *>ret, ret_size)
+ * 
+ *     def put(self, int64_t osmid, data):             # <<<<<<<<<<<<<<
+ *         return self.put_marshaled(osmid, PyMarshal_WriteObjectToString(data, 2))
  * 
- *     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) {
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_5put(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_5put(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
   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;}
+  PyObject *__pyx_v_data = 0;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__osmid,&__pyx_n_s__data,0};
+  __Pyx_RefNannySetupContext("put");
+  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", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __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 = 139; __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 = 139; __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 = 139; __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", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   __pyx_L3_error:;
-  __Pyx_AddTraceback("imposm.cache.tc.BDB.__contains__");
+  __Pyx_AddTraceback("imposm.cache.tc.BDB.put");
   __Pyx_RefNannyFinishContext();
-  return -1;
+  return NULL;
   __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
+  /* "imposm/cache/tc.pyx":140
+ * 
+ *     def put(self, int64_t osmid, data):
+ *         return self.put_marshaled(osmid, PyMarshal_WriteObjectToString(data, 2))             # <<<<<<<<<<<<<<
+ * 
+ *     def put_marshaled(self, int64_t osmid, data):
  */
-  __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));
+  __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 = 140; __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 = 140; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = __pyx_v_data;
+  __Pyx_INCREF(__pyx_t_3);
+  __pyx_t_4 = PyMarshal_WriteObjectToString(__pyx_t_3, 2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 140; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 140; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_3));
+  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
+  __Pyx_GIVEREF(__pyx_t_2);
+  PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_4);
+  __Pyx_GIVEREF(__pyx_t_4);
+  __pyx_t_2 = 0;
+  __pyx_t_4 = 0;
+  __pyx_t_4 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 140; __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_3)); __pyx_t_3 = 0;
+  __pyx_r = __pyx_t_4;
+  __pyx_t_4 = 0;
+  goto __pyx_L0;
 
-  /* "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) {
+  __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.BDB.put");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-    /* "imposm/cache/tc.pyx":152
- *         ret = tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size);
- *         if ret:
- *             return 1             # <<<<<<<<<<<<<<
- *         else:
- *             return 0
+/* "imposm/cache/tc.pyx":142
+ *         return self.put_marshaled(osmid, PyMarshal_WriteObjectToString(data, 2))
+ * 
+ *     def put_marshaled(self, int64_t osmid, data):             # <<<<<<<<<<<<<<
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>data, len(data))
+ * 
  */
-    __pyx_r = 1;
-    goto __pyx_L0;
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_6put_marshaled(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_6put_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 = 142; __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 = 142; __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 = 142; __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 = 142; __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 = 142; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.BDB.put_marshaled");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+
+  /* "imposm/cache/tc.pyx":143
+ * 
+ *     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_BDB *)__pyx_v_self)->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 = 143; __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 = 143; __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 = 143; __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.BDB.put_marshaled");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":145
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>data, len(data))
+ * 
+ *     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");
+
+  /* "imposm/cache/tc.pyx":150
+ *         Should be overridden by subclasses.
+ *         """
+ *         return data             # <<<<<<<<<<<<<<
+ * 
+ *     def __iter__(self):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(__pyx_v_data);
+  __pyx_r = __pyx_v_data;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":152
+ *         return data
+ * 
+ *     def __iter__(self):             # <<<<<<<<<<<<<<
+ *         """
+ *         Return an iterator over the database.
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_7__iter__(PyObject *__pyx_v_self); /*proto*/
+static char __pyx_doc_6imposm_5cache_2tc_3BDB_7__iter__[] = "\n        Return an iterator over the database.\n        Resets any existing iterator.\n        ";
+struct wrapperbase __pyx_wrapperbase_6imposm_5cache_2tc_3BDB_7__iter__;
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_7__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":157
+ *         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":158
+ *         """
+ *         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":159
+ *         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":160
+ *             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":161
+ *         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 = 161; __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 = 161; __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":162
+ *         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":164
+ *         return self
+ * 
+ *     def __contains__(self, int64_t osmid):             # <<<<<<<<<<<<<<
+ *         cdef void *ret
+ *         cdef int ret_size
+ */
+
+static int __pyx_pf_6imposm_5cache_2tc_3BDB_8__contains__(PyObject *__pyx_v_self, PyObject *__pyx_arg_osmid); /*proto*/
+static int __pyx_pf_6imposm_5cache_2tc_3BDB_8__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 = 164; __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":167
+ *         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":168
+ *         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":169
+ *         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
+    /* "imposm/cache/tc.pyx":171
  *             return 1
  *         else:
  *             return 0             # <<<<<<<<<<<<<<
@@ -1527,7 +2000,7 @@ static int __pyx_pf_6imposm_5cache_2tc_3BDB_5__contains__(PyObject *__pyx_v_self
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":156
+/* "imposm/cache/tc.pyx":173
  *             return 0
  * 
  *     def __len__(self):             # <<<<<<<<<<<<<<
@@ -1535,12 +2008,12 @@ static int __pyx_pf_6imposm_5cache_2tc_3BDB_5__contains__(PyObject *__pyx_v_self
  * 
  */
 
-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) {
+static Py_ssize_t __pyx_pf_6imposm_5cache_2tc_3BDB_9__len__(PyObject *__pyx_v_self); /*proto*/
+static Py_ssize_t __pyx_pf_6imposm_5cache_2tc_3BDB_9__len__(PyObject *__pyx_v_self) {
   Py_ssize_t __pyx_r;
   __Pyx_RefNannySetupContext("__len__");
 
-  /* "imposm/cache/tc.pyx":157
+  /* "imposm/cache/tc.pyx":174
  * 
  *     def __len__(self):
  *         return tcbdbrnum(self.db)             # <<<<<<<<<<<<<<
@@ -1556,7 +2029,7 @@ static Py_ssize_t __pyx_pf_6imposm_5cache_2tc_3BDB_6__len__(PyObject *__pyx_v_se
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":159
+/* "imposm/cache/tc.pyx":176
  *         return tcbdbrnum(self.db)
  * 
  *     def __next__(self):             # <<<<<<<<<<<<<<
@@ -1564,10 +2037,10 @@ static Py_ssize_t __pyx_pf_6imposm_5cache_2tc_3BDB_6__len__(PyObject *__pyx_v_se
  *         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) {
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_10__next__(PyObject *__pyx_v_self); /*proto*/
+static char __pyx_doc_6imposm_5cache_2tc_3BDB_10__next__[] = "\n        Return next item as object.\n        ";
+struct wrapperbase __pyx_wrapperbase_6imposm_5cache_2tc_3BDB_10__next__;
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_10__next__(PyObject *__pyx_v_self) {
   int64_t __pyx_v_osmid;
   PyObject *__pyx_v_data;
   PyObject *__pyx_r = NULL;
@@ -1580,7 +2053,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_7__next__(PyObject *__pyx_v_se
   __Pyx_RefNannySetupContext("__next__");
   __pyx_v_data = Py_None; __Pyx_INCREF(Py_None);
 
-  /* "imposm/cache/tc.pyx":165
+  /* "imposm/cache/tc.pyx":182
  *         cdef int64_t osmid
  * 
  *         if not self._cur: raise StopIteration             # <<<<<<<<<<<<<<
@@ -1590,24 +2063,24 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_7__next__(PyObject *__pyx_v_se
   __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;}
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 182; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     goto __pyx_L5;
   }
   __pyx_L5:;
 
-  /* "imposm/cache/tc.pyx":167
+  /* "imposm/cache/tc.pyx":184
  *         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_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 = 184; __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_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 = 184; __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;
@@ -1616,16 +2089,16 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_7__next__(PyObject *__pyx_v_se
     __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_t_6 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 184; __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_t_3 = __Pyx_UnpackItem(__pyx_t_6, 0); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 184; __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_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 = 184; __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_t_4 = __Pyx_UnpackItem(__pyx_t_6, 1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 184; __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;}
+    if (__Pyx_EndUnpack(__pyx_t_6, 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 184; __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);
@@ -1633,7 +2106,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_7__next__(PyObject *__pyx_v_se
     __pyx_t_4 = 0;
   }
 
-  /* "imposm/cache/tc.pyx":170
+  /* "imposm/cache/tc.pyx":187
  * 
  *         # advance cursor, set to NULL if at the end
  *         if tcbdbcurnext(self._cur) == 0:             # <<<<<<<<<<<<<<
@@ -1643,7 +2116,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_7__next__(PyObject *__pyx_v_se
   __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
+    /* "imposm/cache/tc.pyx":188
  *         # advance cursor, set to NULL if at the end
  *         if tcbdbcurnext(self._cur) == 0:
  *             tcbdbcurdel(self._cur)             # <<<<<<<<<<<<<<
@@ -1652,7 +2125,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_7__next__(PyObject *__pyx_v_se
  */
     tcbdbcurdel(((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->_cur);
 
-    /* "imposm/cache/tc.pyx":172
+    /* "imposm/cache/tc.pyx":189
  *         if tcbdbcurnext(self._cur) == 0:
  *             tcbdbcurdel(self._cur)
  *             self._cur = NULL             # <<<<<<<<<<<<<<
@@ -1664,7 +2137,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_7__next__(PyObject *__pyx_v_se
   }
   __pyx_L6:;
 
-  /* "imposm/cache/tc.pyx":175
+  /* "imposm/cache/tc.pyx":192
  * 
  *         # return objectified item
  *         return self._obj(osmid, data)             # <<<<<<<<<<<<<<
@@ -1672,7 +2145,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_7__next__(PyObject *__pyx_v_se
  *     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_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 = 192; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
   __pyx_r = __pyx_t_2;
   __pyx_t_2 = 0;
@@ -1694,7 +2167,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_7__next__(PyObject *__pyx_v_se
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":177
+/* "imposm/cache/tc.pyx":194
  *         return self._obj(osmid, data)
  * 
  *     cdef object _get_cur(self):             # <<<<<<<<<<<<<<
@@ -1713,7 +2186,7 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_3BDB__get_cur(struct __pyx_obj_6imp
   __Pyx_RefNannySetupContext("_get_cur");
   __pyx_v_value = Py_None; __Pyx_INCREF(Py_None);
 
-  /* "imposm/cache/tc.pyx":184
+  /* "imposm/cache/tc.pyx":201
  *         cdef int size
  *         cdef void *ret
  *         ret = tcbdbcurkey3(self._cur, &size)             # <<<<<<<<<<<<<<
@@ -1722,7 +2195,7 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_3BDB__get_cur(struct __pyx_obj_6imp
  */
   __pyx_v_ret = tcbdbcurkey3(__pyx_v_self->_cur, (&__pyx_v_size));
 
-  /* "imposm/cache/tc.pyx":185
+  /* "imposm/cache/tc.pyx":202
  *         cdef void *ret
  *         ret = tcbdbcurkey3(self._cur, &size)
  *         osmid = (<int64_t *>ret)[0]             # <<<<<<<<<<<<<<
@@ -1731,7 +2204,7 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_3BDB__get_cur(struct __pyx_obj_6imp
  */
   __pyx_v_osmid = (((int64_t *)__pyx_v_ret)[0]);
 
-  /* "imposm/cache/tc.pyx":186
+  /* "imposm/cache/tc.pyx":203
  *         ret = tcbdbcurkey3(self._cur, &size)
  *         osmid = (<int64_t *>ret)[0]
  *         ret = tcbdbcurval3(self._cur, &size)             # <<<<<<<<<<<<<<
@@ -1740,20 +2213,20 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_3BDB__get_cur(struct __pyx_obj_6imp
  */
   __pyx_v_ret = tcbdbcurval3(__pyx_v_self->_cur, (&__pyx_v_size));
 
-  /* "imposm/cache/tc.pyx":187
+  /* "imposm/cache/tc.pyx":204
  *         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_t_1 = PyMarshal_ReadObjectFromString(((char *)__pyx_v_ret), __pyx_v_size); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 204; __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
+  /* "imposm/cache/tc.pyx":205
  *         ret = tcbdbcurval3(self._cur, &size)
  *         value = PyMarshal_ReadObjectFromString(<char *>ret, size)
  *         return osmid, value             # <<<<<<<<<<<<<<
@@ -1761,9 +2234,9 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_3BDB__get_cur(struct __pyx_obj_6imp
  *     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_t_1 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 205; __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_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 205; __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);
@@ -1789,7 +2262,7 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_3BDB__get_cur(struct __pyx_obj_6imp
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":190
+/* "imposm/cache/tc.pyx":207
  *         return osmid, value
  * 
  *     def close(self):             # <<<<<<<<<<<<<<
@@ -1797,12 +2270,12 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_3BDB__get_cur(struct __pyx_obj_6imp
  *             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) {
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_11close(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
+static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_11close(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannySetupContext("close");
 
-  /* "imposm/cache/tc.pyx":191
+  /* "imposm/cache/tc.pyx":208
  * 
  *     def close(self):
  *         if self._opened:             # <<<<<<<<<<<<<<
@@ -1811,7 +2284,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_8close(PyObject *__pyx_v_self,
  */
   if (((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->_opened) {
 
-    /* "imposm/cache/tc.pyx":192
+    /* "imposm/cache/tc.pyx":209
  *     def close(self):
  *         if self._opened:
  *             tcbdbclose(self.db)             # <<<<<<<<<<<<<<
@@ -1823,7 +2296,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_8close(PyObject *__pyx_v_self,
   }
   __pyx_L5:;
 
-  /* "imposm/cache/tc.pyx":193
+  /* "imposm/cache/tc.pyx":210
  *         if self._opened:
  *             tcbdbclose(self.db)
  *         self._opened = 0             # <<<<<<<<<<<<<<
@@ -1838,7 +2311,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_8close(PyObject *__pyx_v_self,
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":195
+/* "imposm/cache/tc.pyx":212
  *         self._opened = 0
  * 
  *     def __dealloc__(self):             # <<<<<<<<<<<<<<
@@ -1846,11 +2319,11 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_3BDB_8close(PyObject *__pyx_v_self,
  *             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) {
+static void __pyx_pf_6imposm_5cache_2tc_3BDB_12__dealloc__(PyObject *__pyx_v_self); /*proto*/
+static void __pyx_pf_6imposm_5cache_2tc_3BDB_12__dealloc__(PyObject *__pyx_v_self) {
   __Pyx_RefNannySetupContext("__dealloc__");
 
-  /* "imposm/cache/tc.pyx":196
+  /* "imposm/cache/tc.pyx":213
  * 
  *     def __dealloc__(self):
  *         if self._opened:             # <<<<<<<<<<<<<<
@@ -1859,7 +2332,7 @@ static void __pyx_pf_6imposm_5cache_2tc_3BDB_9__dealloc__(PyObject *__pyx_v_self
  */
   if (((struct __pyx_obj_6imposm_5cache_2tc_BDB *)__pyx_v_self)->_opened) {
 
-    /* "imposm/cache/tc.pyx":197
+    /* "imposm/cache/tc.pyx":214
  *     def __dealloc__(self):
  *         if self._opened:
  *             tcbdbclose(self.db)             # <<<<<<<<<<<<<<
@@ -1871,7 +2344,7 @@ static void __pyx_pf_6imposm_5cache_2tc_3BDB_9__dealloc__(PyObject *__pyx_v_self
   }
   __pyx_L5:;
 
-  /* "imposm/cache/tc.pyx":198
+  /* "imposm/cache/tc.pyx":215
  *         if self._opened:
  *             tcbdbclose(self.db)
  *         tcbdbdel(self.db)             # <<<<<<<<<<<<<<
@@ -1883,7 +2356,7 @@ static void __pyx_pf_6imposm_5cache_2tc_3BDB_9__dealloc__(PyObject *__pyx_v_self
   __Pyx_RefNannyFinishContext();
 }
 
-/* "imposm/cache/tc.pyx":201
+/* "imposm/cache/tc.pyx":218
  * 
  * cdef class CoordDB(BDB):
  *     def put(self, osmid, x, y):             # <<<<<<<<<<<<<<
@@ -1922,17 +2395,17 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_put(PyObject *__pyx_v_self
       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;}
+        __Pyx_RaiseArgtupleInvalid("put", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 218; __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;}
+        __Pyx_RaiseArgtupleInvalid("put", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 218; __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;}
+      if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "put") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 218; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
     }
     __pyx_v_osmid = values[0];
     __pyx_v_x = values[1];
@@ -1946,14 +2419,14 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_put(PyObject *__pyx_v_self
   }
   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_RaiseArgtupleInvalid("put", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 218; __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
+  /* "imposm/cache/tc.pyx":219
  * cdef class CoordDB(BDB):
  *     def put(self, osmid, x, y):
  *         return self._put(osmid, x, y)             # <<<<<<<<<<<<<<
@@ -1961,10 +2434,10 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_put(PyObject *__pyx_v_self
  *     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_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 = 219; __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 = 219; __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 = 219; __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 = 219; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_4);
   __pyx_r = __pyx_t_4;
   __pyx_t_4 = 0;
@@ -1982,7 +2455,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_put(PyObject *__pyx_v_self
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":204
+/* "imposm/cache/tc.pyx":221
  *         return self._put(osmid, x, y)
  * 
  *     def put_marshaled(self, osmid, x, y):             # <<<<<<<<<<<<<<
@@ -2021,17 +2494,17 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_1put_marshaled(PyObject *_
       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;}
+        __Pyx_RaiseArgtupleInvalid("put_marshaled", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 221; __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;}
+        __Pyx_RaiseArgtupleInvalid("put_marshaled", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 221; __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;}
+      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 = 221; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
     }
     __pyx_v_osmid = values[0];
     __pyx_v_x = values[1];
@@ -2045,14 +2518,14 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_1put_marshaled(PyObject *_
   }
   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_RaiseArgtupleInvalid("put_marshaled", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 221; __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
+  /* "imposm/cache/tc.pyx":222
  * 
  *     def put_marshaled(self, osmid, x, y):
  *         return self._put(osmid, x, y)             # <<<<<<<<<<<<<<
@@ -2060,10 +2533,10 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_1put_marshaled(PyObject *_
  *     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_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 = 222; __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 = 222; __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 = 222; __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 = 222; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_4);
   __pyx_r = __pyx_t_4;
   __pyx_t_4 = 0;
@@ -2081,7 +2554,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_1put_marshaled(PyObject *_
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":207
+/* "imposm/cache/tc.pyx":224
  *         return self._put(osmid, x, y)
  * 
  *     cdef bint _put(self, int64_t osmid, double x, double y) nogil:             # <<<<<<<<<<<<<<
@@ -2093,7 +2566,7 @@ static  int __pyx_f_6imposm_5cache_2tc_7CoordDB__put(struct __pyx_obj_6imposm_5c
   __pyx_t_6imposm_5cache_2tc_coord __pyx_v_p;
   int __pyx_r;
 
-  /* "imposm/cache/tc.pyx":208
+  /* "imposm/cache/tc.pyx":225
  * 
  *     cdef bint _put(self, int64_t osmid, double x, double y) nogil:
  *         cdef coord p = coord_struct(x, y)             # <<<<<<<<<<<<<<
@@ -2102,7 +2575,7 @@ static  int __pyx_f_6imposm_5cache_2tc_7CoordDB__put(struct __pyx_obj_6imposm_5c
  */
   __pyx_v_p = __pyx_f_6imposm_5cache_2tc_coord_struct(__pyx_v_x, __pyx_v_y);
 
-  /* "imposm/cache/tc.pyx":209
+  /* "imposm/cache/tc.pyx":226
  *     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))             # <<<<<<<<<<<<<<
@@ -2117,7 +2590,7 @@ static  int __pyx_f_6imposm_5cache_2tc_7CoordDB__put(struct __pyx_obj_6imposm_5c
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":211
+/* "imposm/cache/tc.pyx":228
  *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>&p, sizeof(coord))
  * 
  *     def get(self, int64_t osmid):             # <<<<<<<<<<<<<<
@@ -2137,7 +2610,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_2get(PyObject *__pyx_v_sel
   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;}
+    __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 = 228; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L3_error:;
@@ -2146,7 +2619,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_2get(PyObject *__pyx_v_sel
   return NULL;
   __pyx_L4_argument_unpacking_done:;
 
-  /* "imposm/cache/tc.pyx":214
+  /* "imposm/cache/tc.pyx":231
  *         cdef coord *value
  *         cdef int ret_size
  *         value = <coord *>tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)             # <<<<<<<<<<<<<<
@@ -2155,7 +2628,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_2get(PyObject *__pyx_v_sel
  */
   __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
+  /* "imposm/cache/tc.pyx":232
  *         cdef int ret_size
  *         value = <coord *>tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)
  *         if not value: return             # <<<<<<<<<<<<<<
@@ -2171,7 +2644,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_2get(PyObject *__pyx_v_sel
   }
   __pyx_L5:;
 
-  /* "imposm/cache/tc.pyx":216
+  /* "imposm/cache/tc.pyx":233
  *         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)             # <<<<<<<<<<<<<<
@@ -2179,11 +2652,11 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_2get(PyObject *__pyx_v_sel
  *     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_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 = 233; __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_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 = 233; __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_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 233; __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);
@@ -2209,7 +2682,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_2get(PyObject *__pyx_v_sel
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":218
+/* "imposm/cache/tc.pyx":235
  *         return _uint32_to_coord(value.x), _uint32_to_coord(value.y)
  * 
  *     def get_coords(self, refs):             # <<<<<<<<<<<<<<
@@ -2235,20 +2708,20 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_3get_coords(PyObject *__py
   __Pyx_RefNannySetupContext("get_coords");
   __pyx_v_coords = ((PyObject*)Py_None); __Pyx_INCREF(Py_None);
 
-  /* "imposm/cache/tc.pyx":222
+  /* "imposm/cache/tc.pyx":239
  *         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_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 239; __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
+  /* "imposm/cache/tc.pyx":240
  *         cdef int64_t osmid
  *         coords = list()
  *         for osmid in refs:             # <<<<<<<<<<<<<<
@@ -2258,7 +2731,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_3get_coords(PyObject *__py
   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_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_refs); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 240; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_1);
   }
   for (;;) {
@@ -2271,16 +2744,16 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_3get_coords(PyObject *__py
     } 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;}
+        if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 240; __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_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 = 240; __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
+    /* "imposm/cache/tc.pyx":241
  *         coords = list()
  *         for osmid in refs:
  *             value = <coord *>tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)             # <<<<<<<<<<<<<<
@@ -2289,7 +2762,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_3get_coords(PyObject *__py
  */
     __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
+    /* "imposm/cache/tc.pyx":242
  *         for osmid in refs:
  *             value = <coord *>tcbdbget3(self.db, <char *>&osmid, sizeof(int64_t), &ret_size)
  *             if not value: return             # <<<<<<<<<<<<<<
@@ -2306,7 +2779,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_3get_coords(PyObject *__py
     }
     __pyx_L7:;
 
-    /* "imposm/cache/tc.pyx":226
+    /* "imposm/cache/tc.pyx":243
  *             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)))             # <<<<<<<<<<<<<<
@@ -2314,13 +2787,13 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_3get_coords(PyObject *__py
  *         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;} 
+      PyErr_SetString(PyExc_AttributeError, "'NoneType' object has no attribute 'append'"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 243; __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_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 = 243; __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_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 = 243; __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_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 243; __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);
@@ -2328,12 +2801,12 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_3get_coords(PyObject *__py
     __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_t_8 = PyList_Append(__pyx_v_coords, ((PyObject *)__pyx_t_7)); if (unlikely(__pyx_t_8 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 243; __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
+  /* "imposm/cache/tc.pyx":245
  *             coords.append((_uint32_to_coord(value.x), _uint32_to_coord(value.y)))
  * 
  *         return coords             # <<<<<<<<<<<<<<
@@ -2361,7 +2834,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_7CoordDB_3get_coords(PyObject *__py
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":230
+/* "imposm/cache/tc.pyx":247
  *         return coords
  * 
  *     cdef object _get_cur(self):             # <<<<<<<<<<<<<<
@@ -2381,7 +2854,7 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_7CoordDB__get_cur(struct __pyx_obj_
   PyObject *__pyx_t_4 = NULL;
   __Pyx_RefNannySetupContext("_get_cur");
 
-  /* "imposm/cache/tc.pyx":235
+  /* "imposm/cache/tc.pyx":252
  *         cdef void *ret
  *         cdef coord *value
  *         ret = tcbdbcurkey3(self._cur, &size)             # <<<<<<<<<<<<<<
@@ -2390,7 +2863,7 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_7CoordDB__get_cur(struct __pyx_obj_
  */
   __pyx_v_ret = tcbdbcurkey3(__pyx_v_self->__pyx_base._cur, (&__pyx_v_size));
 
-  /* "imposm/cache/tc.pyx":236
+  /* "imposm/cache/tc.pyx":253
  *         cdef coord *value
  *         ret = tcbdbcurkey3(self._cur, &size)
  *         osmid = (<int64_t *>ret)[0]             # <<<<<<<<<<<<<<
@@ -2399,7 +2872,7 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_7CoordDB__get_cur(struct __pyx_obj_
  */
   __pyx_v_osmid = (((int64_t *)__pyx_v_ret)[0]);
 
-  /* "imposm/cache/tc.pyx":237
+  /* "imposm/cache/tc.pyx":254
  *         ret = tcbdbcurkey3(self._cur, &size)
  *         osmid = (<int64_t *>ret)[0]
  *         value = <coord *>tcbdbcurval3(self._cur, &size)             # <<<<<<<<<<<<<<
@@ -2408,7 +2881,7 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_7CoordDB__get_cur(struct __pyx_obj_
  */
   __pyx_v_value = ((__pyx_t_6imposm_5cache_2tc_coord *)tcbdbcurval3(__pyx_v_self->__pyx_base._cur, (&__pyx_v_size)));
 
-  /* "imposm/cache/tc.pyx":238
+  /* "imposm/cache/tc.pyx":255
  *         osmid = (<int64_t *>ret)[0]
  *         value = <coord *>tcbdbcurval3(self._cur, &size)
  *         return osmid, (_uint32_to_coord(value.x), _uint32_to_coord(value.y))             # <<<<<<<<<<<<<<
@@ -2416,13 +2889,13 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_7CoordDB__get_cur(struct __pyx_obj_
  *     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_t_1 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 255; __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_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 = 255; __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_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 = 255; __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_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 255; __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);
@@ -2430,7 +2903,7 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_7CoordDB__get_cur(struct __pyx_obj_
   __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_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 255; __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);
@@ -2457,7 +2930,7 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_7CoordDB__get_cur(struct __pyx_obj_
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":240
+/* "imposm/cache/tc.pyx":257
  *         return osmid, (_uint32_to_coord(value.x), _uint32_to_coord(value.y))
  * 
  *     cdef object _obj(self, int64_t osmid, data):             # <<<<<<<<<<<<<<
@@ -2471,7 +2944,7 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_7CoordDB__obj(struct __pyx_obj_6imp
   PyObject *__pyx_t_2 = NULL;
   __Pyx_RefNannySetupContext("_obj");
 
-  /* "imposm/cache/tc.pyx":241
+  /* "imposm/cache/tc.pyx":258
  * 
  *     cdef object _obj(self, int64_t osmid, data):
  *         return osmid, data             # <<<<<<<<<<<<<<
@@ -2479,9 +2952,9 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_7CoordDB__obj(struct __pyx_obj_6imp
  * 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_t_1 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); 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 = 241; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __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));
   PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1);
   __Pyx_GIVEREF(__pyx_t_1);
@@ -2506,7 +2979,7 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_7CoordDB__obj(struct __pyx_obj_6imp
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":244
+/* "imposm/cache/tc.pyx":261
  * 
  * cdef class NodeDB(BDB):
  *     def put(self, osmid, tags, pos):             # <<<<<<<<<<<<<<
@@ -2544,17 +3017,17 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_6NodeDB_put(PyObject *__pyx_v_self,
       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;}
+        __Pyx_RaiseArgtupleInvalid("put", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 261; __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;}
+        __Pyx_RaiseArgtupleInvalid("put", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 261; __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;}
+      if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "put") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 261; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
     }
     __pyx_v_osmid = values[0];
     __pyx_v_tags = values[1];
@@ -2568,14 +3041,14 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_6NodeDB_put(PyObject *__pyx_v_self,
   }
   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_RaiseArgtupleInvalid("put", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 261; __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
+  /* "imposm/cache/tc.pyx":262
  * cdef class NodeDB(BDB):
  *     def put(self, osmid, tags, pos):
  *         return self.put_marshaled(osmid, PyMarshal_WriteObjectToString((tags, pos), 2))             # <<<<<<<<<<<<<<
@@ -2583,9 +3056,9 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_6NodeDB_put(PyObject *__pyx_v_self,
  *     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_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__put_marshaled); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 262; __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_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 262; __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);
@@ -2593,10 +3066,10 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_6NodeDB_put(PyObject *__pyx_v_self,
   __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_t_3 = PyMarshal_WriteObjectToString(((PyObject *)__pyx_t_2), 2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 262; __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_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 262; __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);
@@ -2604,7 +3077,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_6NodeDB_put(PyObject *__pyx_v_self,
   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_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 262; __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;
@@ -2626,7 +3099,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_6NodeDB_put(PyObject *__pyx_v_self,
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":247
+/* "imposm/cache/tc.pyx":264
  *         return self.put_marshaled(osmid, PyMarshal_WriteObjectToString((tags, pos), 2))
  * 
  *     def put_marshaled(self, int64_t osmid, data):             # <<<<<<<<<<<<<<
@@ -2666,30 +3139,30 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_6NodeDB_1put_marshaled(PyObject *__
       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;}
+        __Pyx_RaiseArgtupleInvalid("put_marshaled", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 264; __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;}
+      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 = 264; __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_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 = 264; __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_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 = 264; __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_RaiseArgtupleInvalid("put_marshaled", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 264; __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
+  /* "imposm/cache/tc.pyx":265
  * 
  *     def put_marshaled(self, int64_t osmid, data):
  *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>data, len(data))             # <<<<<<<<<<<<<<
@@ -2700,13 +3173,13 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_6NodeDB_1put_marshaled(PyObject *__
   __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_4 = PyBytes_AsString(__pyx_v_data); if (unlikely((!__pyx_t_4) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 265; __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_t_7 = PyObject_Length(__pyx_t_6); if (unlikely(__pyx_t_7 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 265; __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_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 = 265; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_6);
   __pyx_r = __pyx_t_6;
   __pyx_t_6 = 0;
@@ -2724,7 +3197,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_6NodeDB_1put_marshaled(PyObject *__
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":250
+/* "imposm/cache/tc.pyx":267
  *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>data, len(data))
  * 
  *     cdef object _obj(self, int64_t osmid, data):             # <<<<<<<<<<<<<<
@@ -2741,23 +3214,23 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_6NodeDB__obj(struct __pyx_obj_6impo
   PyObject *__pyx_t_5 = NULL;
   __Pyx_RefNannySetupContext("_obj");
 
-  /* "imposm/cache/tc.pyx":251
+  /* "imposm/cache/tc.pyx":268
  * 
  *     cdef object _obj(self, int64_t osmid, data):
  *         return Node(osmid, data[0], data[1])             # <<<<<<<<<<<<<<
  * 
- * cdef class RefTagDB(BDB):
+ * cdef class InsertedWayDB(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_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s__Node); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 268; __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_t_2 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 268; __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_t_3 = __Pyx_GetItemInt(__pyx_v_data, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 268; __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_t_4 = __Pyx_GetItemInt(__pyx_v_data, 1, sizeof(long), PyInt_FromLong); if (!__pyx_t_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 268; __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_t_5 = PyTuple_New(3); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 268; __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);
@@ -2768,7 +3241,7 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_6NodeDB__obj(struct __pyx_obj_6impo
   __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_t_4 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 268; __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;
@@ -2792,7 +3265,167 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_6NodeDB__obj(struct __pyx_obj_6impo
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":257
+/* "imposm/cache/tc.pyx":271
+ * 
+ * cdef class InsertedWayDB(BDB):
+ *     def put(self, int64_t osmid):             # <<<<<<<<<<<<<<
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), 'x', 1);
+ * 
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13InsertedWayDB_put(PyObject *__pyx_v_self, PyObject *__pyx_arg_osmid); /*proto*/
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13InsertedWayDB_put(PyObject *__pyx_v_self, PyObject *__pyx_arg_osmid) {
+  int64_t __pyx_v_osmid;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  __Pyx_RefNannySetupContext("put");
+  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 = 271; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.InsertedWayDB.put");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+
+  /* "imposm/cache/tc.pyx":272
+ * cdef class InsertedWayDB(BDB):
+ *     def put(self, int64_t osmid):
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), 'x', 1);             # <<<<<<<<<<<<<<
+ * 
+ *     def __next__(self):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = __Pyx_PyBool_FromLong(tcbdbput(((struct __pyx_obj_6imposm_5cache_2tc_InsertedWayDB *)__pyx_v_self)->__pyx_base.db, ((char *)(&__pyx_v_osmid)), (sizeof(int64_t)), __pyx_k__x, 1)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 272; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_r = __pyx_t_1;
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("imposm.cache.tc.InsertedWayDB.put");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":274
+ *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), 'x', 1);
+ * 
+ *     def __next__(self):             # <<<<<<<<<<<<<<
+ *         """
+ *         Return next item as object.
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13InsertedWayDB_1__next__(PyObject *__pyx_v_self); /*proto*/
+static char __pyx_doc_6imposm_5cache_2tc_13InsertedWayDB_1__next__[] = "\n        Return next item as object.\n        ";
+struct wrapperbase __pyx_wrapperbase_6imposm_5cache_2tc_13InsertedWayDB_1__next__;
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13InsertedWayDB_1__next__(PyObject *__pyx_v_self) {
+  int64_t __pyx_v_osmid;
+  int __pyx_v_size;
+  void *__pyx_v_ret;
+  PyObject *__pyx_r = NULL;
+  int __pyx_t_1;
+  PyObject *__pyx_t_2 = NULL;
+  __Pyx_RefNannySetupContext("__next__");
+
+  /* "imposm/cache/tc.pyx":282
+ *         cdef void *ret
+ * 
+ *         if not self._cur: raise StopIteration             # <<<<<<<<<<<<<<
+ * 
+ *         ret = tcbdbcurkey3(self._cur, &size)
+ */
+  __pyx_t_1 = (!(((struct __pyx_obj_6imposm_5cache_2tc_InsertedWayDB *)__pyx_v_self)->__pyx_base._cur != 0));
+  if (__pyx_t_1) {
+    __Pyx_Raise(__pyx_builtin_StopIteration, 0, 0);
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 282; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  /* "imposm/cache/tc.pyx":284
+ *         if not self._cur: raise StopIteration
+ * 
+ *         ret = tcbdbcurkey3(self._cur, &size)             # <<<<<<<<<<<<<<
+ *         osmid = (<int64_t *>ret)[0]
+ * 
+ */
+  __pyx_v_ret = tcbdbcurkey3(((struct __pyx_obj_6imposm_5cache_2tc_InsertedWayDB *)__pyx_v_self)->__pyx_base._cur, (&__pyx_v_size));
+
+  /* "imposm/cache/tc.pyx":285
+ * 
+ *         ret = tcbdbcurkey3(self._cur, &size)
+ *         osmid = (<int64_t *>ret)[0]             # <<<<<<<<<<<<<<
+ * 
+ *         # advance cursor, set to NULL if at the end
+ */
+  __pyx_v_osmid = (((int64_t *)__pyx_v_ret)[0]);
+
+  /* "imposm/cache/tc.pyx":288
+ * 
+ *         # 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_InsertedWayDB *)__pyx_v_self)->__pyx_base._cur) == 0);
+  if (__pyx_t_1) {
+
+    /* "imposm/cache/tc.pyx":289
+ *         # 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_InsertedWayDB *)__pyx_v_self)->__pyx_base._cur);
+
+    /* "imposm/cache/tc.pyx":290
+ *         if tcbdbcurnext(self._cur) == 0:
+ *             tcbdbcurdel(self._cur)
+ *             self._cur = NULL             # <<<<<<<<<<<<<<
+ * 
+ *         return osmid
+ */
+    ((struct __pyx_obj_6imposm_5cache_2tc_InsertedWayDB *)__pyx_v_self)->__pyx_base._cur = NULL;
+    goto __pyx_L6;
+  }
+  __pyx_L6:;
+
+  /* "imposm/cache/tc.pyx":292
+ *             self._cur = NULL
+ * 
+ *         return osmid             # <<<<<<<<<<<<<<
+ * 
+ * cdef class RefTagDB(BDB):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_2 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 292; __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_AddTraceback("imposm.cache.tc.InsertedWayDB.__next__");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":298
  *     Database for items with references and tags (i.e. ways/relations).
  *     """
  *     def put(self, osmid, tags, refs):             # <<<<<<<<<<<<<<
@@ -2830,17 +3463,17 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_8RefTagDB_put(PyObject *__pyx_v_sel
       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;}
+        __Pyx_RaiseArgtupleInvalid("put", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 298; __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;}
+        __Pyx_RaiseArgtupleInvalid("put", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 298; __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;}
+      if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "put") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 298; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
     }
     __pyx_v_osmid = values[0];
     __pyx_v_tags = values[1];
@@ -2854,14 +3487,14 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_8RefTagDB_put(PyObject *__pyx_v_sel
   }
   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_RaiseArgtupleInvalid("put", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 298; __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
+  /* "imposm/cache/tc.pyx":299
  *     """
  *     def put(self, osmid, tags, refs):
  *         return self.put_marshaled(osmid, PyMarshal_WriteObjectToString((tags, refs), 2))             # <<<<<<<<<<<<<<
@@ -2869,9 +3502,9 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_8RefTagDB_put(PyObject *__pyx_v_sel
  *     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_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__put_marshaled); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 299; __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_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 299; __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);
@@ -2879,10 +3512,10 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_8RefTagDB_put(PyObject *__pyx_v_sel
   __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_t_3 = PyMarshal_WriteObjectToString(((PyObject *)__pyx_t_2), 2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 299; __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_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 299; __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);
@@ -2890,7 +3523,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_8RefTagDB_put(PyObject *__pyx_v_sel
   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_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 299; __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;
@@ -2912,7 +3545,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_8RefTagDB_put(PyObject *__pyx_v_sel
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":260
+/* "imposm/cache/tc.pyx":301
  *         return self.put_marshaled(osmid, PyMarshal_WriteObjectToString((tags, refs), 2))
  * 
  *     def put_marshaled(self, int64_t osmid, data):             # <<<<<<<<<<<<<<
@@ -2952,30 +3585,30 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_8RefTagDB_1put_marshaled(PyObject *
       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;}
+        __Pyx_RaiseArgtupleInvalid("put_marshaled", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 301; __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;}
+      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 = 301; __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_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 = 301; __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_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 = 301; __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_RaiseArgtupleInvalid("put_marshaled", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 301; __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
+  /* "imposm/cache/tc.pyx":302
  * 
  *     def put_marshaled(self, int64_t osmid, data):
  *         return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), <char *>data, len(data))             # <<<<<<<<<<<<<<
@@ -2986,13 +3619,13 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_8RefTagDB_1put_marshaled(PyObject *
   __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_4 = PyBytes_AsString(__pyx_v_data); if (unlikely((!__pyx_t_4) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 302; __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_t_7 = PyObject_Length(__pyx_t_6); if (unlikely(__pyx_t_7 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 302; __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_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 = 302; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_6);
   __pyx_r = __pyx_t_6;
   __pyx_t_6 = 0;
@@ -3010,7 +3643,7 @@ static PyObject *__pyx_pf_6imposm_5cache_2tc_8RefTagDB_1put_marshaled(PyObject *
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":264
+/* "imposm/cache/tc.pyx":305
  * 
  * cdef class WayDB(RefTagDB):
  *     cdef object _obj(self, int64_t osmid, data):             # <<<<<<<<<<<<<<
@@ -3027,7 +3660,7 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_5WayDB__obj(struct __pyx_obj_6impos
   PyObject *__pyx_t_5 = NULL;
   __Pyx_RefNannySetupContext("_obj");
 
-  /* "imposm/cache/tc.pyx":265
+  /* "imposm/cache/tc.pyx":306
  * cdef class WayDB(RefTagDB):
  *     cdef object _obj(self, int64_t osmid, data):
  *         return Way(osmid, data[0], data[1])             # <<<<<<<<<<<<<<
@@ -3035,15 +3668,15 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_5WayDB__obj(struct __pyx_obj_6impos
  * 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_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s__Way); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 306; __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_t_2 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 306; __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_t_3 = __Pyx_GetItemInt(__pyx_v_data, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 306; __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_t_4 = __Pyx_GetItemInt(__pyx_v_data, 1, sizeof(long), PyInt_FromLong); if (!__pyx_t_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 306; __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_t_5 = PyTuple_New(3); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 306; __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);
@@ -3054,7 +3687,7 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_5WayDB__obj(struct __pyx_obj_6impos
   __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_t_4 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 306; __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;
@@ -3078,66 +3711,2966 @@ static  PyObject *__pyx_f_6imposm_5cache_2tc_5WayDB__obj(struct __pyx_obj_6impos
   return __pyx_r;
 }
 
-/* "imposm/cache/tc.pyx":268
+/* "imposm/cache/tc.pyx":309
+ * 
+ * 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":310
+ * cdef class RelationDB(RefTagDB):
+ *     cdef object _obj(self, int64_t osmid, data):
+ *         return Relation(osmid, data[0], data[1])             # <<<<<<<<<<<<<<
+ * 
+ * from imposm.cache.internal import DeltaCoords as _DeltaCoords
+ */
+  __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 = 310; __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 = 310; __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 = 310; __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 = 310; __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 = 310; __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 = 310; __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;
+}
+
+/* "imposm/cache/tc.pyx":316
+ * import bisect
+ * 
+ * cdef unzip_nodes(list nodes):             # <<<<<<<<<<<<<<
+ *     cdef int64_t last_lon, last_lat, lon, lat
+ *     cdef double lon_f, lat_f
+ */
+
+static  PyObject *__pyx_f_6imposm_5cache_2tc_unzip_nodes(PyObject *__pyx_v_nodes) {
+  int64_t __pyx_v_last_lon;
+  int64_t __pyx_v_last_lat;
+  int64_t __pyx_v_lon;
+  int64_t __pyx_v_lat;
+  double __pyx_v_lon_f;
+  double __pyx_v_lat_f;
+  int64_t __pyx_v_last_id;
+  int64_t __pyx_v_id;
+  PyObject *__pyx_v_ids;
+  PyObject *__pyx_v_lons;
+  PyObject *__pyx_v_lats;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  Py_ssize_t __pyx_t_4;
+  PyObject *__pyx_t_5 = NULL;
+  PyObject *__pyx_t_6 = NULL;
+  int64_t __pyx_t_7;
+  double __pyx_t_8;
+  double __pyx_t_9;
+  PyObject *__pyx_t_10 = NULL;
+  int __pyx_t_11;
+  __Pyx_RefNannySetupContext("unzip_nodes");
+  __pyx_v_ids = ((PyObject*)Py_None); __Pyx_INCREF(Py_None);
+  __pyx_v_lons = ((PyObject*)Py_None); __Pyx_INCREF(Py_None);
+  __pyx_v_lats = ((PyObject*)Py_None); __Pyx_INCREF(Py_None);
+
+  /* "imposm/cache/tc.pyx":320
+ *     cdef double lon_f, lat_f
+ *     cdef int64_t last_id, id
+ *     ids, lons, lats = [], [], []             # <<<<<<<<<<<<<<
+ *     last_id = last_lon = last_lat = 0
+ *     for id, lon_f, lat_f in nodes:
+ */
+  __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  __pyx_t_3 = PyList_New(0); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_3));
+  __Pyx_DECREF(((PyObject *)__pyx_v_ids));
+  __pyx_v_ids = __pyx_t_1;
+  __pyx_t_1 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_v_lons));
+  __pyx_v_lons = __pyx_t_2;
+  __pyx_t_2 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_v_lats));
+  __pyx_v_lats = __pyx_t_3;
+  __pyx_t_3 = 0;
+
+  /* "imposm/cache/tc.pyx":321
+ *     cdef int64_t last_id, id
+ *     ids, lons, lats = [], [], []
+ *     last_id = last_lon = last_lat = 0             # <<<<<<<<<<<<<<
+ *     for id, lon_f, lat_f in nodes:
+ *         lon = _coord_to_uint32(lon_f)
+ */
+  __pyx_v_last_id = 0;
+  __pyx_v_last_lon = 0;
+  __pyx_v_last_lat = 0;
+
+  /* "imposm/cache/tc.pyx":322
+ *     ids, lons, lats = [], [], []
+ *     last_id = last_lon = last_lat = 0
+ *     for id, lon_f, lat_f in nodes:             # <<<<<<<<<<<<<<
+ *         lon = _coord_to_uint32(lon_f)
+ *         lat = _coord_to_uint32(lat_f)
+ */
+  if (unlikely(__pyx_v_nodes == Py_None)) {
+    PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 
+  }
+  __pyx_t_4 = 0; __pyx_t_3 = ((PyObject *)__pyx_v_nodes); __Pyx_INCREF(__pyx_t_3);
+  for (;;) {
+    if (__pyx_t_4 >= PyList_GET_SIZE(__pyx_t_3)) break;
+    __pyx_t_2 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_4); __Pyx_INCREF(__pyx_t_2); __pyx_t_4++;
+    if (PyTuple_CheckExact(__pyx_t_2) && likely(PyTuple_GET_SIZE(__pyx_t_2) == 3)) {
+      PyObject* tuple = __pyx_t_2;
+      __pyx_t_1 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_1);
+      __pyx_t_7 = __Pyx_PyInt_from_py_int64_t(__pyx_t_1); if (unlikely((__pyx_t_7 == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+      __pyx_t_5 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_5);
+      __pyx_t_8 = __pyx_PyFloat_AsDouble(__pyx_t_5); if (unlikely((__pyx_t_8 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+      __pyx_t_6 = PyTuple_GET_ITEM(tuple, 2); __Pyx_INCREF(__pyx_t_6);
+      __pyx_t_9 = __pyx_PyFloat_AsDouble(__pyx_t_6); if (unlikely((__pyx_t_9 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+      __pyx_v_id = __pyx_t_7;
+      __pyx_v_lon_f = __pyx_t_8;
+      __pyx_v_lat_f = __pyx_t_9;
+    } else {
+      __pyx_t_10 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_10);
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+      __pyx_t_1 = __Pyx_UnpackItem(__pyx_t_10, 0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_1);
+      __pyx_t_7 = __Pyx_PyInt_from_py_int64_t(__pyx_t_1); if (unlikely((__pyx_t_7 == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+      __pyx_t_5 = __Pyx_UnpackItem(__pyx_t_10, 1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_5);
+      __pyx_t_9 = __pyx_PyFloat_AsDouble(__pyx_t_5); if (unlikely((__pyx_t_9 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+      __pyx_t_6 = __Pyx_UnpackItem(__pyx_t_10, 2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_6);
+      __pyx_t_8 = __pyx_PyFloat_AsDouble(__pyx_t_6); if (unlikely((__pyx_t_8 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+      if (__Pyx_EndUnpack(__pyx_t_10, 3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+      __pyx_v_id = __pyx_t_7;
+      __pyx_v_lon_f = __pyx_t_9;
+      __pyx_v_lat_f = __pyx_t_8;
+    }
+
+    /* "imposm/cache/tc.pyx":323
+ *     last_id = last_lon = last_lat = 0
+ *     for id, lon_f, lat_f in nodes:
+ *         lon = _coord_to_uint32(lon_f)             # <<<<<<<<<<<<<<
+ *         lat = _coord_to_uint32(lat_f)
+ * 
+ */
+    __pyx_v_lon = __pyx_f_6imposm_5cache_2tc__coord_to_uint32(__pyx_v_lon_f);
+
+    /* "imposm/cache/tc.pyx":324
+ *     for id, lon_f, lat_f in nodes:
+ *         lon = _coord_to_uint32(lon_f)
+ *         lat = _coord_to_uint32(lat_f)             # <<<<<<<<<<<<<<
+ * 
+ *         ids.append(id - last_id)
+ */
+    __pyx_v_lat = __pyx_f_6imposm_5cache_2tc__coord_to_uint32(__pyx_v_lat_f);
+
+    /* "imposm/cache/tc.pyx":326
+ *         lat = _coord_to_uint32(lat_f)
+ * 
+ *         ids.append(id - last_id)             # <<<<<<<<<<<<<<
+ *         lons.append(lon - last_lon)
+ *         lats.append(lat - last_lat)
+ */
+    if (unlikely(__pyx_v_ids == Py_None)) {
+      PyErr_SetString(PyExc_AttributeError, "'NoneType' object has no attribute 'append'"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 
+    }
+    __pyx_t_2 = __Pyx_PyInt_to_py_int64_t((__pyx_v_id - __pyx_v_last_id)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_11 = PyList_Append(__pyx_v_ids, __pyx_t_2); if (unlikely(__pyx_t_11 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+    /* "imposm/cache/tc.pyx":327
+ * 
+ *         ids.append(id - last_id)
+ *         lons.append(lon - last_lon)             # <<<<<<<<<<<<<<
+ *         lats.append(lat - last_lat)
+ *         last_id = id
+ */
+    if (unlikely(__pyx_v_lons == Py_None)) {
+      PyErr_SetString(PyExc_AttributeError, "'NoneType' object has no attribute 'append'"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 327; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 
+    }
+    __pyx_t_2 = __Pyx_PyInt_to_py_int64_t((__pyx_v_lon - __pyx_v_last_lon)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 327; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_11 = PyList_Append(__pyx_v_lons, __pyx_t_2); if (unlikely(__pyx_t_11 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 327; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+    /* "imposm/cache/tc.pyx":328
+ *         ids.append(id - last_id)
+ *         lons.append(lon - last_lon)
+ *         lats.append(lat - last_lat)             # <<<<<<<<<<<<<<
+ *         last_id = id
+ *         last_lon = lon
+ */
+    if (unlikely(__pyx_v_lats == Py_None)) {
+      PyErr_SetString(PyExc_AttributeError, "'NoneType' object has no attribute 'append'"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 328; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 
+    }
+    __pyx_t_2 = __Pyx_PyInt_to_py_int64_t((__pyx_v_lat - __pyx_v_last_lat)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 328; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_11 = PyList_Append(__pyx_v_lats, __pyx_t_2); if (unlikely(__pyx_t_11 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 328; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+    /* "imposm/cache/tc.pyx":329
+ *         lons.append(lon - last_lon)
+ *         lats.append(lat - last_lat)
+ *         last_id = id             # <<<<<<<<<<<<<<
+ *         last_lon = lon
+ *         last_lat = lat
+ */
+    __pyx_v_last_id = __pyx_v_id;
+
+    /* "imposm/cache/tc.pyx":330
+ *         lats.append(lat - last_lat)
+ *         last_id = id
+ *         last_lon = lon             # <<<<<<<<<<<<<<
+ *         last_lat = lat
+ * 
+ */
+    __pyx_v_last_lon = __pyx_v_lon;
+
+    /* "imposm/cache/tc.pyx":331
+ *         last_id = id
+ *         last_lon = lon
+ *         last_lat = lat             # <<<<<<<<<<<<<<
+ * 
+ *     return ids, lons, lats
+ */
+    __pyx_v_last_lat = __pyx_v_lat;
+  }
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+
+  /* "imposm/cache/tc.pyx":333
+ *         last_lat = lat
+ * 
+ *     return ids, lons, lats             # <<<<<<<<<<<<<<
+ * 
+ * cdef zip_nodes(tuple ids, tuple lons, tuple lats):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 333; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_3));
+  __Pyx_INCREF(((PyObject *)__pyx_v_ids));
+  PyTuple_SET_ITEM(__pyx_t_3, 0, ((PyObject *)__pyx_v_ids));
+  __Pyx_GIVEREF(((PyObject *)__pyx_v_ids));
+  __Pyx_INCREF(((PyObject *)__pyx_v_lons));
+  PyTuple_SET_ITEM(__pyx_t_3, 1, ((PyObject *)__pyx_v_lons));
+  __Pyx_GIVEREF(((PyObject *)__pyx_v_lons));
+  __Pyx_INCREF(((PyObject *)__pyx_v_lats));
+  PyTuple_SET_ITEM(__pyx_t_3, 2, ((PyObject *)__pyx_v_lats));
+  __Pyx_GIVEREF(((PyObject *)__pyx_v_lats));
+  __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_5);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_XDECREF(__pyx_t_10);
+  __Pyx_AddTraceback("imposm.cache.tc.unzip_nodes");
+  __pyx_r = 0;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_ids);
+  __Pyx_DECREF(__pyx_v_lons);
+  __Pyx_DECREF(__pyx_v_lats);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":335
+ *     return ids, lons, lats
+ * 
+ * cdef zip_nodes(tuple ids, tuple lons, tuple lats):             # <<<<<<<<<<<<<<
+ *     cdef uint32_t last_lon, last_lat
+ *     cdef int64_t last_id
+ */
+
+static  PyObject *__pyx_f_6imposm_5cache_2tc_zip_nodes(PyObject *__pyx_v_ids, PyObject *__pyx_v_lons, PyObject *__pyx_v_lats) {
+  uint32_t __pyx_v_last_lon;
+  uint32_t __pyx_v_last_lat;
+  int64_t __pyx_v_last_id;
+  PyObject *__pyx_v_nodes;
+  Py_ssize_t __pyx_v_i;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  Py_ssize_t __pyx_t_2;
+  Py_ssize_t __pyx_t_3;
+  PyObject *__pyx_t_4 = NULL;
+  PyObject *__pyx_t_5 = NULL;
+  int64_t __pyx_t_6;
+  uint32_t __pyx_t_7;
+  PyObject *__pyx_t_8 = NULL;
+  int __pyx_t_9;
+  __Pyx_RefNannySetupContext("zip_nodes");
+  __pyx_v_nodes = ((PyObject*)Py_None); __Pyx_INCREF(Py_None);
+
+  /* "imposm/cache/tc.pyx":338
+ *     cdef uint32_t last_lon, last_lat
+ *     cdef int64_t last_id
+ *     nodes = []             # <<<<<<<<<<<<<<
+ *     last_id = last_lon = last_lat = 0
+ * 
+ */
+  __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 338; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __Pyx_DECREF(((PyObject *)__pyx_v_nodes));
+  __pyx_v_nodes = __pyx_t_1;
+  __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":339
+ *     cdef int64_t last_id
+ *     nodes = []
+ *     last_id = last_lon = last_lat = 0             # <<<<<<<<<<<<<<
+ * 
+ *     for i in range(len(ids)):
+ */
+  __pyx_v_last_id = 0;
+  __pyx_v_last_lon = 0;
+  __pyx_v_last_lat = 0;
+
+  /* "imposm/cache/tc.pyx":341
+ *     last_id = last_lon = last_lat = 0
+ * 
+ *     for i in range(len(ids)):             # <<<<<<<<<<<<<<
+ *         last_id += ids[i]
+ *         last_lon += lons[i]
+ */
+  __pyx_t_1 = ((PyObject *)__pyx_v_ids);
+  __Pyx_INCREF(__pyx_t_1);
+  if (unlikely(__pyx_t_1 == Py_None)) {
+    PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 341; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 
+  }
+  __pyx_t_2 = PyTuple_GET_SIZE(__pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
+    __pyx_v_i = __pyx_t_3;
+
+    /* "imposm/cache/tc.pyx":342
+ * 
+ *     for i in range(len(ids)):
+ *         last_id += ids[i]             # <<<<<<<<<<<<<<
+ *         last_lon += lons[i]
+ *         last_lat += lats[i]
+ */
+    __pyx_t_1 = __Pyx_PyInt_to_py_int64_t(__pyx_v_last_id); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 342; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_4 = __Pyx_GetItemInt_Tuple(((PyObject *)__pyx_v_ids), __pyx_v_i, sizeof(Py_ssize_t), PyInt_FromSsize_t); if (!__pyx_t_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 342; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_5 = PyNumber_InPlaceAdd(__pyx_t_1, __pyx_t_4); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 342; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_5);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __pyx_t_6 = __Pyx_PyInt_from_py_int64_t(__pyx_t_5); if (unlikely((__pyx_t_6 == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 342; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+    __pyx_v_last_id = __pyx_t_6;
+
+    /* "imposm/cache/tc.pyx":343
+ *     for i in range(len(ids)):
+ *         last_id += ids[i]
+ *         last_lon += lons[i]             # <<<<<<<<<<<<<<
+ *         last_lat += lats[i]
+ * 
+ */
+    __pyx_t_5 = __Pyx_PyInt_to_py_uint32_t(__pyx_v_last_lon); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 343; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_5);
+    __pyx_t_4 = __Pyx_GetItemInt_Tuple(((PyObject *)__pyx_v_lons), __pyx_v_i, sizeof(Py_ssize_t), PyInt_FromSsize_t); if (!__pyx_t_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 343; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_1 = PyNumber_InPlaceAdd(__pyx_t_5, __pyx_t_4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 343; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __pyx_t_7 = __Pyx_PyInt_from_py_uint32_t(__pyx_t_1); if (unlikely((__pyx_t_7 == (uint32_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 343; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __pyx_v_last_lon = __pyx_t_7;
+
+    /* "imposm/cache/tc.pyx":344
+ *         last_id += ids[i]
+ *         last_lon += lons[i]
+ *         last_lat += lats[i]             # <<<<<<<<<<<<<<
+ * 
+ *         nodes.append((
+ */
+    __pyx_t_1 = __Pyx_PyInt_to_py_uint32_t(__pyx_v_last_lat); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 344; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_4 = __Pyx_GetItemInt_Tuple(((PyObject *)__pyx_v_lats), __pyx_v_i, sizeof(Py_ssize_t), PyInt_FromSsize_t); if (!__pyx_t_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 344; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_5 = PyNumber_InPlaceAdd(__pyx_t_1, __pyx_t_4); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 344; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_5);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __pyx_t_7 = __Pyx_PyInt_from_py_uint32_t(__pyx_t_5); if (unlikely((__pyx_t_7 == (uint32_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 344; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+    __pyx_v_last_lat = __pyx_t_7;
+
+    /* "imposm/cache/tc.pyx":346
+ *         last_lat += lats[i]
+ * 
+ *         nodes.append((             # <<<<<<<<<<<<<<
+ *             last_id,
+ *             _uint32_to_coord(last_lon),
+ */
+    if (unlikely(__pyx_v_nodes == Py_None)) {
+      PyErr_SetString(PyExc_AttributeError, "'NoneType' object has no attribute 'append'"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 346; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 
+    }
+
+    /* "imposm/cache/tc.pyx":347
+ * 
+ *         nodes.append((
+ *             last_id,             # <<<<<<<<<<<<<<
+ *             _uint32_to_coord(last_lon),
+ *             _uint32_to_coord(last_lat)
+ */
+    __pyx_t_5 = __Pyx_PyInt_to_py_int64_t(__pyx_v_last_id); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 347; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_5);
+
+    /* "imposm/cache/tc.pyx":348
+ *         nodes.append((
+ *             last_id,
+ *             _uint32_to_coord(last_lon),             # <<<<<<<<<<<<<<
+ *             _uint32_to_coord(last_lat)
+ *         ))
+ */
+    __pyx_t_4 = PyFloat_FromDouble(__pyx_f_6imposm_5cache_2tc__uint32_to_coord(__pyx_v_last_lon)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 348; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+
+    /* "imposm/cache/tc.pyx":349
+ *             last_id,
+ *             _uint32_to_coord(last_lon),
+ *             _uint32_to_coord(last_lat)             # <<<<<<<<<<<<<<
+ *         ))
+ *     return nodes
+ */
+    __pyx_t_1 = PyFloat_FromDouble(__pyx_f_6imposm_5cache_2tc__uint32_to_coord(__pyx_v_last_lat)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 349; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_8 = PyTuple_New(3); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 347; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_8));
+    PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_5);
+    __Pyx_GIVEREF(__pyx_t_5);
+    PyTuple_SET_ITEM(__pyx_t_8, 1, __pyx_t_4);
+    __Pyx_GIVEREF(__pyx_t_4);
+    PyTuple_SET_ITEM(__pyx_t_8, 2, __pyx_t_1);
+    __Pyx_GIVEREF(__pyx_t_1);
+    __pyx_t_5 = 0;
+    __pyx_t_4 = 0;
+    __pyx_t_1 = 0;
+    __pyx_t_9 = PyList_Append(__pyx_v_nodes, ((PyObject *)__pyx_t_8)); if (unlikely(__pyx_t_9 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 346; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(((PyObject *)__pyx_t_8)); __pyx_t_8 = 0;
+  }
+
+  /* "imposm/cache/tc.pyx":351
+ *             _uint32_to_coord(last_lat)
+ *         ))
+ *     return nodes             # <<<<<<<<<<<<<<
+ * 
+ * class DeltaNodes(object):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_nodes));
+  __pyx_r = ((PyObject *)__pyx_v_nodes);
+  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_4);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_XDECREF(__pyx_t_8);
+  __Pyx_AddTraceback("imposm.cache.tc.zip_nodes");
+  __pyx_r = 0;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_nodes);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":354
+ * 
+ * class DeltaNodes(object):
+ *     def __init__(self, data=None):             # <<<<<<<<<<<<<<
+ *         self.nodes = []
+ *         self.changed = False
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_10DeltaNodes___init__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyMethodDef __pyx_mdef_6imposm_5cache_2tc_10DeltaNodes___init__ = {__Pyx_NAMESTR("__init__"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_10DeltaNodes___init__, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pf_6imposm_5cache_2tc_10DeltaNodes___init__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_self = 0;
+  PyObject *__pyx_v_data = 0;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__self,&__pyx_n_s__data,0};
+  __Pyx_RefNannySetupContext("__init__");
+  __pyx_self = __pyx_self;
+  if (unlikely(__pyx_kwds)) {
+    Py_ssize_t kw_args = PyDict_Size(__pyx_kwds);
+    PyObject* values[2] = {0,0};
+    values[1] = ((PyObject *)Py_None);
+    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__self);
+      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__data);
+        if (value) { values[1] = 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 = 354; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_self = values[0];
+    __pyx_v_data = values[1];
+  } else {
+    __pyx_v_data = ((PyObject *)Py_None);
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  2: __pyx_v_data = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: __pyx_v_self = 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, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 354; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaNodes.__init__");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+
+  /* "imposm/cache/tc.pyx":355
+ * class DeltaNodes(object):
+ *     def __init__(self, data=None):
+ *         self.nodes = []             # <<<<<<<<<<<<<<
+ *         self.changed = False
+ *         if data:
+ */
+  __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 355; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__nodes, ((PyObject *)__pyx_t_1)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 355; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":356
+ *     def __init__(self, data=None):
+ *         self.nodes = []
+ *         self.changed = False             # <<<<<<<<<<<<<<
+ *         if data:
+ *             self.deserialize(data)
+ */
+  __pyx_t_1 = __Pyx_PyBool_FromLong(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 356; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__changed, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 356; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":357
+ *         self.nodes = []
+ *         self.changed = False
+ *         if data:             # <<<<<<<<<<<<<<
+ *             self.deserialize(data)
+ * 
+ */
+  __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_v_data); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 357; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__pyx_t_2) {
+
+    /* "imposm/cache/tc.pyx":358
+ *         self.changed = False
+ *         if data:
+ *             self.deserialize(data)             # <<<<<<<<<<<<<<
+ * 
+ *     def changed(self):
+ */
+    __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__deserialize); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 358; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 358; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_3));
+    __Pyx_INCREF(__pyx_v_data);
+    PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_data);
+    __Pyx_GIVEREF(__pyx_v_data);
+    __pyx_t_4 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 358; __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_3)); __pyx_t_3 = 0;
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    goto __pyx_L6;
+  }
+  __pyx_L6:;
+
+  __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_4);
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaNodes.__init__");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":360
+ *             self.deserialize(data)
+ * 
+ *     def changed(self):             # <<<<<<<<<<<<<<
+ *         return self.changed
+ * 
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_10DeltaNodes_1changed(PyObject *__pyx_self, PyObject *__pyx_v_self); /*proto*/
+static PyMethodDef __pyx_mdef_6imposm_5cache_2tc_10DeltaNodes_1changed = {__Pyx_NAMESTR("changed"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_10DeltaNodes_1changed, METH_O, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pf_6imposm_5cache_2tc_10DeltaNodes_1changed(PyObject *__pyx_self, PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  __Pyx_RefNannySetupContext("changed");
+  __pyx_self = __pyx_self;
+
+  /* "imposm/cache/tc.pyx":361
+ * 
+ *     def changed(self):
+ *         return self.changed             # <<<<<<<<<<<<<<
+ * 
+ *     def get(self, int64_t osmid):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__changed); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 361; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_r = __pyx_t_1;
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaNodes.changed");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":363
+ *         return self.changed
+ * 
+ *     def get(self, int64_t osmid):             # <<<<<<<<<<<<<<
+ *         i = bisect.bisect(self.nodes, (osmid, ))
+ *         if i != len(self.nodes) and self.nodes[i][0] == osmid:
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_10DeltaNodes_2get(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyMethodDef __pyx_mdef_6imposm_5cache_2tc_10DeltaNodes_2get = {__Pyx_NAMESTR("get"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_10DeltaNodes_2get, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pf_6imposm_5cache_2tc_10DeltaNodes_2get(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_self = 0;
+  int64_t __pyx_v_osmid;
+  PyObject *__pyx_v_i;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  Py_ssize_t __pyx_t_5;
+  int __pyx_t_6;
+  int __pyx_t_7;
+  int __pyx_t_8;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__self,&__pyx_n_s__osmid,0};
+  __Pyx_RefNannySetupContext("get");
+  __pyx_self = __pyx_self;
+  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__self);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__osmid);
+      if (likely(values[1])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("get", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 363; __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), "get") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 363; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_self = values[0];
+    __pyx_v_osmid = __Pyx_PyInt_from_py_int64_t(values[1]); if (unlikely((__pyx_v_osmid == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 363; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
+    goto __pyx_L5_argtuple_error;
+  } else {
+    __pyx_v_self = PyTuple_GET_ITEM(__pyx_args, 0);
+    __pyx_v_osmid = __Pyx_PyInt_from_py_int64_t(PyTuple_GET_ITEM(__pyx_args, 1)); if (unlikely((__pyx_v_osmid == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 363; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("get", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 363; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaNodes.get");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_v_i = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "imposm/cache/tc.pyx":364
+ * 
+ *     def get(self, int64_t osmid):
+ *         i = bisect.bisect(self.nodes, (osmid, ))             # <<<<<<<<<<<<<<
+ *         if i != len(self.nodes) and self.nodes[i][0] == osmid:
+ *             return self.nodes[i][1:]
+ */
+  __pyx_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s__bisect); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 364; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_GetAttr(__pyx_t_1, __pyx_n_s__bisect); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 364; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__nodes); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 364; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_3 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 364; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 364; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_4));
+  PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3);
+  __Pyx_GIVEREF(__pyx_t_3);
+  __pyx_t_3 = 0;
+  __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 364; __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_t_4 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 364; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+  __Pyx_DECREF(__pyx_v_i);
+  __pyx_v_i = __pyx_t_4;
+  __pyx_t_4 = 0;
+
+  /* "imposm/cache/tc.pyx":365
+ *     def get(self, int64_t osmid):
+ *         i = bisect.bisect(self.nodes, (osmid, ))
+ *         if i != len(self.nodes) and self.nodes[i][0] == osmid:             # <<<<<<<<<<<<<<
+ *             return self.nodes[i][1:]
+ *         return None
+ */
+  __pyx_t_4 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__nodes); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 365; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_t_5 = PyObject_Length(__pyx_t_4); if (unlikely(__pyx_t_5 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 365; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  __pyx_t_4 = PyInt_FromSsize_t(__pyx_t_5); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 365; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_t_3 = PyObject_RichCompare(__pyx_v_i, __pyx_t_4, Py_NE); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 365; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 365; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (__pyx_t_6) {
+    __pyx_t_3 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__nodes); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 365; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_4 = PyObject_GetItem(__pyx_t_3, __pyx_v_i); if (!__pyx_t_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 365; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __pyx_t_3 = __Pyx_GetItemInt(__pyx_t_4, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 365; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __pyx_t_4 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 365; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_2 = PyObject_RichCompare(__pyx_t_3, __pyx_t_4, Py_EQ); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 365; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __pyx_t_7 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_7 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 365; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    __pyx_t_8 = __pyx_t_7;
+  } else {
+    __pyx_t_8 = __pyx_t_6;
+  }
+  if (__pyx_t_8) {
+
+    /* "imposm/cache/tc.pyx":366
+ *         i = bisect.bisect(self.nodes, (osmid, ))
+ *         if i != len(self.nodes) and self.nodes[i][0] == osmid:
+ *             return self.nodes[i][1:]             # <<<<<<<<<<<<<<
+ *         return None
+ * 
+ */
+    __Pyx_XDECREF(__pyx_r);
+    __pyx_t_2 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__nodes); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 366; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_4 = PyObject_GetItem(__pyx_t_2, __pyx_v_i); if (!__pyx_t_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 366; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    __pyx_t_2 = __Pyx_PySequence_GetSlice(__pyx_t_4, 1, PY_SSIZE_T_MAX); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 366; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __pyx_r = __pyx_t_2;
+    __pyx_t_2 = 0;
+    goto __pyx_L0;
+    goto __pyx_L6;
+  }
+  __pyx_L6:;
+
+  /* "imposm/cache/tc.pyx":367
+ *         if i != len(self.nodes) and self.nodes[i][0] == osmid:
+ *             return self.nodes[i][1:]
+ *         return None             # <<<<<<<<<<<<<<
+ * 
+ *     def add(self, int64_t osmid, double lon, double lat):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(Py_None);
+  __pyx_r = Py_None;
+  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.DeltaNodes.get");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_i);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":369
+ *         return None
+ * 
+ *     def add(self, int64_t osmid, double lon, double lat):             # <<<<<<<<<<<<<<
+ *         # todo: overwrite
+ *         self.changed = True
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_10DeltaNodes_3add(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyMethodDef __pyx_mdef_6imposm_5cache_2tc_10DeltaNodes_3add = {__Pyx_NAMESTR("add"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_10DeltaNodes_3add, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pf_6imposm_5cache_2tc_10DeltaNodes_3add(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_self = 0;
+  int64_t __pyx_v_osmid;
+  double __pyx_v_lon;
+  double __pyx_v_lat;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  int __pyx_t_5;
+  int __pyx_t_6;
+  PyObject *__pyx_t_7 = NULL;
+  PyObject *__pyx_t_8 = NULL;
+  PyObject *__pyx_t_9 = NULL;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__self,&__pyx_n_s__osmid,&__pyx_n_s__lon,&__pyx_n_s__lat,0};
+  __Pyx_RefNannySetupContext("add");
+  __pyx_self = __pyx_self;
+  if (unlikely(__pyx_kwds)) {
+    Py_ssize_t kw_args = PyDict_Size(__pyx_kwds);
+    PyObject* values[4] = {0,0,0,0};
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
+      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__self);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__osmid);
+      if (likely(values[1])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("add", 1, 4, 4, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+      case  2:
+      values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__lon);
+      if (likely(values[2])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("add", 1, 4, 4, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+      case  3:
+      values[3] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__lat);
+      if (likely(values[3])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("add", 1, 4, 4, 3); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __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), "add") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_self = values[0];
+    __pyx_v_osmid = __Pyx_PyInt_from_py_int64_t(values[1]); if (unlikely((__pyx_v_osmid == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_lon = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_lon == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_lat = __pyx_PyFloat_AsDouble(values[3]); if (unlikely((__pyx_v_lat == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  } else if (PyTuple_GET_SIZE(__pyx_args) != 4) {
+    goto __pyx_L5_argtuple_error;
+  } else {
+    __pyx_v_self = PyTuple_GET_ITEM(__pyx_args, 0);
+    __pyx_v_osmid = __Pyx_PyInt_from_py_int64_t(PyTuple_GET_ITEM(__pyx_args, 1)); if (unlikely((__pyx_v_osmid == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_lon = __pyx_PyFloat_AsDouble(PyTuple_GET_ITEM(__pyx_args, 2)); if (unlikely((__pyx_v_lon == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_lat = __pyx_PyFloat_AsDouble(PyTuple_GET_ITEM(__pyx_args, 3)); if (unlikely((__pyx_v_lat == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("add", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaNodes.add");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+
+  /* "imposm/cache/tc.pyx":371
+ *     def add(self, int64_t osmid, double lon, double lat):
+ *         # todo: overwrite
+ *         self.changed = True             # <<<<<<<<<<<<<<
+ *         if self.nodes and self.nodes[-1][0] < osmid:
+ *             self.nodes.append((osmid, lon, lat))
+ */
+  __pyx_t_1 = __Pyx_PyBool_FromLong(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 371; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__changed, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 371; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":372
+ *         # todo: overwrite
+ *         self.changed = True
+ *         if self.nodes and self.nodes[-1][0] < osmid:             # <<<<<<<<<<<<<<
+ *             self.nodes.append((osmid, lon, lat))
+ *         else:
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__nodes); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 372; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 372; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (__pyx_t_2) {
+    __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__nodes); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 372; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_3 = __Pyx_GetItemInt(__pyx_t_1, -1, sizeof(long), PyInt_FromLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 372; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __pyx_t_1 = __Pyx_GetItemInt(__pyx_t_3, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 372; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __pyx_t_3 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 372; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_4 = PyObject_RichCompare(__pyx_t_1, __pyx_t_3, Py_LT); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 372; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_5 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 372; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __pyx_t_6 = __pyx_t_5;
+  } else {
+    __pyx_t_6 = __pyx_t_2;
+  }
+  if (__pyx_t_6) {
+
+    /* "imposm/cache/tc.pyx":373
+ *         self.changed = True
+ *         if self.nodes and self.nodes[-1][0] < osmid:
+ *             self.nodes.append((osmid, lon, lat))             # <<<<<<<<<<<<<<
+ *         else:
+ *             bisect.insort(self.nodes, (osmid, lon, lat))
+ */
+    __pyx_t_4 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__nodes); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 373; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_3 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 373; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_1 = PyFloat_FromDouble(__pyx_v_lon); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 373; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_7 = PyFloat_FromDouble(__pyx_v_lat); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 373; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_7);
+    __pyx_t_8 = PyTuple_New(3); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 373; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_8));
+    PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_3);
+    PyTuple_SET_ITEM(__pyx_t_8, 1, __pyx_t_1);
+    __Pyx_GIVEREF(__pyx_t_1);
+    PyTuple_SET_ITEM(__pyx_t_8, 2, __pyx_t_7);
+    __Pyx_GIVEREF(__pyx_t_7);
+    __pyx_t_3 = 0;
+    __pyx_t_1 = 0;
+    __pyx_t_7 = 0;
+    __pyx_t_7 = __Pyx_PyObject_Append(__pyx_t_4, ((PyObject *)__pyx_t_8)); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 373; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_7);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __Pyx_DECREF(((PyObject *)__pyx_t_8)); __pyx_t_8 = 0;
+    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+    goto __pyx_L6;
+  }
+  /*else*/ {
+
+    /* "imposm/cache/tc.pyx":375
+ *             self.nodes.append((osmid, lon, lat))
+ *         else:
+ *             bisect.insort(self.nodes, (osmid, lon, lat))             # <<<<<<<<<<<<<<
+ * 
+ *     def serialize(self):
+ */
+    __pyx_t_7 = __Pyx_GetName(__pyx_m, __pyx_n_s__bisect); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_7);
+    __pyx_t_8 = PyObject_GetAttr(__pyx_t_7, __pyx_n_s__insort); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_8);
+    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+    __pyx_t_7 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__nodes); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_7);
+    __pyx_t_4 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_1 = PyFloat_FromDouble(__pyx_v_lon); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_3 = PyFloat_FromDouble(__pyx_v_lat); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_9 = PyTuple_New(3); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_9));
+    PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_4);
+    __Pyx_GIVEREF(__pyx_t_4);
+    PyTuple_SET_ITEM(__pyx_t_9, 1, __pyx_t_1);
+    __Pyx_GIVEREF(__pyx_t_1);
+    PyTuple_SET_ITEM(__pyx_t_9, 2, __pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_3);
+    __pyx_t_4 = 0;
+    __pyx_t_1 = 0;
+    __pyx_t_3 = 0;
+    __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_3));
+    PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_7);
+    __Pyx_GIVEREF(__pyx_t_7);
+    PyTuple_SET_ITEM(__pyx_t_3, 1, ((PyObject *)__pyx_t_9));
+    __Pyx_GIVEREF(((PyObject *)__pyx_t_9));
+    __pyx_t_7 = 0;
+    __pyx_t_9 = 0;
+    __pyx_t_9 = PyObject_Call(__pyx_t_8, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_9);
+    __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+    __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+    __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+  }
+  __pyx_L6:;
+
+  __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_4);
+  __Pyx_XDECREF(__pyx_t_7);
+  __Pyx_XDECREF(__pyx_t_8);
+  __Pyx_XDECREF(__pyx_t_9);
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaNodes.add");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":377
+ *             bisect.insort(self.nodes, (osmid, lon, lat))
+ * 
+ *     def serialize(self):             # <<<<<<<<<<<<<<
+ *         ids, lons, lats = unzip_nodes(self.nodes)
+ *         nodes = _DeltaCoords()
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_10DeltaNodes_4serialize(PyObject *__pyx_self, PyObject *__pyx_v_self); /*proto*/
+static PyMethodDef __pyx_mdef_6imposm_5cache_2tc_10DeltaNodes_4serialize = {__Pyx_NAMESTR("serialize"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_10DeltaNodes_4serialize, METH_O, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pf_6imposm_5cache_2tc_10DeltaNodes_4serialize(PyObject *__pyx_self, PyObject *__pyx_v_self) {
+  PyObject *__pyx_v_ids;
+  PyObject *__pyx_v_lons;
+  PyObject *__pyx_v_lats;
+  PyObject *__pyx_v_nodes;
+  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("serialize");
+  __pyx_self = __pyx_self;
+  __pyx_v_ids = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_v_lons = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_v_lats = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_v_nodes = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "imposm/cache/tc.pyx":378
+ * 
+ *     def serialize(self):
+ *         ids, lons, lats = unzip_nodes(self.nodes)             # <<<<<<<<<<<<<<
+ *         nodes = _DeltaCoords()
+ *         nodes.ids = ids
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__nodes); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 378; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (!(likely(PyList_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected list, got %.200s", Py_TYPE(__pyx_t_1)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 378; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __pyx_f_6imposm_5cache_2tc_unzip_nodes(((PyObject*)__pyx_t_1)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 378; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (PyTuple_CheckExact(__pyx_t_2) && likely(PyTuple_GET_SIZE(__pyx_t_2) == 3)) {
+    PyObject* tuple = __pyx_t_2;
+    __pyx_t_1 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_1);
+    __pyx_t_3 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_3);
+    __pyx_t_4 = PyTuple_GET_ITEM(tuple, 2); __Pyx_INCREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    __Pyx_DECREF(__pyx_v_ids);
+    __pyx_v_ids = __pyx_t_1;
+    __pyx_t_1 = 0;
+    __Pyx_DECREF(__pyx_v_lons);
+    __pyx_v_lons = __pyx_t_3;
+    __pyx_t_3 = 0;
+    __Pyx_DECREF(__pyx_v_lats);
+    __pyx_v_lats = __pyx_t_4;
+    __pyx_t_4 = 0;
+  } else {
+    __pyx_t_5 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 378; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_5);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    __pyx_t_1 = __Pyx_UnpackItem(__pyx_t_5, 0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 378; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_3 = __Pyx_UnpackItem(__pyx_t_5, 1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 378; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_4 = __Pyx_UnpackItem(__pyx_t_5, 2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 378; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    if (__Pyx_EndUnpack(__pyx_t_5, 3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 378; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+    __Pyx_DECREF(__pyx_v_ids);
+    __pyx_v_ids = __pyx_t_1;
+    __pyx_t_1 = 0;
+    __Pyx_DECREF(__pyx_v_lons);
+    __pyx_v_lons = __pyx_t_3;
+    __pyx_t_3 = 0;
+    __Pyx_DECREF(__pyx_v_lats);
+    __pyx_v_lats = __pyx_t_4;
+    __pyx_t_4 = 0;
+  }
+
+  /* "imposm/cache/tc.pyx":379
+ *     def serialize(self):
+ *         ids, lons, lats = unzip_nodes(self.nodes)
+ *         nodes = _DeltaCoords()             # <<<<<<<<<<<<<<
+ *         nodes.ids = ids
+ *         nodes.lons = lons
+ */
+  __pyx_t_2 = __Pyx_GetName(__pyx_m, __pyx_n_s___DeltaCoords); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 379; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_4 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 379; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __Pyx_DECREF(__pyx_v_nodes);
+  __pyx_v_nodes = __pyx_t_4;
+  __pyx_t_4 = 0;
+
+  /* "imposm/cache/tc.pyx":380
+ *         ids, lons, lats = unzip_nodes(self.nodes)
+ *         nodes = _DeltaCoords()
+ *         nodes.ids = ids             # <<<<<<<<<<<<<<
+ *         nodes.lons = lons
+ *         nodes.lats = lats
+ */
+  if (PyObject_SetAttr(__pyx_v_nodes, __pyx_n_s__ids, __pyx_v_ids) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 380; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "imposm/cache/tc.pyx":381
+ *         nodes = _DeltaCoords()
+ *         nodes.ids = ids
+ *         nodes.lons = lons             # <<<<<<<<<<<<<<
+ *         nodes.lats = lats
+ *         return nodes.SerializeToString()
+ */
+  if (PyObject_SetAttr(__pyx_v_nodes, __pyx_n_s__lons, __pyx_v_lons) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 381; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "imposm/cache/tc.pyx":382
+ *         nodes.ids = ids
+ *         nodes.lons = lons
+ *         nodes.lats = lats             # <<<<<<<<<<<<<<
+ *         return nodes.SerializeToString()
+ * 
+ */
+  if (PyObject_SetAttr(__pyx_v_nodes, __pyx_n_s__lats, __pyx_v_lats) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 382; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "imposm/cache/tc.pyx":383
+ *         nodes.lons = lons
+ *         nodes.lats = lats
+ *         return nodes.SerializeToString()             # <<<<<<<<<<<<<<
+ * 
+ *     def deserialize(self, data):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_4 = PyObject_GetAttr(__pyx_v_nodes, __pyx_n_s__SerializeToString); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 383; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_t_2 = PyObject_Call(__pyx_t_4, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 383; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  __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_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.DeltaNodes.serialize");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_ids);
+  __Pyx_DECREF(__pyx_v_lons);
+  __Pyx_DECREF(__pyx_v_lats);
+  __Pyx_DECREF(__pyx_v_nodes);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":385
+ *         return nodes.SerializeToString()
+ * 
+ *     def deserialize(self, data):             # <<<<<<<<<<<<<<
+ *         nodes = _DeltaCoords()
+ *         nodes.ParseFromString(data)
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_10DeltaNodes_5deserialize(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyMethodDef __pyx_mdef_6imposm_5cache_2tc_10DeltaNodes_5deserialize = {__Pyx_NAMESTR("deserialize"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_10DeltaNodes_5deserialize, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pf_6imposm_5cache_2tc_10DeltaNodes_5deserialize(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_self = 0;
+  PyObject *__pyx_v_data = 0;
+  PyObject *__pyx_v_nodes;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__self,&__pyx_n_s__data,0};
+  __Pyx_RefNannySetupContext("deserialize");
+  __pyx_self = __pyx_self;
+  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__self);
+      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("deserialize", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 385; __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), "deserialize") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 385; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_self = values[0];
+    __pyx_v_data = values[1];
+  } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
+    goto __pyx_L5_argtuple_error;
+  } else {
+    __pyx_v_self = PyTuple_GET_ITEM(__pyx_args, 0);
+    __pyx_v_data = PyTuple_GET_ITEM(__pyx_args, 1);
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("deserialize", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 385; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaNodes.deserialize");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_v_nodes = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "imposm/cache/tc.pyx":386
+ * 
+ *     def deserialize(self, data):
+ *         nodes = _DeltaCoords()             # <<<<<<<<<<<<<<
+ *         nodes.ParseFromString(data)
+ *         self.nodes = zip_nodes(
+ */
+  __pyx_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s___DeltaCoords); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 386; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 386; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(__pyx_v_nodes);
+  __pyx_v_nodes = __pyx_t_2;
+  __pyx_t_2 = 0;
+
+  /* "imposm/cache/tc.pyx":387
+ *     def deserialize(self, data):
+ *         nodes = _DeltaCoords()
+ *         nodes.ParseFromString(data)             # <<<<<<<<<<<<<<
+ *         self.nodes = zip_nodes(
+ *             nodes.ids, nodes.lons, nodes.lats)
+ */
+  __pyx_t_2 = PyObject_GetAttr(__pyx_v_nodes, __pyx_n_s__ParseFromString); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 387; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 387; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __Pyx_INCREF(__pyx_v_data);
+  PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_data);
+  __Pyx_GIVEREF(__pyx_v_data);
+  __pyx_t_3 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 387; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+
+  /* "imposm/cache/tc.pyx":389
+ *         nodes.ParseFromString(data)
+ *         self.nodes = zip_nodes(
+ *             nodes.ids, nodes.lons, nodes.lats)             # <<<<<<<<<<<<<<
+ * 
+ * class DeltaCoordsDB(object):
+ */
+  __pyx_t_3 = PyObject_GetAttr(__pyx_v_nodes, __pyx_n_s__ids); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 389; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected tuple, got %.200s", Py_TYPE(__pyx_t_3)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 389; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_nodes, __pyx_n_s__lons); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 389; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (!(likely(PyTuple_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected tuple, got %.200s", Py_TYPE(__pyx_t_1)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 389; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyObject_GetAttr(__pyx_v_nodes, __pyx_n_s__lats); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 389; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  if (!(likely(PyTuple_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected tuple, got %.200s", Py_TYPE(__pyx_t_2)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 389; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_4 = __pyx_f_6imposm_5cache_2tc_zip_nodes(((PyObject*)__pyx_t_3), ((PyObject*)__pyx_t_1), ((PyObject*)__pyx_t_2)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 388; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+  /* "imposm/cache/tc.pyx":388
+ *         nodes = _DeltaCoords()
+ *         nodes.ParseFromString(data)
+ *         self.nodes = zip_nodes(             # <<<<<<<<<<<<<<
+ *             nodes.ids, nodes.lons, nodes.lats)
+ * 
+ */
+  if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__nodes, __pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 388; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+  __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.DeltaNodes.deserialize");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_nodes);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":392
+ * 
+ * class DeltaCoordsDB(object):
+ *     def __init__(self, filename, mode='w', estimated_records=0, delta_nodes_cache_size=100, delta_nodes_size=6):             # <<<<<<<<<<<<<<
+ *         self.db = BDB(filename, mode, estimated_records)
+ *         self.mode = mode
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB___init__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyMethodDef __pyx_mdef_6imposm_5cache_2tc_13DeltaCoordsDB___init__ = {__Pyx_NAMESTR("__init__"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB___init__, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB___init__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_self = 0;
+  PyObject *__pyx_v_filename = 0;
+  PyObject *__pyx_v_mode = 0;
+  PyObject *__pyx_v_estimated_records = 0;
+  PyObject *__pyx_v_delta_nodes_cache_size = 0;
+  PyObject *__pyx_v_delta_nodes_size = 0;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__self,&__pyx_n_s__filename,&__pyx_n_s__mode,&__pyx_n_s__estimated_records,&__pyx_n_s_1,&__pyx_n_s__delta_nodes_size,0};
+  __Pyx_RefNannySetupContext("__init__");
+  __pyx_self = __pyx_self;
+  if (unlikely(__pyx_kwds)) {
+    Py_ssize_t kw_args = PyDict_Size(__pyx_kwds);
+    PyObject* values[6] = {0,0,0,0,0,0};
+    values[2] = ((PyObject *)__pyx_n_s__w);
+    values[3] = ((PyObject *)__pyx_int_0);
+    values[4] = ((PyObject *)__pyx_int_100);
+    values[5] = ((PyObject *)__pyx_int_6);
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  6: values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
+      case  5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
+      case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
+      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__self);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__filename);
+      if (likely(values[1])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("__init__", 0, 2, 6, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 392; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+      case  2:
+      if (kw_args > 0) {
+        PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__mode);
+        if (value) { values[2] = value; kw_args--; }
+      }
+      case  3:
+      if (kw_args > 0) {
+        PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__estimated_records);
+        if (value) { values[3] = value; kw_args--; }
+      }
+      case  4:
+      if (kw_args > 0) {
+        PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_1);
+        if (value) { values[4] = value; kw_args--; }
+      }
+      case  5:
+      if (kw_args > 0) {
+        PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__delta_nodes_size);
+        if (value) { values[5] = 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 = 392; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_self = values[0];
+    __pyx_v_filename = values[1];
+    __pyx_v_mode = values[2];
+    __pyx_v_estimated_records = values[3];
+    __pyx_v_delta_nodes_cache_size = values[4];
+    __pyx_v_delta_nodes_size = values[5];
+  } else {
+    __pyx_v_mode = ((PyObject *)__pyx_n_s__w);
+    __pyx_v_estimated_records = ((PyObject *)__pyx_int_0);
+    __pyx_v_delta_nodes_cache_size = ((PyObject *)__pyx_int_100);
+    __pyx_v_delta_nodes_size = ((PyObject *)__pyx_int_6);
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  6:
+      __pyx_v_delta_nodes_size = PyTuple_GET_ITEM(__pyx_args, 5);
+      case  5:
+      __pyx_v_delta_nodes_cache_size = PyTuple_GET_ITEM(__pyx_args, 4);
+      case  4:
+      __pyx_v_estimated_records = PyTuple_GET_ITEM(__pyx_args, 3);
+      case  3:
+      __pyx_v_mode = PyTuple_GET_ITEM(__pyx_args, 2);
+      case  2:
+      __pyx_v_filename = PyTuple_GET_ITEM(__pyx_args, 1);
+      __pyx_v_self = 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, 2, 6, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 392; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaCoordsDB.__init__");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+
+  /* "imposm/cache/tc.pyx":393
+ * class DeltaCoordsDB(object):
+ *     def __init__(self, filename, mode='w', estimated_records=0, delta_nodes_cache_size=100, delta_nodes_size=6):
+ *         self.db = BDB(filename, mode, estimated_records)             # <<<<<<<<<<<<<<
+ *         self.mode = mode
+ *         self.delta_nodes = {}
+ */
+  __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 393; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __Pyx_INCREF(__pyx_v_filename);
+  PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_filename);
+  __Pyx_GIVEREF(__pyx_v_filename);
+  __Pyx_INCREF(__pyx_v_mode);
+  PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_v_mode);
+  __Pyx_GIVEREF(__pyx_v_mode);
+  __Pyx_INCREF(__pyx_v_estimated_records);
+  PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_v_estimated_records);
+  __Pyx_GIVEREF(__pyx_v_estimated_records);
+  __pyx_t_2 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_6imposm_5cache_2tc_BDB)), ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 393; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+  if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__db, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 393; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+  /* "imposm/cache/tc.pyx":394
+ *     def __init__(self, filename, mode='w', estimated_records=0, delta_nodes_cache_size=100, delta_nodes_size=6):
+ *         self.db = BDB(filename, mode, estimated_records)
+ *         self.mode = mode             # <<<<<<<<<<<<<<
+ *         self.delta_nodes = {}
+ *         self.delta_node_ids = deque()
+ */
+  if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__mode, __pyx_v_mode) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 394; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "imposm/cache/tc.pyx":395
+ *         self.db = BDB(filename, mode, estimated_records)
+ *         self.mode = mode
+ *         self.delta_nodes = {}             # <<<<<<<<<<<<<<
+ *         self.delta_node_ids = deque()
+ *         self.delta_nodes_cache_size = delta_nodes_cache_size
+ */
+  __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 395; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__delta_nodes, ((PyObject *)__pyx_t_2)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 395; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+
+  /* "imposm/cache/tc.pyx":396
+ *         self.mode = mode
+ *         self.delta_nodes = {}
+ *         self.delta_node_ids = deque()             # <<<<<<<<<<<<<<
+ *         self.delta_nodes_cache_size = delta_nodes_cache_size
+ *         self.delta_nodes_size = delta_nodes_size
+ */
+  __pyx_t_2 = __Pyx_GetName(__pyx_m, __pyx_n_s__deque); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 396; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_1 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 396; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__delta_node_ids, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 396; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":397
+ *         self.delta_nodes = {}
+ *         self.delta_node_ids = deque()
+ *         self.delta_nodes_cache_size = delta_nodes_cache_size             # <<<<<<<<<<<<<<
+ *         self.delta_nodes_size = delta_nodes_size
+ * 
+ */
+  if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s_1, __pyx_v_delta_nodes_cache_size) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 397; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "imposm/cache/tc.pyx":398
+ *         self.delta_node_ids = deque()
+ *         self.delta_nodes_cache_size = delta_nodes_cache_size
+ *         self.delta_nodes_size = delta_nodes_size             # <<<<<<<<<<<<<<
+ * 
+ *     def put(self, int64_t osmid, double lon, double lat):
+ */
+  if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__delta_nodes_size, __pyx_v_delta_nodes_size) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 398; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  __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.DeltaCoordsDB.__init__");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":400
+ *         self.delta_nodes_size = delta_nodes_size
+ * 
+ *     def put(self, int64_t osmid, double lon, double lat):             # <<<<<<<<<<<<<<
+ *         if self.mode == 'r':
+ *             return None
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_1put(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyMethodDef __pyx_mdef_6imposm_5cache_2tc_13DeltaCoordsDB_1put = {__Pyx_NAMESTR("put"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_1put, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_1put(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_self = 0;
+  int64_t __pyx_v_osmid;
+  double __pyx_v_lon;
+  double __pyx_v_lat;
+  PyObject *__pyx_v_delta_id;
+  PyObject *__pyx_v_delta_node;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  int __pyx_t_3;
+  PyObject *__pyx_t_4 = NULL;
+  PyObject *__pyx_t_5 = NULL;
+  PyObject *__pyx_t_6 = NULL;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__self,&__pyx_n_s__osmid,&__pyx_n_s__lon,&__pyx_n_s__lat,0};
+  __Pyx_RefNannySetupContext("put");
+  __pyx_self = __pyx_self;
+  if (unlikely(__pyx_kwds)) {
+    Py_ssize_t kw_args = PyDict_Size(__pyx_kwds);
+    PyObject* values[4] = {0,0,0,0};
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
+      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__self);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__osmid);
+      if (likely(values[1])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("put", 1, 4, 4, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 400; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+      case  2:
+      values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__lon);
+      if (likely(values[2])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("put", 1, 4, 4, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 400; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+      case  3:
+      values[3] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__lat);
+      if (likely(values[3])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("put", 1, 4, 4, 3); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 400; __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 = 400; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_self = values[0];
+    __pyx_v_osmid = __Pyx_PyInt_from_py_int64_t(values[1]); if (unlikely((__pyx_v_osmid == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 400; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_lon = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_lon == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 400; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_lat = __pyx_PyFloat_AsDouble(values[3]); if (unlikely((__pyx_v_lat == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 400; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  } else if (PyTuple_GET_SIZE(__pyx_args) != 4) {
+    goto __pyx_L5_argtuple_error;
+  } else {
+    __pyx_v_self = PyTuple_GET_ITEM(__pyx_args, 0);
+    __pyx_v_osmid = __Pyx_PyInt_from_py_int64_t(PyTuple_GET_ITEM(__pyx_args, 1)); if (unlikely((__pyx_v_osmid == (int64_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 400; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_lon = __pyx_PyFloat_AsDouble(PyTuple_GET_ITEM(__pyx_args, 2)); if (unlikely((__pyx_v_lon == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 400; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_lat = __pyx_PyFloat_AsDouble(PyTuple_GET_ITEM(__pyx_args, 3)); if (unlikely((__pyx_v_lat == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 400; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("put", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 400; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaCoordsDB.put");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_v_delta_id = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_v_delta_node = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "imposm/cache/tc.pyx":401
+ * 
+ *     def put(self, int64_t osmid, double lon, double lat):
+ *         if self.mode == 'r':             # <<<<<<<<<<<<<<
+ *             return None
+ *         delta_id = osmid >> self.delta_nodes_size
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__mode); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 401; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_RichCompare(__pyx_t_1, ((PyObject *)__pyx_n_s__r), Py_EQ); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 401; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 401; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  if (__pyx_t_3) {
+
+    /* "imposm/cache/tc.pyx":402
+ *     def put(self, int64_t osmid, double lon, double lat):
+ *         if self.mode == 'r':
+ *             return None             # <<<<<<<<<<<<<<
+ *         delta_id = osmid >> self.delta_nodes_size
+ *         if delta_id not in self.delta_nodes:
+ */
+    __Pyx_XDECREF(__pyx_r);
+    __Pyx_INCREF(Py_None);
+    __pyx_r = Py_None;
+    goto __pyx_L0;
+    goto __pyx_L6;
+  }
+  __pyx_L6:;
+
+  /* "imposm/cache/tc.pyx":403
+ *         if self.mode == 'r':
+ *             return None
+ *         delta_id = osmid >> self.delta_nodes_size             # <<<<<<<<<<<<<<
+ *         if delta_id not in self.delta_nodes:
+ *             self.fetch_delta_node(delta_id)
+ */
+  __pyx_t_2 = __Pyx_PyInt_to_py_int64_t(__pyx_v_osmid); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 403; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__delta_nodes_size); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 403; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_4 = PyNumber_Rshift(__pyx_t_2, __pyx_t_1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 403; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(__pyx_v_delta_id);
+  __pyx_v_delta_id = __pyx_t_4;
+  __pyx_t_4 = 0;
+
+  /* "imposm/cache/tc.pyx":404
+ *             return None
+ *         delta_id = osmid >> self.delta_nodes_size
+ *         if delta_id not in self.delta_nodes:             # <<<<<<<<<<<<<<
+ *             self.fetch_delta_node(delta_id)
+ *         delta_node = self.delta_nodes[delta_id]
+ */
+  __pyx_t_4 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__delta_nodes); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 404; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_t_3 = (__Pyx_NegateNonNeg(PySequence_Contains(__pyx_t_4, __pyx_v_delta_id))); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 404; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  if (__pyx_t_3) {
+
+    /* "imposm/cache/tc.pyx":405
+ *         delta_id = osmid >> self.delta_nodes_size
+ *         if delta_id not in self.delta_nodes:
+ *             self.fetch_delta_node(delta_id)             # <<<<<<<<<<<<<<
+ *         delta_node = self.delta_nodes[delta_id]
+ *         delta_node.add(osmid, lon, lat)
+ */
+    __pyx_t_4 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__fetch_delta_node); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 405; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 405; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+    __Pyx_INCREF(__pyx_v_delta_id);
+    PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_delta_id);
+    __Pyx_GIVEREF(__pyx_v_delta_id);
+    __pyx_t_2 = PyObject_Call(__pyx_t_4, ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 405; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    goto __pyx_L7;
+  }
+  __pyx_L7:;
+
+  /* "imposm/cache/tc.pyx":406
+ *         if delta_id not in self.delta_nodes:
+ *             self.fetch_delta_node(delta_id)
+ *         delta_node = self.delta_nodes[delta_id]             # <<<<<<<<<<<<<<
+ *         delta_node.add(osmid, lon, lat)
+ *         return True
+ */
+  __pyx_t_2 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__delta_nodes); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 406; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_1 = PyObject_GetItem(__pyx_t_2, __pyx_v_delta_id); if (!__pyx_t_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 406; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __Pyx_DECREF(__pyx_v_delta_node);
+  __pyx_v_delta_node = __pyx_t_1;
+  __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":407
+ *             self.fetch_delta_node(delta_id)
+ *         delta_node = self.delta_nodes[delta_id]
+ *         delta_node.add(osmid, lon, lat)             # <<<<<<<<<<<<<<
+ *         return True
+ * 
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_delta_node, __pyx_n_s__add); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 407; __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 = 407; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_4 = PyFloat_FromDouble(__pyx_v_lon); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 407; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_t_5 = PyFloat_FromDouble(__pyx_v_lat); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 407; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_5);
+  __pyx_t_6 = PyTuple_New(3); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 407; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_6));
+  PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_2);
+  __Pyx_GIVEREF(__pyx_t_2);
+  PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_t_4);
+  __Pyx_GIVEREF(__pyx_t_4);
+  PyTuple_SET_ITEM(__pyx_t_6, 2, __pyx_t_5);
+  __Pyx_GIVEREF(__pyx_t_5);
+  __pyx_t_2 = 0;
+  __pyx_t_4 = 0;
+  __pyx_t_5 = 0;
+  __pyx_t_5 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_6), NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 407; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_5);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_6)); __pyx_t_6 = 0;
+  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+
+  /* "imposm/cache/tc.pyx":408
+ *         delta_node = self.delta_nodes[delta_id]
+ *         delta_node.add(osmid, lon, lat)
+ *         return True             # <<<<<<<<<<<<<<
+ * 
+ *     put_marshaled = put
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_5 = __Pyx_PyBool_FromLong(1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 408; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_5);
+  __pyx_r = __pyx_t_5;
+  __pyx_t_5 = 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_4);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaCoordsDB.put");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_delta_id);
+  __Pyx_DECREF(__pyx_v_delta_node);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":412
+ *     put_marshaled = put
+ * 
+ *     def get(self, osmid):             # <<<<<<<<<<<<<<
+ *         delta_id = osmid >> self.delta_nodes_size
+ *         if delta_id not in self.delta_nodes:
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_2get(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyMethodDef __pyx_mdef_6imposm_5cache_2tc_13DeltaCoordsDB_2get = {__Pyx_NAMESTR("get"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_2get, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_2get(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_self = 0;
+  PyObject *__pyx_v_osmid = 0;
+  PyObject *__pyx_v_delta_id;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  int __pyx_t_3;
+  PyObject *__pyx_t_4 = NULL;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__self,&__pyx_n_s__osmid,0};
+  __Pyx_RefNannySetupContext("get");
+  __pyx_self = __pyx_self;
+  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__self);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__osmid);
+      if (likely(values[1])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("get", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 412; __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), "get") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 412; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_self = values[0];
+    __pyx_v_osmid = values[1];
+  } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
+    goto __pyx_L5_argtuple_error;
+  } else {
+    __pyx_v_self = PyTuple_GET_ITEM(__pyx_args, 0);
+    __pyx_v_osmid = PyTuple_GET_ITEM(__pyx_args, 1);
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("get", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 412; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaCoordsDB.get");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_v_delta_id = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "imposm/cache/tc.pyx":413
+ * 
+ *     def get(self, osmid):
+ *         delta_id = osmid >> self.delta_nodes_size             # <<<<<<<<<<<<<<
+ *         if delta_id not in self.delta_nodes:
+ *             self.fetch_delta_node(delta_id)
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__delta_nodes_size); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 413; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyNumber_Rshift(__pyx_v_osmid, __pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 413; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(__pyx_v_delta_id);
+  __pyx_v_delta_id = __pyx_t_2;
+  __pyx_t_2 = 0;
+
+  /* "imposm/cache/tc.pyx":414
+ *     def get(self, osmid):
+ *         delta_id = osmid >> self.delta_nodes_size
+ *         if delta_id not in self.delta_nodes:             # <<<<<<<<<<<<<<
+ *             self.fetch_delta_node(delta_id)
+ *         return self.delta_nodes[delta_id].get(osmid)
+ */
+  __pyx_t_2 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__delta_nodes); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 414; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = (__Pyx_NegateNonNeg(PySequence_Contains(__pyx_t_2, __pyx_v_delta_id))); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 414; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  if (__pyx_t_3) {
+
+    /* "imposm/cache/tc.pyx":415
+ *         delta_id = osmid >> self.delta_nodes_size
+ *         if delta_id not in self.delta_nodes:
+ *             self.fetch_delta_node(delta_id)             # <<<<<<<<<<<<<<
+ *         return self.delta_nodes[delta_id].get(osmid)
+ * 
+ */
+    __pyx_t_2 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__fetch_delta_node); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 415; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 415; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+    __Pyx_INCREF(__pyx_v_delta_id);
+    PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_delta_id);
+    __Pyx_GIVEREF(__pyx_v_delta_id);
+    __pyx_t_4 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 415; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    goto __pyx_L6;
+  }
+  __pyx_L6:;
+
+  /* "imposm/cache/tc.pyx":416
+ *         if delta_id not in self.delta_nodes:
+ *             self.fetch_delta_node(delta_id)
+ *         return self.delta_nodes[delta_id].get(osmid)             # <<<<<<<<<<<<<<
+ * 
+ *     def get_coords(self, osmids):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_4 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__delta_nodes); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 416; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_t_1 = PyObject_GetItem(__pyx_t_4, __pyx_v_delta_id); if (!__pyx_t_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 416; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  __pyx_t_4 = PyObject_GetAttr(__pyx_t_1, __pyx_n_s__get); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 416; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 416; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __Pyx_INCREF(__pyx_v_osmid);
+  PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_osmid);
+  __Pyx_GIVEREF(__pyx_v_osmid);
+  __pyx_t_2 = PyObject_Call(__pyx_t_4, ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 416; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+  __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_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaCoordsDB.get");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_delta_id);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":418
+ *         return self.delta_nodes[delta_id].get(osmid)
+ * 
+ *     def get_coords(self, osmids):             # <<<<<<<<<<<<<<
+ *         coords = []
+ *         for osmid in osmids:
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_3get_coords(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyMethodDef __pyx_mdef_6imposm_5cache_2tc_13DeltaCoordsDB_3get_coords = {__Pyx_NAMESTR("get_coords"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_3get_coords, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_3get_coords(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_self = 0;
+  PyObject *__pyx_v_osmids = 0;
+  PyObject *__pyx_v_coords;
+  PyObject *__pyx_v_osmid;
+  PyObject *__pyx_v_coord;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  Py_ssize_t __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  PyObject *__pyx_t_5 = NULL;
+  int __pyx_t_6;
+  int __pyx_t_7;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__self,&__pyx_n_s__osmids,0};
+  __Pyx_RefNannySetupContext("get_coords");
+  __pyx_self = __pyx_self;
+  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__self);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__osmids);
+      if (likely(values[1])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("get_coords", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 418; __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), "get_coords") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 418; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_self = values[0];
+    __pyx_v_osmids = values[1];
+  } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
+    goto __pyx_L5_argtuple_error;
+  } else {
+    __pyx_v_self = PyTuple_GET_ITEM(__pyx_args, 0);
+    __pyx_v_osmids = PyTuple_GET_ITEM(__pyx_args, 1);
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("get_coords", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 418; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaCoordsDB.get_coords");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_v_coords = ((PyObject*)Py_None); __Pyx_INCREF(Py_None);
+  __pyx_v_osmid = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_v_coord = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "imposm/cache/tc.pyx":419
+ * 
+ *     def get_coords(self, osmids):
+ *         coords = []             # <<<<<<<<<<<<<<
+ *         for osmid in osmids:
+ *             coord = self.get(osmid)
+ */
+  __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 419; __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":420
+ *     def get_coords(self, osmids):
+ *         coords = []
+ *         for osmid in osmids:             # <<<<<<<<<<<<<<
+ *             coord = self.get(osmid)
+ *             if coord is None:
+ */
+  if (PyList_CheckExact(__pyx_v_osmids) || PyTuple_CheckExact(__pyx_v_osmids)) {
+    __pyx_t_2 = 0; __pyx_t_1 = __pyx_v_osmids; __Pyx_INCREF(__pyx_t_1);
+  } else {
+    __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_osmids); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 420; __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 = 420; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        break;
+      }
+      __Pyx_GOTREF(__pyx_t_3);
+    }
+    __Pyx_DECREF(__pyx_v_osmid);
+    __pyx_v_osmid = __pyx_t_3;
+    __pyx_t_3 = 0;
+
+    /* "imposm/cache/tc.pyx":421
+ *         coords = []
+ *         for osmid in osmids:
+ *             coord = self.get(osmid)             # <<<<<<<<<<<<<<
+ *             if coord is None:
+ *                 return
+ */
+    __pyx_t_3 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__get); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 421; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 421; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_4));
+    __Pyx_INCREF(__pyx_v_osmid);
+    PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_v_osmid);
+    __Pyx_GIVEREF(__pyx_v_osmid);
+    __pyx_t_5 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_t_4), NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 421; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_5);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0;
+    __Pyx_DECREF(__pyx_v_coord);
+    __pyx_v_coord = __pyx_t_5;
+    __pyx_t_5 = 0;
+
+    /* "imposm/cache/tc.pyx":422
+ *         for osmid in osmids:
+ *             coord = self.get(osmid)
+ *             if coord is None:             # <<<<<<<<<<<<<<
+ *                 return
+ *             coords.append(coord)
+ */
+    __pyx_t_6 = (__pyx_v_coord == Py_None);
+    if (__pyx_t_6) {
+
+      /* "imposm/cache/tc.pyx":423
+ *             coord = self.get(osmid)
+ *             if coord is None:
+ *                 return             # <<<<<<<<<<<<<<
+ *             coords.append(coord)
+ *         return coords
+ */
+      __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_L8;
+    }
+    __pyx_L8:;
+
+    /* "imposm/cache/tc.pyx":424
+ *             if coord is None:
+ *                 return
+ *             coords.append(coord)             # <<<<<<<<<<<<<<
+ *         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 = 424; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 
+    }
+    __pyx_t_7 = PyList_Append(__pyx_v_coords, __pyx_v_coord); if (unlikely(__pyx_t_7 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 424; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":425
+ *                 return
+ *             coords.append(coord)
+ *         return coords             # <<<<<<<<<<<<<<
+ * 
+ *     def close(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_4);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaCoordsDB.get_coords");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_coords);
+  __Pyx_DECREF(__pyx_v_osmid);
+  __Pyx_DECREF(__pyx_v_coord);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":427
+ *         return coords
+ * 
+ *     def close(self):             # <<<<<<<<<<<<<<
+ *         for node_id, node in self.delta_nodes.iteritems():
+ *             self._put(node_id, node)
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_4close(PyObject *__pyx_self, PyObject *__pyx_v_self); /*proto*/
+static PyMethodDef __pyx_mdef_6imposm_5cache_2tc_13DeltaCoordsDB_4close = {__Pyx_NAMESTR("close"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_4close, METH_O, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_4close(PyObject *__pyx_self, PyObject *__pyx_v_self) {
+  PyObject *__pyx_v_node_id;
+  PyObject *__pyx_v_node;
+  PyObject *__pyx_r = NULL;
+  Py_ssize_t __pyx_t_1;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  PyObject *__pyx_t_5 = NULL;
+  PyObject *__pyx_t_6 = NULL;
+  __Pyx_RefNannySetupContext("close");
+  __pyx_self = __pyx_self;
+  __pyx_v_node_id = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_v_node = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "imposm/cache/tc.pyx":428
+ * 
+ *     def close(self):
+ *         for node_id, node in self.delta_nodes.iteritems():             # <<<<<<<<<<<<<<
+ *             self._put(node_id, node)
+ *         self.delta_nodes = {}
+ */
+  __pyx_t_2 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__delta_nodes); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 428; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__iteritems); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 428; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 428; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (PyList_CheckExact(__pyx_t_2) || PyTuple_CheckExact(__pyx_t_2)) {
+    __pyx_t_1 = 0; __pyx_t_3 = __pyx_t_2; __Pyx_INCREF(__pyx_t_3);
+  } else {
+    __pyx_t_1 = -1; __pyx_t_3 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 428; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+  }
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  for (;;) {
+    if (likely(PyList_CheckExact(__pyx_t_3))) {
+      if (__pyx_t_1 >= PyList_GET_SIZE(__pyx_t_3)) break;
+      __pyx_t_2 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_1); __Pyx_INCREF(__pyx_t_2); __pyx_t_1++;
+    } else if (likely(PyTuple_CheckExact(__pyx_t_3))) {
+      if (__pyx_t_1 >= PyTuple_GET_SIZE(__pyx_t_3)) break;
+      __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_3, __pyx_t_1); __Pyx_INCREF(__pyx_t_2); __pyx_t_1++;
+    } else {
+      __pyx_t_2 = PyIter_Next(__pyx_t_3);
+      if (!__pyx_t_2) {
+        if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 428; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        break;
+      }
+      __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_4 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_4);
+      __pyx_t_5 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_5);
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+      __Pyx_DECREF(__pyx_v_node_id);
+      __pyx_v_node_id = __pyx_t_4;
+      __pyx_t_4 = 0;
+      __Pyx_DECREF(__pyx_v_node);
+      __pyx_v_node = __pyx_t_5;
+      __pyx_t_5 = 0;
+    } else {
+      __pyx_t_6 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 428; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_6);
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+      __pyx_t_4 = __Pyx_UnpackItem(__pyx_t_6, 0); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 428; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_4);
+      __pyx_t_5 = __Pyx_UnpackItem(__pyx_t_6, 1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 428; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_5);
+      if (__Pyx_EndUnpack(__pyx_t_6, 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 428; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+      __Pyx_DECREF(__pyx_v_node_id);
+      __pyx_v_node_id = __pyx_t_4;
+      __pyx_t_4 = 0;
+      __Pyx_DECREF(__pyx_v_node);
+      __pyx_v_node = __pyx_t_5;
+      __pyx_t_5 = 0;
+    }
+
+    /* "imposm/cache/tc.pyx":429
+ *     def close(self):
+ *         for node_id, node in self.delta_nodes.iteritems():
+ *             self._put(node_id, node)             # <<<<<<<<<<<<<<
+ *         self.delta_nodes = {}
+ *         self.delta_node_ids = deque()
+ */
+    __pyx_t_2 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___put); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 429; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 429; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_5));
+    __Pyx_INCREF(__pyx_v_node_id);
+    PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_v_node_id);
+    __Pyx_GIVEREF(__pyx_v_node_id);
+    __Pyx_INCREF(__pyx_v_node);
+    PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_v_node);
+    __Pyx_GIVEREF(__pyx_v_node);
+    __pyx_t_4 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 429; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  }
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+
+  /* "imposm/cache/tc.pyx":430
+ *         for node_id, node in self.delta_nodes.iteritems():
+ *             self._put(node_id, node)
+ *         self.delta_nodes = {}             # <<<<<<<<<<<<<<
+ *         self.delta_node_ids = deque()
+ *         self.db.close()
+ */
+  __pyx_t_3 = PyDict_New(); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 430; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_3));
+  if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__delta_nodes, ((PyObject *)__pyx_t_3)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 430; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+
+  /* "imposm/cache/tc.pyx":431
+ *             self._put(node_id, node)
+ *         self.delta_nodes = {}
+ *         self.delta_node_ids = deque()             # <<<<<<<<<<<<<<
+ *         self.db.close()
+ * 
+ */
+  __pyx_t_3 = __Pyx_GetName(__pyx_m, __pyx_n_s__deque); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 431; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_4 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 431; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__delta_node_ids, __pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 431; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+  /* "imposm/cache/tc.pyx":432
+ *         self.delta_nodes = {}
+ *         self.delta_node_ids = deque()
+ *         self.db.close()             # <<<<<<<<<<<<<<
+ * 
+ *     def _put(self, delta_id, delta_node):
+ */
+  __pyx_t_4 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__db); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 432; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_t_3 = PyObject_GetAttr(__pyx_t_4, __pyx_n_s__close); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 432; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  __pyx_t_4 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 432; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+  __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_5);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaCoordsDB.close");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_node_id);
+  __Pyx_DECREF(__pyx_v_node);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":434
+ *         self.db.close()
+ * 
+ *     def _put(self, delta_id, delta_node):             # <<<<<<<<<<<<<<
+ *         data = delta_node.serialize()
+ *         self.db.put_marshaled(delta_id, data)
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_5_put(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyMethodDef __pyx_mdef_6imposm_5cache_2tc_13DeltaCoordsDB_5_put = {__Pyx_NAMESTR("_put"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_5_put, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_5_put(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_self = 0;
+  PyObject *__pyx_v_delta_id = 0;
+  PyObject *__pyx_v_delta_node = 0;
+  PyObject *__pyx_v_data;
+  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__self,&__pyx_n_s__delta_id,&__pyx_n_s__delta_node,0};
+  __Pyx_RefNannySetupContext("_put");
+  __pyx_self = __pyx_self;
+  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__self);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__delta_id);
+      if (likely(values[1])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("_put", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 434; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+      case  2:
+      values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__delta_node);
+      if (likely(values[2])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("_put", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 434; __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 = 434; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_self = values[0];
+    __pyx_v_delta_id = values[1];
+    __pyx_v_delta_node = values[2];
+  } else if (PyTuple_GET_SIZE(__pyx_args) != 3) {
+    goto __pyx_L5_argtuple_error;
+  } else {
+    __pyx_v_self = PyTuple_GET_ITEM(__pyx_args, 0);
+    __pyx_v_delta_id = PyTuple_GET_ITEM(__pyx_args, 1);
+    __pyx_v_delta_node = 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 = 434; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaCoordsDB._put");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_v_data = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "imposm/cache/tc.pyx":435
+ * 
+ *     def _put(self, delta_id, delta_node):
+ *         data = delta_node.serialize()             # <<<<<<<<<<<<<<
+ *         self.db.put_marshaled(delta_id, data)
+ * 
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_delta_node, __pyx_n_s__serialize); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 435; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 435; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(__pyx_v_data);
+  __pyx_v_data = __pyx_t_2;
+  __pyx_t_2 = 0;
+
+  /* "imposm/cache/tc.pyx":436
+ *     def _put(self, delta_id, delta_node):
+ *         data = delta_node.serialize()
+ *         self.db.put_marshaled(delta_id, data)             # <<<<<<<<<<<<<<
+ * 
+ *     def _get(self, delta_id):
+ */
+  __pyx_t_2 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__db); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 436; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_1 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__put_marshaled); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 436; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(__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 = 436; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  __Pyx_INCREF(__pyx_v_delta_id);
+  PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_v_delta_id);
+  __Pyx_GIVEREF(__pyx_v_delta_id);
+  __Pyx_INCREF(__pyx_v_data);
+  PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_data);
+  __Pyx_GIVEREF(__pyx_v_data);
+  __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 = 436; __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;
+
+  __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.DeltaCoordsDB._put");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_data);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":438
+ *         self.db.put_marshaled(delta_id, data)
+ * 
+ *     def _get(self, delta_id):             # <<<<<<<<<<<<<<
+ *         return DeltaNodes(data=self.db.get_raw(delta_id))
+ * 
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_6_get(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyMethodDef __pyx_mdef_6imposm_5cache_2tc_13DeltaCoordsDB_6_get = {__Pyx_NAMESTR("_get"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_6_get, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_6_get(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_self = 0;
+  PyObject *__pyx_v_delta_id = 0;
+  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;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__self,&__pyx_n_s__delta_id,0};
+  __Pyx_RefNannySetupContext("_get");
+  __pyx_self = __pyx_self;
+  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__self);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__delta_id);
+      if (likely(values[1])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("_get", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 438; __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), "_get") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 438; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_self = values[0];
+    __pyx_v_delta_id = values[1];
+  } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
+    goto __pyx_L5_argtuple_error;
+  } else {
+    __pyx_v_self = PyTuple_GET_ITEM(__pyx_args, 0);
+    __pyx_v_delta_id = PyTuple_GET_ITEM(__pyx_args, 1);
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("_get", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 438; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaCoordsDB._get");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+
+  /* "imposm/cache/tc.pyx":439
+ * 
+ *     def _get(self, delta_id):
+ *         return DeltaNodes(data=self.db.get_raw(delta_id))             # <<<<<<<<<<<<<<
+ * 
+ *     def fetch_delta_node(self, delta_id):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s__DeltaNodes); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 439; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 439; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  __pyx_t_3 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__db); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 439; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_4 = PyObject_GetAttr(__pyx_t_3, __pyx_n_s__get_raw); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 439; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 439; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_3));
+  __Pyx_INCREF(__pyx_v_delta_id);
+  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_delta_id);
+  __Pyx_GIVEREF(__pyx_v_delta_id);
+  __pyx_t_5 = PyObject_Call(__pyx_t_4, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 439; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_5);
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+  if (PyDict_SetItem(__pyx_t_2, ((PyObject *)__pyx_n_s__data), __pyx_t_5) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 439; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+  __pyx_t_5 = PyEval_CallObjectWithKeywords(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), ((PyObject *)__pyx_t_2)); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 439; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_5);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+  __pyx_r = __pyx_t_5;
+  __pyx_t_5 = 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.DeltaCoordsDB._get");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "imposm/cache/tc.pyx":441
+ *         return DeltaNodes(data=self.db.get_raw(delta_id))
+ * 
+ *     def fetch_delta_node(self, delta_id):             # <<<<<<<<<<<<<<
+ *         if len(self.delta_node_ids) >= self.delta_nodes_cache_size:
+ *             rm_id = self.delta_node_ids.popleft()
+ */
+
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_7fetch_delta_node(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyMethodDef __pyx_mdef_6imposm_5cache_2tc_13DeltaCoordsDB_7fetch_delta_node = {__Pyx_NAMESTR("fetch_delta_node"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_7fetch_delta_node, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pf_6imposm_5cache_2tc_13DeltaCoordsDB_7fetch_delta_node(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_self = 0;
+  PyObject *__pyx_v_delta_id = 0;
+  PyObject *__pyx_v_rm_id;
+  PyObject *__pyx_v_rm_node;
+  PyObject *__pyx_v_new_node;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  Py_ssize_t __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  int __pyx_t_5;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__self,&__pyx_n_s__delta_id,0};
+  __Pyx_RefNannySetupContext("fetch_delta_node");
+  __pyx_self = __pyx_self;
+  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__self);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__delta_id);
+      if (likely(values[1])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("fetch_delta_node", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 441; __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), "fetch_delta_node") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 441; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_self = values[0];
+    __pyx_v_delta_id = values[1];
+  } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
+    goto __pyx_L5_argtuple_error;
+  } else {
+    __pyx_v_self = PyTuple_GET_ITEM(__pyx_args, 0);
+    __pyx_v_delta_id = PyTuple_GET_ITEM(__pyx_args, 1);
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("fetch_delta_node", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 441; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("imposm.cache.tc.DeltaCoordsDB.fetch_delta_node");
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_v_rm_id = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_v_rm_node = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_v_new_node = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "imposm/cache/tc.pyx":442
  * 
- * cdef class RelationDB(RefTagDB):
- *     cdef object _obj(self, int64_t osmid, data):             # <<<<<<<<<<<<<<
- *         return Relation(osmid, data[0], data[1])
+ *     def fetch_delta_node(self, delta_id):
+ *         if len(self.delta_node_ids) >= self.delta_nodes_cache_size:             # <<<<<<<<<<<<<<
+ *             rm_id = self.delta_node_ids.popleft()
+ *             rm_node = self.delta_nodes.pop(rm_id)
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__delta_node_ids); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 442; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_Length(__pyx_t_1); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 442; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __pyx_t_1 = PyInt_FromSsize_t(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 442; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_3 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 442; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_4 = PyObject_RichCompare(__pyx_t_1, __pyx_t_3, Py_GE); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 442; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_5 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 442; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  if (__pyx_t_5) {
+
+    /* "imposm/cache/tc.pyx":443
+ *     def fetch_delta_node(self, delta_id):
+ *         if len(self.delta_node_ids) >= self.delta_nodes_cache_size:
+ *             rm_id = self.delta_node_ids.popleft()             # <<<<<<<<<<<<<<
+ *             rm_node = self.delta_nodes.pop(rm_id)
+ *             if rm_node.changed:
  */
+    __pyx_t_4 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__delta_node_ids); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 443; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_3 = PyObject_GetAttr(__pyx_t_4, __pyx_n_s__popleft); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 443; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __pyx_t_4 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 443; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_DECREF(__pyx_v_rm_id);
+    __pyx_v_rm_id = __pyx_t_4;
+    __pyx_t_4 = 0;
 
-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":444
+ *         if len(self.delta_node_ids) >= self.delta_nodes_cache_size:
+ *             rm_id = self.delta_node_ids.popleft()
+ *             rm_node = self.delta_nodes.pop(rm_id)             # <<<<<<<<<<<<<<
+ *             if rm_node.changed:
+ *                 self._put(rm_id, rm_node)
+ */
+    __pyx_t_4 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__delta_nodes); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 444; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_3 = PyObject_GetAttr(__pyx_t_4, __pyx_n_s__pop); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 444; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 444; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_4));
+    __Pyx_INCREF(__pyx_v_rm_id);
+    PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_v_rm_id);
+    __Pyx_GIVEREF(__pyx_v_rm_id);
+    __pyx_t_1 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_t_4), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 444; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0;
+    __Pyx_DECREF(__pyx_v_rm_node);
+    __pyx_v_rm_node = __pyx_t_1;
+    __pyx_t_1 = 0;
+
+    /* "imposm/cache/tc.pyx":445
+ *             rm_id = self.delta_node_ids.popleft()
+ *             rm_node = self.delta_nodes.pop(rm_id)
+ *             if rm_node.changed:             # <<<<<<<<<<<<<<
+ *                 self._put(rm_id, rm_node)
+ *         new_node = self._get(delta_id)
+ */
+    __pyx_t_1 = PyObject_GetAttr(__pyx_v_rm_node, __pyx_n_s__changed); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 445; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_5 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 445; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    if (__pyx_t_5) {
 
-  /* "imposm/cache/tc.pyx":269
- * cdef class RelationDB(RefTagDB):
- *     cdef object _obj(self, int64_t osmid, data):
- *         return Relation(osmid, data[0], data[1])             # <<<<<<<<<<<<<<
+      /* "imposm/cache/tc.pyx":446
+ *             rm_node = self.delta_nodes.pop(rm_id)
+ *             if rm_node.changed:
+ *                 self._put(rm_id, rm_node)             # <<<<<<<<<<<<<<
+ *         new_node = self._get(delta_id)
+ *         if new_node is None:
  */
-  __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_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___put); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 446; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_1);
+      __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 446; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(((PyObject *)__pyx_t_4));
+      __Pyx_INCREF(__pyx_v_rm_id);
+      PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_v_rm_id);
+      __Pyx_GIVEREF(__pyx_v_rm_id);
+      __Pyx_INCREF(__pyx_v_rm_node);
+      PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_v_rm_node);
+      __Pyx_GIVEREF(__pyx_v_rm_node);
+      __pyx_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_4), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 446; __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_4)); __pyx_t_4 = 0;
+      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+      goto __pyx_L7;
+    }
+    __pyx_L7:;
+    goto __pyx_L6;
+  }
+  __pyx_L6:;
+
+  /* "imposm/cache/tc.pyx":447
+ *             if rm_node.changed:
+ *                 self._put(rm_id, rm_node)
+ *         new_node = self._get(delta_id)             # <<<<<<<<<<<<<<
+ *         if new_node is None:
+ *             new_node = DeltaNodes()
+ */
+  __pyx_t_3 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___get); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 447; __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_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 447; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_4));
+  __Pyx_INCREF(__pyx_v_delta_id);
+  PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_v_delta_id);
+  __Pyx_GIVEREF(__pyx_v_delta_id);
+  __pyx_t_1 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_t_4), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 447; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0;
+  __Pyx_DECREF(__pyx_v_new_node);
+  __pyx_v_new_node = __pyx_t_1;
+  __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":448
+ *                 self._put(rm_id, rm_node)
+ *         new_node = self._get(delta_id)
+ *         if new_node is None:             # <<<<<<<<<<<<<<
+ *             new_node = DeltaNodes()
+ *         self.delta_nodes[delta_id] = new_node
+ */
+  __pyx_t_5 = (__pyx_v_new_node == Py_None);
+  if (__pyx_t_5) {
+
+    /* "imposm/cache/tc.pyx":449
+ *         new_node = self._get(delta_id)
+ *         if new_node is None:
+ *             new_node = DeltaNodes()             # <<<<<<<<<<<<<<
+ *         self.delta_nodes[delta_id] = new_node
+ *         self.delta_node_ids.append(delta_id)
+ */
+    __pyx_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s__DeltaNodes); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 449; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_4 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 449; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __Pyx_DECREF(__pyx_v_new_node);
+    __pyx_v_new_node = __pyx_t_4;
+    __pyx_t_4 = 0;
+    goto __pyx_L8;
+  }
+  __pyx_L8:;
+
+  /* "imposm/cache/tc.pyx":450
+ *         if new_node is None:
+ *             new_node = DeltaNodes()
+ *         self.delta_nodes[delta_id] = new_node             # <<<<<<<<<<<<<<
+ *         self.delta_node_ids.append(delta_id)
+ * 
+ */
+  __pyx_t_4 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__delta_nodes); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 450; __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;}
+  if (PyObject_SetItem(__pyx_t_4, __pyx_v_delta_id, __pyx_v_new_node) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 450; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+  /* "imposm/cache/tc.pyx":451
+ *             new_node = DeltaNodes()
+ *         self.delta_nodes[delta_id] = new_node
+ *         self.delta_node_ids.append(delta_id)             # <<<<<<<<<<<<<<
+ * 
+ */
+  __pyx_t_4 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s__delta_node_ids); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 451; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_4);
+  __pyx_t_1 = __Pyx_PyObject_Append(__pyx_t_4, __pyx_v_delta_id); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 451; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
   __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_AddTraceback("imposm.cache.tc.DeltaCoordsDB.fetch_delta_node");
+  __pyx_r = NULL;
   __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_rm_id);
+  __Pyx_DECREF(__pyx_v_rm_node);
+  __Pyx_DECREF(__pyx_v_new_node);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
@@ -3163,7 +6696,7 @@ static void __pyx_tp_dealloc_6imposm_5cache_2tc_BDB(PyObject *o) {
     PyObject *etype, *eval, *etb;
     PyErr_Fetch(&etype, &eval, &etb);
     ++Py_REFCNT(o);
-    __pyx_pf_6imposm_5cache_2tc_3BDB_9__dealloc__(o);
+    __pyx_pf_6imposm_5cache_2tc_3BDB_12__dealloc__(o);
     if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
     --Py_REFCNT(o);
     PyErr_Restore(etype, eval, etb);
@@ -3193,8 +6726,11 @@ static int __pyx_tp_clear_6imposm_5cache_2tc_BDB(PyObject *o) {
 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)},
+  {__Pyx_NAMESTR("get_raw"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_3BDB_4get_raw, METH_O, __Pyx_DOCSTR(__pyx_doc_6imposm_5cache_2tc_3BDB_4get_raw)},
+  {__Pyx_NAMESTR("put"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_3BDB_5put, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("put_marshaled"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_3BDB_6put_marshaled, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("__next__"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_3BDB_10__next__, METH_NOARGS|METH_COEXIST, __Pyx_DOCSTR(__pyx_doc_6imposm_5cache_2tc_3BDB_10__next__)},
+  {__Pyx_NAMESTR("close"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_3BDB_11close, METH_NOARGS, __Pyx_DOCSTR(0)},
   {0, 0, 0, 0}
 };
 
@@ -3257,20 +6793,20 @@ static PyNumberMethods __pyx_tp_as_number_BDB = {
 };
 
 static PySequenceMethods __pyx_tp_as_sequence_BDB = {
-  __pyx_pf_6imposm_5cache_2tc_3BDB_6__len__, /*sq_length*/
+  __pyx_pf_6imposm_5cache_2tc_3BDB_9__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*/
+  __pyx_pf_6imposm_5cache_2tc_3BDB_8__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*/
+  __pyx_pf_6imposm_5cache_2tc_3BDB_9__len__, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
@@ -3326,8 +6862,8 @@ static PyTypeObject __pyx_type_6imposm_5cache_2tc_BDB = {
   __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_pf_6imposm_5cache_2tc_3BDB_7__iter__, /*tp_iter*/
+  __pyx_pf_6imposm_5cache_2tc_3BDB_10__next__, /*tp_iternext*/
   __pyx_methods_6imposm_5cache_2tc_BDB, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
@@ -3510,7 +7046,177 @@ static PyTypeObject __pyx_type_6imposm_5cache_2tc_CoordDB = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_6imposm_5cache_2tc_CoordDB, /*tp_new*/
+  __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*/
@@ -3523,24 +7229,24 @@ static PyTypeObject __pyx_type_6imposm_5cache_2tc_CoordDB = {
   0, /*tp_version_tag*/
   #endif
 };
-static struct __pyx_vtabstruct_6imposm_5cache_2tc_NodeDB __pyx_vtable_6imposm_5cache_2tc_NodeDB;
+static struct __pyx_vtabstruct_6imposm_5cache_2tc_InsertedWayDB __pyx_vtable_6imposm_5cache_2tc_InsertedWayDB;
 
-static PyObject *__pyx_tp_new_6imposm_5cache_2tc_NodeDB(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_6imposm_5cache_2tc_NodeDB *p;
+static PyObject *__pyx_tp_new_6imposm_5cache_2tc_InsertedWayDB(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_6imposm_5cache_2tc_InsertedWayDB *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;
+  p = ((struct __pyx_obj_6imposm_5cache_2tc_InsertedWayDB *)o);
+  p->__pyx_base.__pyx_vtab = (struct __pyx_vtabstruct_6imposm_5cache_2tc_BDB*)__pyx_vtabptr_6imposm_5cache_2tc_InsertedWayDB;
   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)},
+static PyMethodDef __pyx_methods_6imposm_5cache_2tc_InsertedWayDB[] = {
+  {__Pyx_NAMESTR("put"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_13InsertedWayDB_put, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("__next__"), (PyCFunction)__pyx_pf_6imposm_5cache_2tc_13InsertedWayDB_1__next__, METH_NOARGS|METH_COEXIST, __Pyx_DOCSTR(__pyx_doc_6imposm_5cache_2tc_13InsertedWayDB_1__next__)},
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number_NodeDB = {
+static PyNumberMethods __pyx_tp_as_number_InsertedWayDB = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -3598,7 +7304,7 @@ static PyNumberMethods __pyx_tp_as_number_NodeDB = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_NodeDB = {
+static PySequenceMethods __pyx_tp_as_sequence_InsertedWayDB = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -3611,13 +7317,13 @@ static PySequenceMethods __pyx_tp_as_sequence_NodeDB = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_NodeDB = {
+static PyMappingMethods __pyx_tp_as_mapping_InsertedWayDB = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_NodeDB = {
+static PyBufferProcs __pyx_tp_as_buffer_InsertedWayDB = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -3638,10 +7344,10 @@ static PyBufferProcs __pyx_tp_as_buffer_NodeDB = {
   #endif
 };
 
-static PyTypeObject __pyx_type_6imposm_5cache_2tc_NodeDB = {
+static PyTypeObject __pyx_type_6imposm_5cache_2tc_InsertedWayDB = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("imposm.cache.tc.NodeDB"), /*tp_name*/
-  sizeof(struct __pyx_obj_6imposm_5cache_2tc_NodeDB), /*tp_basicsize*/
+  __Pyx_NAMESTR("imposm.cache.tc.InsertedWayDB"), /*tp_name*/
+  sizeof(struct __pyx_obj_6imposm_5cache_2tc_InsertedWayDB), /*tp_basicsize*/
   0, /*tp_itemsize*/
   __pyx_tp_dealloc_6imposm_5cache_2tc_BDB, /*tp_dealloc*/
   0, /*tp_print*/
@@ -3653,15 +7359,15 @@ static PyTypeObject __pyx_type_6imposm_5cache_2tc_NodeDB = {
   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*/
+  &__pyx_tp_as_number_InsertedWayDB, /*tp_as_number*/
+  &__pyx_tp_as_sequence_InsertedWayDB, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_InsertedWayDB, /*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*/
+  &__pyx_tp_as_buffer_InsertedWayDB, /*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*/
@@ -3669,8 +7375,8 @@ static PyTypeObject __pyx_type_6imposm_5cache_2tc_NodeDB = {
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
-  0, /*tp_iternext*/
-  __pyx_methods_6imposm_5cache_2tc_NodeDB, /*tp_methods*/
+  __pyx_pf_6imposm_5cache_2tc_13InsertedWayDB_1__next__, /*tp_iternext*/
+  __pyx_methods_6imposm_5cache_2tc_InsertedWayDB, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -3680,7 +7386,7 @@ static PyTypeObject __pyx_type_6imposm_5cache_2tc_NodeDB = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_6imposm_5cache_2tc_NodeDB, /*tp_new*/
+  __pyx_tp_new_6imposm_5cache_2tc_InsertedWayDB, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -4220,31 +7926,74 @@ static struct PyModuleDef __pyx_moduledef = {
 
 static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {&__pyx_n_s_1, __pyx_k_1, sizeof(__pyx_k_1), 0, 0, 1, 1},
+  {&__pyx_n_s_2, __pyx_k_2, sizeof(__pyx_k_2), 0, 0, 1, 1},
+  {&__pyx_n_s_3, __pyx_k_3, sizeof(__pyx_k_3), 0, 0, 1, 1},
+  {&__pyx_n_s_4, __pyx_k_4, sizeof(__pyx_k_4), 0, 0, 1, 1},
+  {&__pyx_n_s__DeltaCoords, __pyx_k__DeltaCoords, sizeof(__pyx_k__DeltaCoords), 0, 0, 1, 1},
+  {&__pyx_n_s__DeltaCoordsDB, __pyx_k__DeltaCoordsDB, sizeof(__pyx_k__DeltaCoordsDB), 0, 0, 1, 1},
+  {&__pyx_n_s__DeltaNodes, __pyx_k__DeltaNodes, sizeof(__pyx_k__DeltaNodes), 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__ParseFromString, __pyx_k__ParseFromString, sizeof(__pyx_k__ParseFromString), 0, 0, 1, 1},
   {&__pyx_n_s__Relation, __pyx_k__Relation, sizeof(__pyx_k__Relation), 0, 0, 1, 1},
+  {&__pyx_n_s__SerializeToString, __pyx_k__SerializeToString, sizeof(__pyx_k__SerializeToString), 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___DeltaCoords, __pyx_k___DeltaCoords, sizeof(__pyx_k___DeltaCoords), 0, 0, 1, 1},
+  {&__pyx_n_s____init__, __pyx_k____init__, sizeof(__pyx_k____init__), 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, __pyx_k___get, sizeof(__pyx_k___get), 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__add, __pyx_k__add, sizeof(__pyx_k__add), 0, 0, 1, 1},
   {&__pyx_n_s__append, __pyx_k__append, sizeof(__pyx_k__append), 0, 0, 1, 1},
+  {&__pyx_n_s__bisect, __pyx_k__bisect, sizeof(__pyx_k__bisect), 0, 0, 1, 1},
+  {&__pyx_n_s__changed, __pyx_k__changed, sizeof(__pyx_k__changed), 0, 0, 1, 1},
+  {&__pyx_n_s__close, __pyx_k__close, sizeof(__pyx_k__close), 0, 0, 1, 1},
+  {&__pyx_n_s__collections, __pyx_k__collections, sizeof(__pyx_k__collections), 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__delta_id, __pyx_k__delta_id, sizeof(__pyx_k__delta_id), 0, 0, 1, 1},
+  {&__pyx_n_s__delta_node, __pyx_k__delta_node, sizeof(__pyx_k__delta_node), 0, 0, 1, 1},
+  {&__pyx_n_s__delta_node_ids, __pyx_k__delta_node_ids, sizeof(__pyx_k__delta_node_ids), 0, 0, 1, 1},
+  {&__pyx_n_s__delta_nodes, __pyx_k__delta_nodes, sizeof(__pyx_k__delta_nodes), 0, 0, 1, 1},
+  {&__pyx_n_s__delta_nodes_size, __pyx_k__delta_nodes_size, sizeof(__pyx_k__delta_nodes_size), 0, 0, 1, 1},
+  {&__pyx_n_s__deque, __pyx_k__deque, sizeof(__pyx_k__deque), 0, 0, 1, 1},
+  {&__pyx_n_s__deserialize, __pyx_k__deserialize, sizeof(__pyx_k__deserialize), 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__fetch_delta_node, __pyx_k__fetch_delta_node, sizeof(__pyx_k__fetch_delta_node), 0, 0, 1, 1},
   {&__pyx_n_s__filename, __pyx_k__filename, sizeof(__pyx_k__filename), 0, 0, 1, 1},
+  {&__pyx_n_s__get, __pyx_k__get, sizeof(__pyx_k__get), 0, 0, 1, 1},
+  {&__pyx_n_s__get_coords, __pyx_k__get_coords, sizeof(__pyx_k__get_coords), 0, 0, 1, 1},
+  {&__pyx_n_s__get_raw, __pyx_k__get_raw, sizeof(__pyx_k__get_raw), 0, 0, 1, 1},
+  {&__pyx_n_s__ids, __pyx_k__ids, sizeof(__pyx_k__ids), 0, 0, 1, 1},
+  {&__pyx_n_s__insort, __pyx_k__insort, sizeof(__pyx_k__insort), 0, 0, 1, 1},
+  {&__pyx_n_s__iteritems, __pyx_k__iteritems, sizeof(__pyx_k__iteritems), 0, 0, 1, 1},
+  {&__pyx_n_s__lat, __pyx_k__lat, sizeof(__pyx_k__lat), 0, 0, 1, 1},
+  {&__pyx_n_s__lats, __pyx_k__lats, sizeof(__pyx_k__lats), 0, 0, 1, 1},
+  {&__pyx_n_s__lon, __pyx_k__lon, sizeof(__pyx_k__lon), 0, 0, 1, 1},
+  {&__pyx_n_s__lons, __pyx_k__lons, sizeof(__pyx_k__lons), 0, 0, 1, 1},
   {&__pyx_n_s__mode, __pyx_k__mode, sizeof(__pyx_k__mode), 0, 0, 1, 1},
+  {&__pyx_n_s__nodes, __pyx_k__nodes, sizeof(__pyx_k__nodes), 0, 0, 1, 1},
+  {&__pyx_n_s__object, __pyx_k__object, sizeof(__pyx_k__object), 0, 0, 1, 1},
   {&__pyx_n_s__osmid, __pyx_k__osmid, sizeof(__pyx_k__osmid), 0, 0, 1, 1},
+  {&__pyx_n_s__osmids, __pyx_k__osmids, sizeof(__pyx_k__osmids), 0, 0, 1, 1},
+  {&__pyx_n_s__pop, __pyx_k__pop, sizeof(__pyx_k__pop), 0, 0, 1, 1},
+  {&__pyx_n_s__popleft, __pyx_k__popleft, sizeof(__pyx_k__popleft), 0, 0, 1, 1},
   {&__pyx_n_s__pos, __pyx_k__pos, sizeof(__pyx_k__pos), 0, 0, 1, 1},
+  {&__pyx_n_s__put, __pyx_k__put, sizeof(__pyx_k__put), 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__range, __pyx_k__range, sizeof(__pyx_k__range), 0, 0, 1, 1},
   {&__pyx_n_s__refs, __pyx_k__refs, sizeof(__pyx_k__refs), 0, 0, 1, 1},
+  {&__pyx_n_s__self, __pyx_k__self, sizeof(__pyx_k__self), 0, 0, 1, 1},
+  {&__pyx_n_s__serialize, __pyx_k__serialize, sizeof(__pyx_k__serialize), 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},
@@ -4252,8 +8001,10 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {0, 0, 0, 0, 0, 0, 0}
 };
 static int __Pyx_InitCachedBuiltins(void) {
+  __pyx_builtin_object = __Pyx_GetName(__pyx_b, __pyx_n_s__object); if (!__pyx_builtin_object) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 353; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __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;}
+  __pyx_builtin_StopIteration = __Pyx_GetName(__pyx_b, __pyx_n_s__StopIteration); if (!__pyx_builtin_StopIteration) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 182; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_range = __Pyx_GetName(__pyx_b, __pyx_n_s__range); if (!__pyx_builtin_range) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 341; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   return 0;
   __pyx_L1_error:;
   return -1;
@@ -4269,6 +8020,8 @@ 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_6 = PyInt_FromLong(6); if (unlikely(!__pyx_int_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_100 = PyInt_FromLong(100); if (unlikely(!__pyx_int_100)) {__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:;
@@ -4285,6 +8038,7 @@ PyMODINIT_FUNC PyInit_tc(void)
 {
   PyObject *__pyx_t_1 = NULL;
   PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
   #if CYTHON_REFNANNY
   void* __pyx_refnanny = NULL;
   __Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny");
@@ -4340,17 +8094,17 @@ PyMODINIT_FUNC PyInit_tc(void)
   {
     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__;
+      __pyx_wrapperbase_6imposm_5cache_2tc_3BDB_7__iter__ = *((PyWrapperDescrObject *)wrapper)->d_base;
+      __pyx_wrapperbase_6imposm_5cache_2tc_3BDB_7__iter__.doc = __pyx_doc_6imposm_5cache_2tc_3BDB_7__iter__;
+      ((PyWrapperDescrObject *)wrapper)->d_base = &__pyx_wrapperbase_6imposm_5cache_2tc_3BDB_7__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__;
+      __pyx_wrapperbase_6imposm_5cache_2tc_3BDB_10__next__ = *((PyWrapperDescrObject *)wrapper)->d_base;
+      __pyx_wrapperbase_6imposm_5cache_2tc_3BDB_10__next__.doc = __pyx_doc_6imposm_5cache_2tc_3BDB_10__next__;
+      ((PyWrapperDescrObject *)wrapper)->d_base = &__pyx_wrapperbase_6imposm_5cache_2tc_3BDB_10__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;}
@@ -4362,40 +8116,55 @@ PyMODINIT_FUNC PyInit_tc(void)
   __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;}
+  if (PyType_Ready(&__pyx_type_6imposm_5cache_2tc_CoordDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 217; __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 = 217; __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 = 217; __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;}
+  if (PyType_Ready(&__pyx_type_6imposm_5cache_2tc_NodeDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 260; __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 = 260; __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 = 260; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_6imposm_5cache_2tc_NodeDB = &__pyx_type_6imposm_5cache_2tc_NodeDB;
+  __pyx_vtabptr_6imposm_5cache_2tc_InsertedWayDB = &__pyx_vtable_6imposm_5cache_2tc_InsertedWayDB;
+  __pyx_vtable_6imposm_5cache_2tc_InsertedWayDB.__pyx_base = *__pyx_vtabptr_6imposm_5cache_2tc_BDB;
+  __pyx_type_6imposm_5cache_2tc_InsertedWayDB.tp_base = __pyx_ptype_6imposm_5cache_2tc_BDB;
+  if (PyType_Ready(&__pyx_type_6imposm_5cache_2tc_InsertedWayDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  {
+    PyObject *wrapper = __Pyx_GetAttrString((PyObject *)&__pyx_type_6imposm_5cache_2tc_InsertedWayDB, "__next__"); if (unlikely(!wrapper)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (Py_TYPE(wrapper) == &PyWrapperDescr_Type) {
+      __pyx_wrapperbase_6imposm_5cache_2tc_13InsertedWayDB_1__next__ = *((PyWrapperDescrObject *)wrapper)->d_base;
+      __pyx_wrapperbase_6imposm_5cache_2tc_13InsertedWayDB_1__next__.doc = __pyx_doc_6imposm_5cache_2tc_13InsertedWayDB_1__next__;
+      ((PyWrapperDescrObject *)wrapper)->d_base = &__pyx_wrapperbase_6imposm_5cache_2tc_13InsertedWayDB_1__next__;
+    }
+  }
+  if (__Pyx_SetVtable(__pyx_type_6imposm_5cache_2tc_InsertedWayDB.tp_dict, __pyx_vtabptr_6imposm_5cache_2tc_InsertedWayDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "InsertedWayDB", (PyObject *)&__pyx_type_6imposm_5cache_2tc_InsertedWayDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_6imposm_5cache_2tc_InsertedWayDB = &__pyx_type_6imposm_5cache_2tc_InsertedWayDB;
   __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;}
+  if (PyType_Ready(&__pyx_type_6imposm_5cache_2tc_RefTagDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 294; __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 = 294; __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 = 294; __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;}
+  if (PyType_Ready(&__pyx_type_6imposm_5cache_2tc_WayDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 304; __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 = 304; __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 = 304; __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;}
+  if (PyType_Ready(&__pyx_type_6imposm_5cache_2tc_RelationDB) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 308; __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 = 308; __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 = 308; __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 ---*/
@@ -4417,7 +8186,7 @@ PyMODINIT_FUNC PyInit_tc(void)
   __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_t_2 = __Pyx_Import(((PyObject *)__pyx_n_s_2), ((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;}
@@ -4470,6 +8239,298 @@ PyMODINIT_FUNC PyInit_tc(void)
   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":312
+ *         return Relation(osmid, data[0], data[1])
+ * 
+ * from imposm.cache.internal import DeltaCoords as _DeltaCoords             # <<<<<<<<<<<<<<
+ * from collections import deque
+ * import bisect
+ */
+  __pyx_t_2 = PyList_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 312; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  __Pyx_INCREF(((PyObject *)__pyx_n_s__DeltaCoords));
+  PyList_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_n_s__DeltaCoords));
+  __Pyx_GIVEREF(((PyObject *)__pyx_n_s__DeltaCoords));
+  __pyx_t_1 = __Pyx_Import(((PyObject *)__pyx_n_s_3), ((PyObject *)__pyx_t_2)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 312; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_GetAttr(__pyx_t_1, __pyx_n_s__DeltaCoords); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 312; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s___DeltaCoords, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 312; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":313
+ * 
+ * from imposm.cache.internal import DeltaCoords as _DeltaCoords
+ * from collections import deque             # <<<<<<<<<<<<<<
+ * import bisect
+ * 
+ */
+  __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 313; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __Pyx_INCREF(((PyObject *)__pyx_n_s__deque));
+  PyList_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_n_s__deque));
+  __Pyx_GIVEREF(((PyObject *)__pyx_n_s__deque));
+  __pyx_t_2 = __Pyx_Import(((PyObject *)__pyx_n_s__collections), ((PyObject *)__pyx_t_1)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 313; __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__deque); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 313; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__deque, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 313; __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":314
+ * from imposm.cache.internal import DeltaCoords as _DeltaCoords
+ * from collections import deque
+ * import bisect             # <<<<<<<<<<<<<<
+ * 
+ * cdef unzip_nodes(list nodes):
+ */
+  __pyx_t_2 = __Pyx_Import(((PyObject *)__pyx_n_s__bisect), 0); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 314; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__bisect, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 314; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+  /* "imposm/cache/tc.pyx":353
+ *     return nodes
+ * 
+ * class DeltaNodes(object):             # <<<<<<<<<<<<<<
+ *     def __init__(self, data=None):
+ *         self.nodes = []
+ */
+  __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 353; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+
+  /* "imposm/cache/tc.pyx":354
+ * 
+ * class DeltaNodes(object):
+ *     def __init__(self, data=None):             # <<<<<<<<<<<<<<
+ *         self.nodes = []
+ *         self.changed = False
+ */
+  __pyx_t_1 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_6imposm_5cache_2tc_10DeltaNodes___init__, NULL, __pyx_n_s_4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 354; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyObject_SetItem(__pyx_t_2, __pyx_n_s____init__, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 354; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":360
+ *             self.deserialize(data)
+ * 
+ *     def changed(self):             # <<<<<<<<<<<<<<
+ *         return self.changed
+ * 
+ */
+  __pyx_t_1 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_6imposm_5cache_2tc_10DeltaNodes_1changed, NULL, __pyx_n_s_4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 360; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyObject_SetItem(__pyx_t_2, __pyx_n_s__changed, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 360; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":363
+ *         return self.changed
+ * 
+ *     def get(self, int64_t osmid):             # <<<<<<<<<<<<<<
+ *         i = bisect.bisect(self.nodes, (osmid, ))
+ *         if i != len(self.nodes) and self.nodes[i][0] == osmid:
+ */
+  __pyx_t_1 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_6imposm_5cache_2tc_10DeltaNodes_2get, NULL, __pyx_n_s_4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 363; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyObject_SetItem(__pyx_t_2, __pyx_n_s__get, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 363; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":369
+ *         return None
+ * 
+ *     def add(self, int64_t osmid, double lon, double lat):             # <<<<<<<<<<<<<<
+ *         # todo: overwrite
+ *         self.changed = True
+ */
+  __pyx_t_1 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_6imposm_5cache_2tc_10DeltaNodes_3add, NULL, __pyx_n_s_4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyObject_SetItem(__pyx_t_2, __pyx_n_s__add, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":377
+ *             bisect.insort(self.nodes, (osmid, lon, lat))
+ * 
+ *     def serialize(self):             # <<<<<<<<<<<<<<
+ *         ids, lons, lats = unzip_nodes(self.nodes)
+ *         nodes = _DeltaCoords()
+ */
+  __pyx_t_1 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_6imposm_5cache_2tc_10DeltaNodes_4serialize, NULL, __pyx_n_s_4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 377; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyObject_SetItem(__pyx_t_2, __pyx_n_s__serialize, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 377; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":385
+ *         return nodes.SerializeToString()
+ * 
+ *     def deserialize(self, data):             # <<<<<<<<<<<<<<
+ *         nodes = _DeltaCoords()
+ *         nodes.ParseFromString(data)
+ */
+  __pyx_t_1 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_6imposm_5cache_2tc_10DeltaNodes_5deserialize, NULL, __pyx_n_s_4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 385; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyObject_SetItem(__pyx_t_2, __pyx_n_s__deserialize, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 385; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "imposm/cache/tc.pyx":353
+ *     return nodes
+ * 
+ * class DeltaNodes(object):             # <<<<<<<<<<<<<<
+ *     def __init__(self, data=None):
+ *         self.nodes = []
+ */
+  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 353; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __Pyx_INCREF(__pyx_builtin_object);
+  PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_builtin_object);
+  __Pyx_GIVEREF(__pyx_builtin_object);
+  __pyx_t_3 = __Pyx_CreateClass(((PyObject *)__pyx_t_1), ((PyObject *)__pyx_t_2), __pyx_n_s__DeltaNodes, __pyx_n_s_4); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 353; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__DeltaNodes, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 353; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+
+  /* "imposm/cache/tc.pyx":391
+ *             nodes.ids, nodes.lons, nodes.lats)
+ * 
+ * class DeltaCoordsDB(object):             # <<<<<<<<<<<<<<
+ *     def __init__(self, filename, mode='w', estimated_records=0, delta_nodes_cache_size=100, delta_nodes_size=6):
+ *         self.db = BDB(filename, mode, estimated_records)
+ */
+  __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 391; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+
+  /* "imposm/cache/tc.pyx":392
+ * 
+ * class DeltaCoordsDB(object):
+ *     def __init__(self, filename, mode='w', estimated_records=0, delta_nodes_cache_size=100, delta_nodes_size=6):             # <<<<<<<<<<<<<<
+ *         self.db = BDB(filename, mode, estimated_records)
+ *         self.mode = mode
+ */
+  __pyx_t_3 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_6imposm_5cache_2tc_13DeltaCoordsDB___init__, NULL, __pyx_n_s_4); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 392; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  if (PyObject_SetItem(__pyx_t_2, __pyx_n_s____init__, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 392; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+
+  /* "imposm/cache/tc.pyx":400
+ *         self.delta_nodes_size = delta_nodes_size
+ * 
+ *     def put(self, int64_t osmid, double lon, double lat):             # <<<<<<<<<<<<<<
+ *         if self.mode == 'r':
+ *             return None
+ */
+  __pyx_t_3 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_6imposm_5cache_2tc_13DeltaCoordsDB_1put, NULL, __pyx_n_s_4); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 400; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  if (PyObject_SetItem(__pyx_t_2, __pyx_n_s__put, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 400; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+
+  /* "imposm/cache/tc.pyx":410
+ *         return True
+ * 
+ *     put_marshaled = put             # <<<<<<<<<<<<<<
+ * 
+ *     def get(self, osmid):
+ */
+  __pyx_t_3 = PyObject_GetItem(__pyx_t_2, __pyx_n_s__put); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 410; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  if (PyObject_SetItem(__pyx_t_2, __pyx_n_s__put_marshaled, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 410; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+
+  /* "imposm/cache/tc.pyx":412
+ *     put_marshaled = put
+ * 
+ *     def get(self, osmid):             # <<<<<<<<<<<<<<
+ *         delta_id = osmid >> self.delta_nodes_size
+ *         if delta_id not in self.delta_nodes:
+ */
+  __pyx_t_3 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_6imposm_5cache_2tc_13DeltaCoordsDB_2get, NULL, __pyx_n_s_4); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 412; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  if (PyObject_SetItem(__pyx_t_2, __pyx_n_s__get, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 412; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+
+  /* "imposm/cache/tc.pyx":418
+ *         return self.delta_nodes[delta_id].get(osmid)
+ * 
+ *     def get_coords(self, osmids):             # <<<<<<<<<<<<<<
+ *         coords = []
+ *         for osmid in osmids:
+ */
+  __pyx_t_3 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_6imposm_5cache_2tc_13DeltaCoordsDB_3get_coords, NULL, __pyx_n_s_4); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 418; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  if (PyObject_SetItem(__pyx_t_2, __pyx_n_s__get_coords, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 418; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+
+  /* "imposm/cache/tc.pyx":427
+ *         return coords
+ * 
+ *     def close(self):             # <<<<<<<<<<<<<<
+ *         for node_id, node in self.delta_nodes.iteritems():
+ *             self._put(node_id, node)
+ */
+  __pyx_t_3 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_6imposm_5cache_2tc_13DeltaCoordsDB_4close, NULL, __pyx_n_s_4); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 427; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  if (PyObject_SetItem(__pyx_t_2, __pyx_n_s__close, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 427; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+
+  /* "imposm/cache/tc.pyx":434
+ *         self.db.close()
+ * 
+ *     def _put(self, delta_id, delta_node):             # <<<<<<<<<<<<<<
+ *         data = delta_node.serialize()
+ *         self.db.put_marshaled(delta_id, data)
+ */
+  __pyx_t_3 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_6imposm_5cache_2tc_13DeltaCoordsDB_5_put, NULL, __pyx_n_s_4); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 434; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  if (PyObject_SetItem(__pyx_t_2, __pyx_n_s___put, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 434; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+
+  /* "imposm/cache/tc.pyx":438
+ *         self.db.put_marshaled(delta_id, data)
+ * 
+ *     def _get(self, delta_id):             # <<<<<<<<<<<<<<
+ *         return DeltaNodes(data=self.db.get_raw(delta_id))
+ * 
+ */
+  __pyx_t_3 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_6imposm_5cache_2tc_13DeltaCoordsDB_6_get, NULL, __pyx_n_s_4); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 438; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  if (PyObject_SetItem(__pyx_t_2, __pyx_n_s___get, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 438; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+
+  /* "imposm/cache/tc.pyx":441
+ *         return DeltaNodes(data=self.db.get_raw(delta_id))
+ * 
+ *     def fetch_delta_node(self, delta_id):             # <<<<<<<<<<<<<<
+ *         if len(self.delta_node_ids) >= self.delta_nodes_cache_size:
+ *             rm_id = self.delta_node_ids.popleft()
+ */
+  __pyx_t_3 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_6imposm_5cache_2tc_13DeltaCoordsDB_7fetch_delta_node, NULL, __pyx_n_s_4); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 441; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  if (PyObject_SetItem(__pyx_t_2, __pyx_n_s__fetch_delta_node, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 441; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+
+  /* "imposm/cache/tc.pyx":391
+ *             nodes.ids, nodes.lons, nodes.lats)
+ * 
+ * class DeltaCoordsDB(object):             # <<<<<<<<<<<<<<
+ *     def __init__(self, filename, mode='w', estimated_records=0, delta_nodes_cache_size=100, delta_nodes_size=6):
+ *         self.db = BDB(filename, mode, estimated_records)
+ */
+  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 391; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_3));
+  __Pyx_INCREF(__pyx_builtin_object);
+  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_builtin_object);
+  __Pyx_GIVEREF(__pyx_builtin_object);
+  __pyx_t_1 = __Pyx_CreateClass(((PyObject *)__pyx_t_3), ((PyObject *)__pyx_t_2), __pyx_n_s__DeltaCoordsDB, __pyx_n_s_4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 391; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__DeltaCoordsDB, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 391; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __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
@@ -4483,6 +8544,7 @@ PyMODINIT_FUNC PyInit_tc(void)
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
   __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
   if (__pyx_m) {
     __Pyx_AddTraceback("init imposm.cache.tc");
     Py_DECREF(__pyx_m); __pyx_m = 0;
@@ -4843,6 +8905,117 @@ bad:
     return module;
 }
 
+static PyObject *__Pyx_FindPy2Metaclass(PyObject *bases) {
+    PyObject *metaclass;
+    /* Default metaclass */
+#if PY_MAJOR_VERSION < 3
+    if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
+        PyObject *base = PyTuple_GET_ITEM(bases, 0);
+        metaclass = PyObject_GetAttrString(base, "__class__");
+        if (!metaclass) {
+            PyErr_Clear();
+            metaclass = (PyObject*) Py_TYPE(base);
+        }
+    } else {
+        metaclass = (PyObject *) &PyClass_Type;
+    }
+#else
+    if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
+        PyObject *base = PyTuple_GET_ITEM(bases, 0);
+        metaclass = (PyObject*) Py_TYPE(base);
+    } else {
+        metaclass = (PyObject *) &PyType_Type;
+    }
+#endif
+    Py_INCREF(metaclass);
+    return metaclass;
+}
+
+static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name,
+                                   PyObject *modname) {
+    PyObject *result;
+    PyObject *metaclass;
+
+    if (PyDict_SetItemString(dict, "__module__", modname) < 0)
+        return NULL;
+
+    /* Python2 __metaclass__ */
+    metaclass = PyDict_GetItemString(dict, "__metaclass__");
+    if (metaclass) {
+        Py_INCREF(metaclass);
+    } else {
+        metaclass = __Pyx_FindPy2Metaclass(bases);
+    }
+    result = PyObject_CallFunctionObjArgs(metaclass, name, bases, dict, NULL);
+    Py_DECREF(metaclass);
+    return result;
+}
+
+
+static PyObject *__pyx_binding_PyCFunctionType_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) {
+	__pyx_binding_PyCFunctionType_object *op = PyObject_GC_New(__pyx_binding_PyCFunctionType_object, __pyx_binding_PyCFunctionType);
+    if (op == NULL)
+        return NULL;
+	op->func.m_ml = ml;
+	Py_XINCREF(self);
+	op->func.m_self = self;
+	Py_XINCREF(module);
+	op->func.m_module = module;
+	PyObject_GC_Track(op);
+	return (PyObject *)op;
+}
+
+static void __pyx_binding_PyCFunctionType_dealloc(__pyx_binding_PyCFunctionType_object *m) {
+	PyObject_GC_UnTrack(m);
+	Py_XDECREF(m->func.m_self);
+	Py_XDECREF(m->func.m_module);
+    PyObject_GC_Del(m);
+}
+
+static PyObject *__pyx_binding_PyCFunctionType_descr_get(PyObject *func, PyObject *obj, PyObject *type) {
+	if (obj == Py_None)
+		obj = NULL;
+	return PyMethod_New(func, obj, type);
+}
+
+static int __pyx_binding_PyCFunctionType_init(void) {
+    __pyx_binding_PyCFunctionType_type = PyCFunction_Type;
+    __pyx_binding_PyCFunctionType_type.tp_name = __Pyx_NAMESTR("cython_binding_builtin_function_or_method");
+    __pyx_binding_PyCFunctionType_type.tp_dealloc = (destructor)__pyx_binding_PyCFunctionType_dealloc;
+    __pyx_binding_PyCFunctionType_type.tp_descr_get = __pyx_binding_PyCFunctionType_descr_get;
+    if (PyType_Ready(&__pyx_binding_PyCFunctionType_type) < 0) {
+        return -1;
+    }
+    __pyx_binding_PyCFunctionType = &__pyx_binding_PyCFunctionType_type;
+    return 0;
+
+}
+
+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 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;
@@ -4895,19 +9068,19 @@ static CYTHON_INLINE int64_t __Pyx_PyInt_from_py_int64_t(PyObject* x) {
     }
 }
 
-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;
+static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_uint32_t(uint32_t val) {
+    const uint32_t neg_one = (uint32_t)-1, const_zero = (uint32_t)0;
     const int is_unsigned = const_zero < neg_one;
-    if ((sizeof(int64_t) == sizeof(char))  ||
-        (sizeof(int64_t) == sizeof(short))) {
+    if ((sizeof(uint32_t) == sizeof(char))  ||
+        (sizeof(uint32_t) == sizeof(short))) {
         return PyInt_FromLong((long)val);
-    } else if ((sizeof(int64_t) == sizeof(int)) ||
-               (sizeof(int64_t) == sizeof(long))) {
+    } else if ((sizeof(uint32_t) == sizeof(int)) ||
+               (sizeof(uint32_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)) {
+    } else if (sizeof(uint32_t) == sizeof(PY_LONG_LONG)) {
         if (is_unsigned)
             return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)val);
         else
@@ -4915,11 +9088,63 @@ static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_int64_t(int64_t val) {
     } else {
         int one = 1; int little = (int)*(unsigned char *)&one;
         unsigned char *bytes = (unsigned char *)&val;
-        return _PyLong_FromByteArray(bytes, sizeof(int64_t), 
+        return _PyLong_FromByteArray(bytes, sizeof(uint32_t), 
                                      little, !is_unsigned);
     }
 }
 
+static CYTHON_INLINE uint32_t __Pyx_PyInt_from_py_uint32_t(PyObject* x) {
+    const uint32_t neg_one = (uint32_t)-1, const_zero = (uint32_t)0;
+    const int is_unsigned = const_zero < neg_one;
+    if (sizeof(uint32_t) == sizeof(char)) {
+        if (is_unsigned)
+            return (uint32_t)__Pyx_PyInt_AsUnsignedChar(x);
+        else
+            return (uint32_t)__Pyx_PyInt_AsSignedChar(x);
+    } else if (sizeof(uint32_t) == sizeof(short)) {
+        if (is_unsigned)
+            return (uint32_t)__Pyx_PyInt_AsUnsignedShort(x);
+        else
+            return (uint32_t)__Pyx_PyInt_AsSignedShort(x);
+    } else if (sizeof(uint32_t) == sizeof(int)) {
+        if (is_unsigned)
+            return (uint32_t)__Pyx_PyInt_AsUnsignedInt(x);
+        else
+            return (uint32_t)__Pyx_PyInt_AsSignedInt(x);
+    } else if (sizeof(uint32_t) == sizeof(long)) {
+        if (is_unsigned)
+            return (uint32_t)__Pyx_PyInt_AsUnsignedLong(x);
+        else
+            return (uint32_t)__Pyx_PyInt_AsSignedLong(x);
+    } else if (sizeof(uint32_t) == sizeof(PY_LONG_LONG)) {
+        if (is_unsigned)
+            return (uint32_t)__Pyx_PyInt_AsUnsignedLongLong(x);
+        else
+            return (uint32_t)__Pyx_PyInt_AsSignedLongLong(x);
+    }  else {
+        uint32_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 (uint32_t)-1;
+    }
+}
+
 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;
diff --git a/imposm/cache/tc.pyx b/imposm/cache/tc.pyx
index e9111ae..6278907 100644
--- a/imposm/cache/tc.pyx
+++ b/imposm/cache/tc.pyx
@@ -101,7 +101,7 @@ cdef class BDB:
         self._tune_db(estimated_records)
         tcbdbsetcmpfunc(self.db, tccmpint64, NULL)
         if not tcbdbopen(self.db, filename, _modes[mode]):
-            raise IOError
+            raise IOError(tcbdbecode(self.db))
         self._opened = 1
     
     def _tune_db(self, estimated_records):
@@ -125,12 +125,29 @@ cdef class BDB:
         if not ret: return None
         return self._obj(osmid, PyMarshal_ReadObjectFromString(<char *>ret, ret_size))
 
+    def get_raw(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 PyString_FromStringAndSize(<char *>ret, ret_size)
+
+    def put(self, int64_t osmid, data):
+        return self.put_marshaled(osmid, PyMarshal_WriteObjectToString(data, 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):
         """
         Create an object from the id and unmarshaled data.
         Should be overridden by subclasses.
         """
-        pass
+        return data
 
     def __iter__(self):
         """
@@ -250,6 +267,30 @@ cdef class NodeDB(BDB):
     cdef object _obj(self, int64_t osmid, data):
         return Node(osmid, data[0], data[1])
 
+cdef class InsertedWayDB(BDB):
+    def put(self, int64_t osmid):
+        return tcbdbput(self.db, <char *>&osmid, sizeof(int64_t), 'x', 1);
+
+    def __next__(self):
+        """
+        Return next item as object.
+        """
+        cdef int64_t osmid
+        cdef int size
+        cdef void *ret
+
+        if not self._cur: raise StopIteration
+
+        ret = tcbdbcurkey3(self._cur, &size)
+        osmid = (<int64_t *>ret)[0]
+
+        # advance cursor, set to NULL if at the end
+        if tcbdbcurnext(self._cur) == 0:
+            tcbdbcurdel(self._cur)
+            self._cur = NULL
+
+        return osmid
+
 cdef class RefTagDB(BDB):
     """
     Database for items with references and tags (i.e. ways/relations).
@@ -267,3 +308,145 @@ cdef class WayDB(RefTagDB):
 cdef class RelationDB(RefTagDB):
     cdef object _obj(self, int64_t osmid, data):
         return Relation(osmid, data[0], data[1])
+
+from imposm.cache.internal import DeltaCoords as _DeltaCoords
+from collections import deque
+import bisect
+
+cdef unzip_nodes(list nodes):
+    cdef int64_t last_lon, last_lat, lon, lat
+    cdef double lon_f, lat_f
+    cdef int64_t last_id, id
+    ids, lons, lats = [], [], []
+    last_id = last_lon = last_lat = 0
+    for id, lon_f, lat_f in nodes:
+        lon = _coord_to_uint32(lon_f)
+        lat = _coord_to_uint32(lat_f)
+        
+        ids.append(id - last_id)
+        lons.append(lon - last_lon)
+        lats.append(lat - last_lat)
+        last_id = id
+        last_lon = lon
+        last_lat = lat
+    
+    return ids, lons, lats
+
+cdef zip_nodes(tuple ids, tuple lons, tuple lats):
+    cdef uint32_t last_lon, last_lat
+    cdef int64_t last_id
+    nodes = []
+    last_id = last_lon = last_lat = 0
+
+    for i in range(len(ids)):
+        last_id += ids[i]
+        last_lon += lons[i]
+        last_lat += lats[i]
+    
+        nodes.append((
+            last_id,
+            _uint32_to_coord(last_lon),
+            _uint32_to_coord(last_lat)
+        ))
+    return nodes
+
+class DeltaNodes(object):
+    def __init__(self, data=None):
+        self.nodes = []
+        self.changed = False
+        if data:
+            self.deserialize(data)
+    
+    def changed(self):
+        return self.changed
+    
+    def get(self, int64_t osmid):
+        i = bisect.bisect(self.nodes, (osmid, ))
+        if i != len(self.nodes) and self.nodes[i][0] == osmid:
+            return self.nodes[i][1:]
+        return None
+    
+    def add(self, int64_t osmid, double lon, double lat):
+        # todo: overwrite
+        self.changed = True
+        if self.nodes and self.nodes[-1][0] < osmid:
+            self.nodes.append((osmid, lon, lat))
+        else:
+            bisect.insort(self.nodes, (osmid, lon, lat))
+    
+    def serialize(self):
+        ids, lons, lats = unzip_nodes(self.nodes)
+        nodes = _DeltaCoords()
+        nodes.ids = ids
+        nodes.lons = lons
+        nodes.lats = lats
+        return nodes.SerializeToString()
+    
+    def deserialize(self, data):
+        nodes = _DeltaCoords()
+        nodes.ParseFromString(data)
+        self.nodes = zip_nodes(
+            nodes.ids, nodes.lons, nodes.lats)
+
+class DeltaCoordsDB(object):
+    def __init__(self, filename, mode='w', estimated_records=0, delta_nodes_cache_size=100, delta_nodes_size=6):
+        self.db = BDB(filename, mode, estimated_records)
+        self.mode = mode
+        self.delta_nodes = {}
+        self.delta_node_ids = deque()
+        self.delta_nodes_cache_size = delta_nodes_cache_size
+        self.delta_nodes_size = delta_nodes_size
+    
+    def put(self, int64_t osmid, double lon, double lat):
+        if self.mode == 'r':
+            return None
+        delta_id = osmid >> self.delta_nodes_size
+        if delta_id not in self.delta_nodes:
+            self.fetch_delta_node(delta_id)
+        delta_node = self.delta_nodes[delta_id]
+        delta_node.add(osmid, lon, lat)
+        return True
+    
+    put_marshaled = put
+    
+    def get(self, osmid):
+        delta_id = osmid >> self.delta_nodes_size
+        if delta_id not in self.delta_nodes:
+            self.fetch_delta_node(delta_id)
+        return self.delta_nodes[delta_id].get(osmid)
+    
+    def get_coords(self, osmids):
+        coords = []
+        for osmid in osmids:
+            coord = self.get(osmid)
+            if coord is None:
+                return
+            coords.append(coord)
+        return coords
+    
+    def close(self):
+        for node_id, node in self.delta_nodes.iteritems():
+            self._put(node_id, node)
+        self.delta_nodes = {}
+        self.delta_node_ids = deque()
+        self.db.close()
+    
+    def _put(self, delta_id, delta_node):
+        data = delta_node.serialize()
+        self.db.put_marshaled(delta_id, data)
+    
+    def _get(self, delta_id):
+        return DeltaNodes(data=self.db.get_raw(delta_id))
+    
+    def fetch_delta_node(self, delta_id):
+        if len(self.delta_node_ids) >= self.delta_nodes_cache_size:
+            rm_id = self.delta_node_ids.popleft()
+            rm_node = self.delta_nodes.pop(rm_id)
+            if rm_node.changed:
+                self._put(rm_id, rm_node)
+        new_node = self._get(delta_id)
+        if new_node is None:
+            new_node = DeltaNodes()
+        self.delta_nodes[delta_id] = new_node
+        self.delta_node_ids.append(delta_id)
+
diff --git a/imposm/version.py b/imposm/config.py
similarity index 65%
copy from imposm/version.py
copy to imposm/config.py
index b70c049..4b3d3c9 100644
--- a/imposm/version.py
+++ b/imposm/config.py
@@ -12,4 +12,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-__version__ = '2.1.3'
+# import relations with missing rings
+import_partial_relations = False
+
+# select relation builder: union or contains
+relation_builder = 'contains'
+
+# log relation that take longer than x seconds
+imposm_multipolygon_report = 60
+
+# skip relations with more rings (0 skip nothing)
+imposm_multipolygon_max_ring = 0
diff --git a/imposm/db/__init__.py b/imposm/db/__init__.py
index 14129d9..e69de29 100644
--- a/imposm/db/__init__.py
+++ b/imposm/db/__init__.py
@@ -1,4 +0,0 @@
-from . postgis import PostGISDB
-
-def DB(db_conf):
-    return PostGISDB(db_conf)
\ No newline at end of file
diff --git a/imposm/db/config.py b/imposm/db/config.py
new file mode 100644
index 0000000..efb8121
--- /dev/null
+++ b/imposm/db/config.py
@@ -0,0 +1,73 @@
+# 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 re
+import cgi
+import urllib
+
+from . postgis import PostGISDB
+from .. mapping import Options
+
+def DB(db_conf):
+    if db_conf.get('name', 'postgis') == 'postgis':
+        # default and backwards compat
+        return PostGISDB(db_conf)
+    raise ValueError('unknown db: %s' % (db_conf.name,))
+
+def db_conf_from_string(conf, base_db_conf):
+    db_conf = _parse_rfc1738_args(conf)
+    if 'proj' not in db_conf:
+        db_conf.proj = base_db_conf.proj
+    if 'prefix' not in db_conf:
+        db_conf.prefix = base_db_conf.prefix
+    return db_conf
+
+
+def _parse_rfc1738_args(name):
+    # from SQLAlchemy lib/sqlalchemy/engine/url.py
+    # MIT licensed
+    pattern = re.compile(r'''
+            (?P<name>\w+)://
+            (?:
+                (?P<user>[^:/]*)
+                (?::(?P<password>[^/]*))?
+            @)?
+            (?:
+                (?P<host>[^/:]*)
+                (?::(?P<port>[^/]*))?
+            )?
+            (?:/(?P<db>.*))?
+            '''
+            , re.X)
+
+    m = pattern.match(name)
+    if m is not None:
+        components = m.groupdict()
+        if components['db'] is not None:
+            tokens = components['db'].split('?', 2)
+            components['db'] = tokens[0]
+            query = (len(tokens) > 1 and dict(cgi.parse_qsl(tokens[1]))) or None
+            if query is not None:
+                query = dict((k.encode('ascii'), query[k]) for k in query)
+        else:
+            query = None
+        components['query'] = query
+
+        if components['password'] is not None:
+            components['password'] = urllib.unquote_plus(components['password'])
+
+        return Options(**components)
+    else:
+        raise ValueError(
+            "Could not parse rfc1738 URL from string '%s'" % name)
diff --git a/imposm/db/postgis.py b/imposm/db/postgis.py
index 5382102..b56557c 100644
--- a/imposm/db/postgis.py
+++ b/imposm/db/postgis.py
@@ -32,25 +32,32 @@ class PostGISDB(object):
 
     @property
     def table_prefix(self):
-        return self.db_conf.prefix
+        return self.db_conf.prefix.rstrip('_') + '_'
 
     def to_tablename(self, name):
-        return self.table_prefix.rstrip('_') + '_' + name.lower()
+        return self.table_prefix + name.lower()
 
     @property
     def connection(self):
         if not self._connection:
+            kw = {}
+            if self.db_conf.port:
+                kw['port'] = int(self.db_conf.port)
             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'),
+                **kw
             )
             self._connection.set_isolation_level(
                 psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED)
         return self._connection
     
+    def commit(self):
+        self.connection.commit()
+    
     @property
     def cur(self):
         if self._cur is None:
@@ -84,8 +91,8 @@ class PostGISDB(object):
 
         self.connection.commit()
     
-    def wkb_wrapper(self, wkb):
-        return psycopg2.Binary(wkb)
+    def geom_wrapper(self, geom):
+        return psycopg2.Binary(geom.wkb)
     
     def reconnect(self):
         if self._connection:
@@ -109,8 +116,8 @@ class PostGISDB(object):
             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)
+            (osm_id, type, geometry %(extra_arg_names)s)
+            VALUES (%%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)
@@ -136,7 +143,6 @@ class PostGISDB(object):
         cur.execute("""
             CREATE TABLE "%s" (
                 osm_id INT4 PRIMARY KEY,
-                name VARCHAR(255),
                 type VARCHAR(255)
                 %s
             );
@@ -159,14 +165,14 @@ class PostGISDB(object):
         existing_tables = []
         for row in cur:
             table_name = row[0]
-            if not table_name.startswith((new_prefix, backup_prefix)):
+            if table_name.startswith(existing_prefix) and 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)):
+            if table_name.startswith(existing_prefix) and 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 + '%', ))
@@ -265,15 +271,14 @@ class PostGISUnionView(object):
         selects = []
         for mapping in self.mapping.mappings:
             field_str = ', '.join(self._mapping_fields(mapping))
-            selects.append("""SELECT osm_id, name, type, geometry, %s,
+            selects.append("""SELECT osm_id, 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)
+        stmt = 'CREATE VIEW "%s" as (\n%s\n)' % (self.view_name, selects)
         
-        print stmt
         return stmt
 
     def _geom_table_stmt(self):
@@ -302,15 +307,20 @@ class PostGISUnionView(object):
         cur.execute('BEGIN')
         try:
             cur.execute('SAVEPOINT pre_create_view')
+            cur.execute('SELECT * FROM pg_views WHERE viewname = %s', (self.view_name, ))
+            if cur.fetchall():
+                cur.execute('DROP VIEW %s' % (self.view_name, ))
             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())
+        cur.execute('SELECT * FROM geometry_columns WHERE f_table_name = %s', (self.view_name, ))
+        if cur.fetchall():
+            # drop old entry to handle changes of SRID
+            cur.execute('DELETE FROM geometry_columns WHERE f_table_name = %s', (self.view_name, ))
+        cur.execute(self._geom_table_stmt())
 
 
 class PostGISGeneralizedTable(object):
@@ -330,9 +340,16 @@ class PostGISGeneralizedTable(object):
 
     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))
+        if fields:
+            fields += ','
+        if self.mapping.where:
+            where = ' WHERE ' + self.mapping.where
+        else:
+            where = ''
+        return """CREATE TABLE "%s" AS (SELECT osm_id, type, %s
+            ST_Simplify(geometry, %f) as geometry from "%s"%s)""" % (
+            self.table_name, fields, self.mapping.tolerance, self.db.to_tablename(self.mapping.origin.name),
+            where)
 
     def create(self):
         cur = self.db.connection.cursor()
@@ -343,11 +360,12 @@ class PostGISGeneralizedTable(object):
         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())
+        cur.execute('SELECT * FROM geometry_columns WHERE f_table_name = %s', (self.table_name, ))
+        if cur.fetchall():
+            # drop old entry to handle changes of SRID
+            cur.execute('DELETE FROM geometry_columns WHERE f_table_name = %s', (self.table_name, ))
+        cur.execute(self._geom_table_stmt())
 
diff --git a/imposm/dbimporter.py b/imposm/dbimporter.py
index eb76568..cde29dc 100644
--- a/imposm/dbimporter.py
+++ b/imposm/dbimporter.py
@@ -67,7 +67,6 @@ class ImporterProcess(Process):
             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)
@@ -98,6 +97,13 @@ class WayProcess(ImporterProcess):
 
     def doit(self):
         coords_cache = self.osm_cache.coords_cache(mode='r')
+        inserted_ways_cache = self.osm_cache.inserted_ways_cache(mode='r')
+        inserted_ways = iter(inserted_ways_cache)
+
+        try:
+            skip_id = inserted_ways.next()
+        except StopIteration:
+            skip_id = 2**64
 
         while True:
             ways = self.in_queue.get()
@@ -105,18 +111,24 @@ class WayProcess(ImporterProcess):
                 break
 
             for way in ways:
-                if way.tags.get('_inserted_'):
+                while skip_id < way.osm_id:
+                    try:
+                        skip_id = inserted_ways.next()
+                    except StopIteration:
+                        skip_id = 2**64
+                if skip_id == way.osm_id:
                     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)
 
 
@@ -144,7 +156,7 @@ class RelationProcess(ImporterProcess):
                     if str(ex):
                         log.debug(ex)
                     continue
-                mappings = self.mapper.for_ways(relation.tags)
+                mappings = self.mapper.for_relations(relation.tags)
                 if mappings:
                     inserted = self.insert(mappings, relation.osm_id, relation.geom, relation.tags)
                     if inserted:
@@ -171,7 +183,7 @@ class DBImporter(threading.Thread):
 
             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))
+            insert_data.append((osm_id, osm_elem.type, self.db.geom_wrapper(osm_elem.geom)) + tuple(extra_args))
 
             if len(insert_data) >= 128:
                 if not self.dry_run:
diff --git a/imposm/defaultmapping.py b/imposm/defaultmapping.py
index 7168606..a8ac1da 100644
--- a/imposm/defaultmapping.py
+++ b/imposm/defaultmapping.py
@@ -16,13 +16,35 @@ from imposm.mapping import (
     Options,
     Points, LineStrings, Polygons,
     String, Bool, Integer, OneOfInt,
+    set_default_name_type, LocalizedName,
     WayZOrder, ZOrder, Direction,
     GeneralizedTable, UnionView,
+    PseudoArea, meter_to_mapunit, sqr_meter_to_mapunit,
 )
 
+# # internal configuration options
+# # uncomment to make changes to the default values
+# import imposm.config
+# 
+# # import relations with missing rings
+# imposm.config.import_partial_relations = False
+# 
+# # select relation builder: union or contains
+# imposm.config.relation_builder = 'contains'
+# 
+# # log relation that take longer than x seconds
+# imposm.config.imposm_multipolygon_report = 60
+# 
+# # skip relations with more rings (0 skip nothing)
+# imposm.config.imposm_multipolygon_max_ring = 0
+
+
+# set_default_name_type(LocalizedName(['name:en', 'int_name', 'name']))
+
 db_conf = Options(
     # db='osm',
     host='localhost',
+    port=5432,
     user='osm',
     password='osm',
     sslmode='allow',
@@ -234,6 +256,7 @@ transport_areas = Polygons(
 landusages = Polygons(
     name = 'landusages',
     fields = (
+        ('area', PseudoArea()),
         ('z_order', ZOrder([
             'pedestrian',
             'footway',
@@ -348,40 +371,68 @@ amenities = Points(
 
 motorways_gen1 = GeneralizedTable(
     name = 'motorways_gen1',
-    tolerance = 50.0,
+    tolerance = meter_to_mapunit(50.0),
     origin = motorways,
 )
 
 mainroads_gen1 = GeneralizedTable(
     name = 'mainroads_gen1',
-    tolerance = 50.0,
+    tolerance = meter_to_mapunit(50.0),
     origin = mainroads,
 )
 
 railways_gen1 = GeneralizedTable(
     name = 'railways_gen1',
-    tolerance = 50.0,
+    tolerance = meter_to_mapunit(50.0),
     origin = railways,
 )
 
 motorways_gen0 = GeneralizedTable(
     name = 'motorways_gen0',
-    tolerance = 200.0,
+    tolerance = meter_to_mapunit(200.0),
     origin = motorways_gen1,
 )
 
 mainroads_gen0 = GeneralizedTable(
     name = 'mainroads_gen0',
-    tolerance = 200.0,
+    tolerance = meter_to_mapunit(200.0),
     origin = mainroads_gen1,
 )
 
 railways_gen0 = GeneralizedTable(
     name = 'railways_gen0',
-    tolerance = 200.0,
+    tolerance = meter_to_mapunit(200.0),
     origin = railways_gen1,
 )
 
+landusages_gen0 = GeneralizedTable(
+    name = 'landusages_gen0',
+    tolerance = meter_to_mapunit(200.0),
+    origin = landusages,
+    where = "ST_Area(geometry)>%f" % sqr_meter_to_mapunit(500000),
+)
+
+landusages_gen1 = GeneralizedTable(
+    name = 'landusages_gen1',
+    tolerance = meter_to_mapunit(50.0),
+    origin = landusages,
+    where = "ST_Area(geometry)>%f" % sqr_meter_to_mapunit(50000),
+)
+
+waterareas_gen0 = GeneralizedTable(
+    name = 'waterareas_gen0',
+    tolerance = meter_to_mapunit(200.0),
+    origin = waterareas,
+    where = "ST_Area(geometry)>%f" % sqr_meter_to_mapunit(500000),
+)
+
+waterareas_gen1 = GeneralizedTable(
+    name = 'waterareas_gen1',
+    tolerance = meter_to_mapunit(50.0),
+    origin = waterareas,
+    where = "ST_Area(geometry)>%f" % sqr_meter_to_mapunit(50000),
+)
+
 roads = UnionView(
     name = 'roads',
     fields = (
diff --git a/imposm/geom.py b/imposm/geom.py
index da823d6..62684fe 100644
--- a/imposm/geom.py
+++ b/imposm/geom.py
@@ -12,6 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import shapely.geos
 from shapely.geometry.base import BaseGeometry
 from shapely import geometry
 from shapely import wkt
@@ -29,7 +30,14 @@ class IncompletePolygonError(Exception):
 TOLERANCE_DEEGREES = 1e-8
 TOLERANCE_METERS = 1e-3
 
+# older versions had unhandled floating point execptions in .buffer(0)
+SHAPELY_SUPPORTS_BUFFER = shapely.geos.geos_capi_version >= (1, 6, 0)
+
 def validate_and_simplify(geom, meter_units=False):
+    if SHAPELY_SUPPORTS_BUFFER:
+        # buffer(0) is nearly fast as is_valid 
+        return geom.buffer(0)
+    
     orig_geom = geom
     if not geom.is_valid:
         tolerance = TOLERANCE_METERS if meter_units else TOLERANCE_DEEGREES
@@ -39,7 +47,6 @@ def validate_and_simplify(geom, meter_units=False):
                                        orig_geom)
     return geom
 
-
 class GeomBuilder(object):
     def build(self, osm_elem):
         # TODO is this method still in use?
diff --git a/imposm/mapping.py b/imposm/mapping.py
index 6a7de02..f85cc03 100644
--- a/imposm/mapping.py
+++ b/imposm/mapping.py
@@ -13,6 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from __future__ import division
+import math
 import imposm.geom
 
 ANY = '__any__'
@@ -26,6 +28,7 @@ __all__ = [
     'ZOrder',
     'PointTable',
     'String',
+    'LocalizedName',
     'LineStringTable',
     'Direction',
     'OneOfInt',
@@ -34,8 +37,46 @@ __all__ = [
     'Bool',
     'GeneralizedTable',
     'UnionView',
+    'set_default_name_field',
 ]
 
+default_name_field = None
+
+def set_default_name_type(type, column_name='name'):
+    """
+    Set new default type for 'name' field.
+    
+    ::
+        
+        set_default_name_type(LocalizedName(['name:en', 'int_name', 'name']))
+    
+    """
+    global default_name_field
+    default_name_field = column_name, type
+
+# changed by imposm.app if the projection is epsg:4326
+import_srs_is_geographic = False
+
+def meter_to_mapunit(meter):
+    """
+    Convert ``meter`` into the mapunit of the import.
+    Only supports EPSG:4326 (degrees) at the moment, all other
+    SRS will use meter as mapunit.
+    """
+    if import_srs_is_geographic:
+        deg_to_meter = (40000 * 1000) / 360
+        return meter / deg_to_meter
+    return meter
+
+def sqr_meter_to_mapunit(sqr_meter):
+    """
+    Convert ``sqr_meter`` into the mapunit of the import.
+    Only supports EPSG:4326 (degrees) at the moment, all other
+    SRS will use meter as mapunit.
+    """
+    if import_srs_is_geographic:
+        return meter_to_mapunit(math.sqrt(sqr_meter))**2
+    return sqr_meter
 
 class Mapping(object):
     table = None
@@ -44,21 +85,23 @@ class Mapping(object):
     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
+        self.fields = fields or tuple(self.fields)
+        self._add_name_field()
         if field_filter:
             self.field_filter = field_filter
+
+    def _add_name_field(self):
+        """
+        Add name field to default if not set.
+        """
+        if not any(1 for name, _type in self.fields if name == 'name'):
+            if default_name_field:
+                self.fields = (default_name_field,) + self.fields
+            else:
+                self.fields = (('name', Name()),) + self.fields
         
     @property
     def insert_stmt(self):
@@ -66,12 +109,18 @@ class Mapping(object):
             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]
+        extra_field_names = []
+        for field_name, field_filter in self.field_filter:
+            extra_field_names.append(field_name)
+        
+        for field_name, field in self.fields:
+            field_names = field.extra_fields()
+            if field_names is not None:
+                extra_field_names.extend(field_names)
+            else:
+                extra_field_names.append(field_name)
+        return extra_field_names
     
     def build_geom(self, osm_elem):
         try:
@@ -96,85 +145,122 @@ class TagMapper(object):
         self._init_map()
 
     def _init_map(self):
-        self.points = {}
-        self.lines = {}
-        self.polygons = {}
-        self.nodes_tags = set()
-        self.ways_tags = set()
+        self.point_mappings = {}
+        self.line_mappings = {}
+        self.polygon_mappings = {}
+        self.point_tags = {}
+        self.line_tags = {}
+        self.polygon_tags = {}
 
         for mapping in self.mappings:
             if mapping.table is PointTable:
-                tags = self.nodes_tags
-                add_to = self.points
+                tags = self.point_tags
+                add_to = self.point_mappings
             elif mapping.table is LineStringTable:
-                tags = self.ways_tags
-                add_to = self.lines
+                tags = self.line_tags
+                add_to = self.line_mappings
             elif mapping.table is PolygonTable:
-                tags = self.ways_tags
-                add_to = self.polygons
-
-            tags.update(mapping.extra_field_names())
+                tags = self.polygon_tags
+                add_to = self.polygon_mappings
+            
+            for extra in mapping.extra_field_names():
+                tags.setdefault(extra, set()).add('__any__')
 
             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)
+                    tags.setdefault(tag, set()).add(type)
+                    add_to[tag].setdefault(type, []).append(mapping)
 
     def for_nodes(self, tags):
-        return self._mapping_for_tags(self.points, tags)
+        return self._mapping_for_tags(self.point_mappings, tags)
 
     def for_ways(self, tags):
-        return (self._mapping_for_tags(self.lines, tags) + 
-                self._mapping_for_tags(self.polygons, tags))
+        return (self._mapping_for_tags(self.line_mappings, tags) + 
+                self._mapping_for_tags(self.polygon_mappings, tags))
+
+    def for_relations(self, tags):
+        return self._mapping_for_tags(self.polygon_mappings, 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]
+                else:
+                    if '__any__' in filter_tags[k]:
+                        pass
+                    elif tags[k] in filter_tags[k]:
+                        pass
+                    else:
+                        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)
+        tags = dict(self.point_tags)
+        return self._tag_filter(tags)
 
     def tag_filter_for_ways(self):
-        return self._tag_filter(self.ways_tags)
+        tags = dict()
+        for k, v in self.line_tags.iteritems():
+            tags.setdefault(k, set()).update(v)
+        
+        for k, v in self.polygon_tags.iteritems():
+            tags.setdefault(k, set()).update(v)
+        return self._tag_filter(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)
+        tags = dict()
+        for k, v in self.line_tags.iteritems():
+            tags.setdefault(k, set()).update(v)
+        for k, v in self.polygon_tags.iteritems():
+            tags.setdefault(k, set()).update(v)
+        tags['type'] = set(['multipolygon', 'boundary'])  # for type=multipolygon
+        expected_tags = set(['type', 'name'])
+        _rel_filter = self._tag_filter(tags)
         def rel_filter(tags):
-            if tags.get('type') != 'multipolygon':
+            if tags.get('type') == 'multipolygon':
+                pass
+            elif tags.get('type') == 'boundary' and 'boundary' in tags:
+                # a lot of the boundary relations are not multipolygon
+                pass
+            else:
                 tags.clear()
                 return
+            tag_count = len(tags)
             _rel_filter(tags)
+            if len(tags) < tag_count:
+                # we removed tags...
+                if not set(tags).difference(expected_tags):
+                    # but no tags except name and type are left
+                    # remove all, otherwise tags from longest
+                    # way/ring would be used during MP building
+                    tags.clear()
         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:
+
+        for tag_name in tags:
+            if tag_name in tag_map:
                 tag_value = tags[tag_name]
+                mappings = []
                 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)
-
+                    mappings.extend(tag_map[tag_name][tag_value])
+                elif ANY in tag_map[tag_name]:
+                    mappings.extend(tag_map[tag_name][ANY])
+
+                new_mappings = []
+                for proc in mappings:
+                    if proc not in mapping_set:
+                        mapping_set.add(proc)
+                        new_mappings.append(proc)
+                if new_mappings:
+                    result.append(((tag_name, tag_value), tuple(new_mappings)))
+        
         return result
 
 
@@ -218,24 +304,46 @@ class Polygons(Mapping):
 
 
 class GeneralizedTable(object):
-    def __init__(self, name, tolerance, origin):
+    def __init__(self, name, tolerance, origin, where=None):
         self.name = name
         self.tolerance = tolerance
         self.origin = origin
         self.classname = origin.name
         self.fields = self.origin.fields
+        self.where = where
 
 class UnionView(object):
     def __init__(self, name, mappings, fields):
         self.name = name
         self.mappings = mappings
         self.fields = fields
+        self._add_name_field()
+        
+    def _add_name_field(self):
+        """
+        Add name field to default if not set.
+        """
+        if not any(1 for name, _type in self.fields if name == 'name'):
+            if default_name_field:
+                self.fields = ((default_name_field[0], ''),) + self.fields
+            else:
+                self.fields = (('name', ''),) + self.fields
 
 class DropElem(Exception):
     pass
 
 
 class FieldType(object):
+    def extra_fields(self):
+        """
+        List with names of fields (keys) that should be processed
+        during read-phase.
+        
+        Return ``None`` to use the field name from the mapping.
+        Return ``[]`` if no extra fields (keys) are required.
+        """
+        return None
+    
     def value(self, val, osm_elem):
         return val
 
@@ -247,6 +355,60 @@ class String(FieldType):
     """
     column_type = "VARCHAR(255)"
 
+class Name(String):
+    """
+    Field for name values.
+    
+    Filters out common FixMe values.
+    
+    :PostgreSQL datatype: VARCHAR(255)
+
+    .. versionadded:: 2.3.0
+    """
+    
+    filter_out_names = set((
+        'fixme', 'fix me', 'fix-me!',
+        '0', 'none', 'n/a', 's/n',
+        'kein name', 'kein',
+        'unbenannt', 'unbekannt',
+        'noch unbekannt', 'noch ohne namen',
+        'noname', 'unnamed', 'namenlos', 'no_name', 'no name',
+        'editme', '_edit_me_',
+    ))
+
+    def value(self, val, osm_elem):
+        if val and val.lower() in self.filter_out_names:
+            osm_elem.name = ''
+            val = ''
+        return val
+
+class LocalizedName(Name):
+    """
+    Field for localized name values.
+    Checks different name keys and uses the first key with
+    a valid value.
+    
+    :param coalesce: list of name keys to check
+    :PostgreSQL datatype: VARCHAR(255)
+    
+    .. versionadded:: 2.3.0
+    """
+    def __init__(self, coalesce=['name', 'int_name']):
+        self.coalesce_keys = coalesce
+    
+    def extra_fields(self):
+        return self.coalesce_keys
+    
+    def value(self, val, osm_elem):
+        for key in self.coalesce_keys:
+            val = osm_elem.tags.get(key)
+            if val and val.lower() not in self.filter_out_names:
+                osm_elem.name = val
+                return val
+        else:
+            osm_elem.name = ''
+            return ''
+
 class Bool(FieldType):
     """
     Field for boolean values.
@@ -295,6 +457,42 @@ class Direction(FieldType):
                 return -1
         return 0
 
+class PseudoArea(FieldType):
+    """
+    Field for the (pseudo) area of a polygon in square meters.
+    
+    The value is just an approximation since the geometries are in
+    EPSG:4326 and not in a equal-area projection. The approximation
+    is good for smaller polygons (<1%) and should be precise enough
+    to compare geometries for rendering order (larger below smaller).
+    
+    The area of the geometry is multiplied by the cosine of
+    the mid-latitude to compensate the reduced size towards
+    the poles.
+    
+    :PostgreSQL datatype: REAL
+    
+    .. versionadded:: 2.3.0
+    """
+    
+    column_type = "REAL"
+    
+    def value(self, val, osm_elem):
+        area = osm_elem.geom.area
+        if not area:
+            return None
+        
+        extent = osm_elem.geom.bounds
+        mid_lat = extent[1] + (abs(extent[3] - extent[1]) / 2)
+        sqr_deg = area * math.cos(math.radians(mid_lat))
+        
+        # convert deg^2 to m^2
+        sqr_m = (math.sqrt(sqr_deg) * (40075160 / 360))**2
+        return sqr_m
+    
+    def extra_fields(self):
+        return []
+
 class OneOfInt(FieldType):
     """
     Field type for integer values.
@@ -344,6 +542,9 @@ class ZOrder(FieldType):
         for i, t in enumerate(types[::-1]):
             self.rank[t] = i
 
+    def extra_fields(self):
+        return []
+
     def value(self, val, osm_elem):
         return self.rank.get(osm_elem.type, 0)
 
@@ -380,6 +581,9 @@ class WayZOrder(FieldType):
     }
 
     brunnel_bool = Bool()
+    
+    def extra_fields(self):
+        return []
 
     def value(self, val, osm_elem):
         tags = osm_elem.tags
diff --git a/imposm/multipolygon.py b/imposm/multipolygon.py
index e26294a..00f1c9d 100644
--- a/imposm/multipolygon.py
+++ b/imposm/multipolygon.py
@@ -26,19 +26,25 @@ from imposm.merge import merge
 
 import imposm.base
 import imposm.geom
+import imposm.config
 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))
+def RelationBuilder(*args, **kw):
+    if imposm.config.relation_builder == 'contains':
+        return ContainsRelationBuilder(*args, **kw)
+    if imposm.config.relation_builder == 'union':
+        return UnionRelationBuilder(*args, **kw)
+    raise ValueError('unknown relation_builder "%s"'
+        % (imposm.config.relation_builder, ))
 
-class RelationBuilder(object):
+class RelationBuilderBase(object):
+    validate_rings = True
     def __init__(self, relation, ways_cache, coords_cache):
         self.relation = relation
         self.polygon_builder = PolygonBuilder()
@@ -54,14 +60,21 @@ class RelationBuilder(object):
             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 imposm.config.import_partial_relations:
+                    continue
+                else:
+                    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)
+            if way.coords is None:
+                if not imposm.config.import_partial_relations:
+                    raise IncompletePolygonError()
+            else:
+                ways.append(way)
         return ways
     
     def build_rings(self, ways):
@@ -70,24 +83,30 @@ class RelationBuilder(object):
         
         for ring in (Ring(w) for w in ways):
             if ring.is_closed():
-                ring.geom = self.polygon_builder.build_checked_geom(ring, validate=True)
+                ring.geom = self.polygon_builder.build_checked_geom(ring, validate=self.validate_rings)
                 rings.append(ring)
             else:
                 incomplete_rings.append(ring)
         
         merged_rings = self.build_ring_from_incomplete(incomplete_rings)
+        if len(rings) + len(merged_rings) == 0:
+            raise IncompletePolygonError('linestrings from relation %s have no rings' % (self.relation.osm_id, ))
         
         return rings + merged_rings
         
     def build_ring_from_incomplete(self, incomplete_rings):
         
         rings = merge_rings(incomplete_rings)
-        for ring in rings:
+
+        for ring in rings[:]:
             if not ring.is_closed():
-                raise InvalidGeometryError('linestrings from relation %s do not form a ring' %
+                if imposm.config.import_partial_relations:
+                    rings.remove(ring)
+                    continue
+                else:
+                    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)
+            ring.geom = self.polygon_builder.build_checked_geom(ring, validate=self.validate_rings)
         return rings
     
     def fetch_way_coords(self, way):
@@ -98,48 +117,15 @@ class RelationBuilder(object):
         if coords is None:
             log.debug('missing coord from way %s in relation %s',
                 way.osm_id, self.relation.osm_id)
-            raise IncompletePolygonError()
-        
+            return None
         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)
+        raise NotImplementedError()
         
-        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:
@@ -157,15 +143,16 @@ class RelationBuilder(object):
             rings = self.build_rings(ways)
             time_rings = time.time() - time_start
 
-            if len(rings) > IMPOSM_MULTIPOLYGON_MAX_RING:
+            if (imposm.config.imposm_multipolygon_max_ring
+                and len(rings) > imposm.config.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)
-            
+                raise IncompletePolygonError('skipping too large multipolygon')
             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:
+            if time_ways + time_rings + time_relations > imposm.config.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:
@@ -178,6 +165,124 @@ class RelationBuilder(object):
             log.exception(ex)
             raise IncompletePolygonError(ex)
 
+
+class UnionRelationBuilder(RelationBuilderBase):
+    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[0]
+        rel_tags = relation_tags(self.relation.tags, polygon.tags)
+        polygon.mark_as_inserted(rel_tags)
+        
+        geom = polygon.geom
+        for r in rings[1:]:
+            if geom.contains(r.geom):
+                # inside -> hole -> subtract
+                geom = geom.difference(r.geom)
+                r.mark_as_inserted(rel_tags)
+            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.mark_as_inserted(rel_tags)
+        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
+
+class ContainsRelationBuilder(RelationBuilderBase):
+    validate_rings = False
+    
+    def _ring_is_hole(self, rings, idx):
+        """
+        Returns True if rings[idx] is a hole, False if it is a
+        shell (also if hole in a hole, etc)
+        """
+        contained_counter = 0
+        while True:
+            idx = rings[idx].contained_by
+            if idx is None:
+                break
+            contained_counter += 1
+        
+        return contained_counter % 2 == 1
+    
+    def build_relation_geometry(self, rings):
+        """
+        Build relation geometry from rings.
+        """
+        rings.sort(key=lambda x: x.geom.area, reverse=True)
+        total_rings = len(rings)
+
+        shells = set([rings[0]])
+
+        for i in xrange(total_rings):
+            test_geom = shapely.prepared.prep(rings[i].geom)
+            for j in xrange(i+1, total_rings):
+                if test_geom.contains(rings[j].geom):
+                    # j in inside of i
+                    if rings[j].contained_by is not None:
+                        # j is inside a larger ring, remove that relationship
+                        # e.g. j is hole inside a hole (i)
+                        rings[rings[j].contained_by].holes.discard(rings[j])
+                        shells.discard(rings[j])
+                    
+                    # remember parent
+                    rings[j].contained_by = i
+                    
+                    # add ring as hole or shell
+                    if self._ring_is_hole(rings, j):
+                        rings[i].holes.add(rings[j])
+                    else:
+                        shells.add(rings[j])
+            if rings[i].contained_by is None:
+                # add as shell if it is not a hole
+                shells.add(rings[i])
+        
+        rel_tags = relation_tags(self.relation.tags, rings[0].tags)
+
+        # build polygons from rings
+        polygons = []
+        for shell in shells:
+            shell.mark_as_inserted(rel_tags)
+            exterior = shell.geom.exterior
+            interiors = []
+            for hole in shell.holes:
+                hole.mark_as_inserted(rel_tags)
+                interiors.append(hole.geom.exterior)
+            
+            polygons.append(shapely.geometry.Polygon(exterior, interiors))
+            
+        if len(polygons) == 1:
+            geom = polygons[0]
+        else:
+            geom = shapely.geometry.MultiPolygon(polygons)
+        
+        geom = imposm.geom.validate_and_simplify(geom)
+        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 = []
+        for r in rings:
+            all_ways.extend(r.ways)
+        self.relation.ways = all_ways
+    
+
 def relation_tags(rel_tags, way_tags):
     result = dict(rel_tags)
     
@@ -216,7 +321,6 @@ def merge_rings(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]:
@@ -269,7 +373,9 @@ class Ring(object):
         self.refs = way.refs
         self.coords = way.coords
         self.tags = dict(way.tags)
-        self._inserted = way
+        self.inserted = way.inserted
+        self.contained_by = None
+        self.holes = set()
     
     def __repr__(self):
         return 'Ring(%r, %r, %r)' % (self.osm_id, self.tags, self.ways)
@@ -294,13 +400,9 @@ class Ring(object):
     def is_closed(self):
         return len(self.refs) >= 4 and self.refs[0] == self.refs[-1]
     
-    def _set_inserted(self, value):
+    def mark_as_inserted(self, tags):
         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)
+            if tags_same_or_empty(tags, w.tags):
+                w.inserted = True
+        if tags_same_or_empty(tags, self.tags):
+            self.inserted = True
diff --git a/imposm/psqldb.py b/imposm/psqldb.py
index 5c7359c..e78bc02 100644
--- a/imposm/psqldb.py
+++ b/imposm/psqldb.py
@@ -45,7 +45,7 @@ def find_sql_files(version, mapping):
             postgis_sql = p
         p = '/usr/share/postgresql-8.3-postgis/spatial_ref_sys.sql'
         if exists(p):
-            spatial_ref_sys = p
+            spatial_ref_sys_sql = p
         p = '/etc/postgresql/8.3/main/pg_hba.conf'
         if exists(p):
             pg_hba = p
diff --git a/imposm/test/test_cache.py b/imposm/test/test_cache.py
index 02a3e6e..02174d3 100644
--- a/imposm/test/test_cache.py
+++ b/imposm/test/test_cache.py
@@ -12,8 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import os
 import tempfile
-from imposm.cache.tc import NodeDB, CoordDB
+from imposm.cache.tc import NodeDB, DeltaCoordsDB
 
 from nose.tools import eq_, assert_almost_equal
 
@@ -23,16 +24,25 @@ class TestNodeDB(object):
         fd_, self.fname = tempfile.mkstemp('.db')
         self.db = NodeDB(self.fname)
     
+    def teardown(self):
+        os.unlink(self.fname)
+    
     def test_insert(self):
         assert self.db.put(1000, {'foo': 2}, (123, 456))
+        assert self.db.put(2**40, {'bar': 2}, (123, 456))
         
         nd = self.db.get(1000)
         eq_(nd.osm_id, 1000)
         eq_(nd.tags, {'foo': 2})
         eq_(nd.coord, (123, 456))
+
+        nd = self.db.get(2**40)
+        eq_(nd.osm_id, 2**40)
+
     
     def test_read_only(self):
         assert self.db.put(1000, {'foo': 2}, (123, 456))
+        assert self.db.put(2**40, {'bar': 2}, (123, 456))
         self.db.close()
         self.db = NodeDB(self.fname, 'r')
         
@@ -40,6 +50,9 @@ class TestNodeDB(object):
         eq_(nd.osm_id, 1000)
         eq_(nd.tags, {'foo': 2})
         eq_(nd.coord, (123, 456))
+
+        nd = self.db.get(2**40)
+        eq_(nd.osm_id, 2**40)
         
         assert not self.db.put(1001, {'foo': 2}, (123, 456))
         assert not self.db.get(1001)
@@ -58,36 +71,44 @@ class TestNodeDB(object):
 class TestCoordDB(object):
     def setup(self):
         fd_, self.fname = tempfile.mkstemp('.db')
-        self.db = CoordDB(self.fname)
+        self.db = DeltaCoordsDB(self.fname)
     
     def test_insert(self):
         assert self.db.put(1000, 123, 179.123456789)
+        assert self.db.put(2**40, 123, 179.123456789)
+        assert self.db.put(2**40+1, 123, 179.123456789)
         
         pos = self.db.get(1000)
         assert_almost_equal(pos[0], 123.0, 7)
         assert_almost_equal(pos[1], 179.123456789, 7)
+
+        assert self.db.get(2**40)
+        assert self.db.get(2**40+1)
     
     def test_read_only(self):
-        assert self.db.put(1000, 123, 456)
+        assert self.db.put(1000, 123, 0)
+        assert self.db.put(1001, -180.0, -90)
+        assert self.db.put(1010, 180, 90)
+        assert self.db.put(2**40, 123, 179.123456789)
+        assert self.db.put(2**40+1, 123, 179.123456789)
+        
         self.db.close()
-        self.db = CoordDB(self.fname, 'r')
+        self.db = DeltaCoordsDB(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)
+        assert_almost_equal(pos[0], 123.0, 6)
+        assert_almost_equal(pos[1], 0.0, 6)
 
-    def test_iter(self):
-        assert self.db.put(1000, 123, 456)
+        pos = self.db.get(1001)
+        assert_almost_equal(pos[0], -180.0, 6)
+        assert_almost_equal(pos[1], -90.0, 6)
         
-        coords = list(self.db)
-        eq_(len(coords), 1)
+        pos = self.db.get(1010)
+        assert_almost_equal(pos[0], 180.0, 6)
+        assert_almost_equal(pos[1], 90.0, 6)
         
-        osm_id, pos = coords[0]
+        assert self.db.get(2**40)
+        assert self.db.get(2**40+1)
         
-        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
+        assert not self.db.put(2001, 123, 456)
+        assert not self.db.get(2001)
diff --git a/imposm/test/test_field_types.py b/imposm/test/test_field_types.py
new file mode 100644
index 0000000..cbbab32
--- /dev/null
+++ b/imposm/test/test_field_types.py
@@ -0,0 +1,49 @@
+# 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 imposm
+
+from imposm.base import OSMElem
+from imposm.mapping import Name, LocalizedName
+
+
+def test_name_field():
+    name = Name()
+    elem = OSMElem(1, [], 'test', tags={'name': 'fixme'})
+    assert name.value('fixme', elem) == ''
+    assert elem.name == ''
+    
+    elem = OSMElem(1, [], 'test', tags={'name': 'Foo Street'})
+    assert name.value('Foo Street', elem) == 'Foo Street'
+    assert elem.name == 'Foo Street'
+
+def test_localized_name_field():
+    name = LocalizedName(['name:de', 'name:en', 'foo'])
+    elem = OSMElem(1, [], 'test', tags={'name': 'Foo'})
+    assert name.value(None, elem) == ''
+    assert elem.name == ''
+
+    elem = OSMElem(1, [], 'test', tags={'name:de': 'Foo', 'name:en': 'Bar'})
+    assert name.value(None, elem) == 'Foo'
+    assert elem.name == 'Foo'
+
+    elem = OSMElem(1, [], 'test', tags={'name:es': 'Foo', 'name:en': 'Bar'})
+    assert name.value(None, elem) == 'Bar'
+    assert elem.name == 'Bar'
+
+    elem = OSMElem(1, [], 'test', tags={'name:es': 'Foo', 'foo': 'Bar'})
+    assert name.value(None, elem) == 'Bar'
+    assert elem.name == 'Bar'
+    
diff --git a/imposm/test/test_imported.py b/imposm/test/test_imported.py
new file mode 100644
index 0000000..41c9948
--- /dev/null
+++ b/imposm/test/test_imported.py
@@ -0,0 +1,108 @@
+# 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 re
+import os
+import tempfile
+import shutil
+
+from contextlib import contextmanager
+
+import imposm.app
+import imposm.db.config
+import imposm.mapping
+
+from nose.tools import eq_
+from nose.plugins import skip
+
+temp_dir = None
+old_cwd = None
+
+try:
+    from imposm_test_conf import db_conf
+    db_conf = imposm.mapping.Options(db_conf)
+except ImportError:
+    raise skip.SkipTest('no imposm_test_conf.py with db_conf found')
+
+def setup_module():
+    global old_cwd, temp_dir
+    old_cwd = os.getcwd()
+    temp_dir = tempfile.mkdtemp()
+    os.chdir(temp_dir)
+    test_osm_file = os.path.join(os.path.dirname(__file__), 'test.out.osm')
+    with capture_out():
+        imposm.app.main(['--read', test_osm_file, '--write', '-d', db_conf.db, '--host', db_conf.host,
+            '--proj', db_conf.proj])
+
+class TestImported(object):
+    def __init__(self):
+        self.db = imposm.db.config.DB(db_conf)
+    
+    def test_point(self):
+        cur = self.db.cur
+        cur.execute('select osm_id, name, ST_AsText(geometry) from osm_new_places where osm_id = 1')
+        results = cur.fetchall()
+        eq_(len(results), 1)
+        eq_(results[0], (1, 'Foo', 'POINT(13 47.5)'))
+
+    def test_way(self):
+        cur = self.db.cur
+        cur.execute('select osm_id, name, ST_AsText(geometry) from osm_new_landusages where osm_id = 1001')
+        results = cur.fetchall()
+        eq_(len(results), 1)
+        eq_(results[0][:-1], (1001, 'way 1001',))
+        eq_(roundwkt(results[0][-1]), 'POLYGON((13.0 47.5,14.5 50.0,16.5 49.0,17.0 47.0,14.5 45.5,13.0 47.5),(14.0 47.5,15.0 47.0,15.5 48.0,14.5 48.5,14.0 47.5))')
+
+        cur.execute('select osm_id, name, ST_AsText(geometry) from osm_new_landusages where osm_id = 2001')
+        results = cur.fetchall()
+        eq_(len(results), 1)
+        eq_(results[0][:-1], (2001, 'way 2001',))
+        eq_(roundwkt(results[0][-1]), 'POLYGON((23.0 47.5,24.5 50.0,26.5 49.0,27.0 47.0,24.5 45.5,23.0 47.5),(24.5 47.0,25.5 46.5,26.0 47.5,25.0 47.5,24.5 47.0),(24.2 48.25,25.25 47.7,25.7 48.8,24.7 49.25,24.2 48.25))')
+
+
+        cur.execute('select osm_id, name, ST_AsText(geometry) from osm_new_landusages where osm_id = 3001')
+        results = cur.fetchall()
+        eq_(len(results), 1)
+        eq_(results[0][:-1], (3001, 'way 3002',))
+        eq_(roundwkt(results[0][-1]), 'POLYGON((33.0 47.5,34.5 50.0,36.5 49.0,37.0 47.0,34.5 45.5,33.0 47.5),(34.0 47.5,35.0 47.0,35.5 48.0,34.5 48.5,34.0 47.5))')
+
+
+def roundwkt(wkt):
+    def round_num(num_str):
+        return str(round(float(num_str.group(0)), 2))
+    return re.sub('\d+(\.\d+)?', round_num, wkt)
+
+def teardown_module():
+    if old_cwd:
+        os.chdir(old_cwd)
+    
+    if temp_dir and os.path.exists(temp_dir):
+        shutil.rmtree(temp_dir)
+    
+
+ at contextmanager
+def capture_out():
+    import sys
+    from cStringIO import StringIO
+
+    old_stdout = sys.stdout
+    old_stderr = sys.stderr
+    try:
+        sys.stdout = StringIO()
+        sys.stderr = StringIO()
+        yield sys.stdout, sys.stderr
+    finally:
+        sys.stdout = old_stdout
+        sys.stderr = old_stderr
+    
\ No newline at end of file
diff --git a/imposm/test/test_multipolygon.py b/imposm/test/test_multipolygon.py
index 3463ffc..a8ccff8 100644
--- a/imposm/test/test_multipolygon.py
+++ b/imposm/test/test_multipolygon.py
@@ -13,42 +13,282 @@
 # limitations under the License.
 
 from imposm.base import Relation, Way
-from imposm.multipolygon import RelationBuilder, Ring, merge_rings
+from imposm.multipolygon import UnionRelationBuilder, ContainsRelationBuilder, Ring, merge_rings
 
-from nose.tools import eq_
+from nose.tools import eq_, assert_almost_equal
 
-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)]
+class RelationBuilderTestBase(object):
+
+    def test_broken_polygon_self_intersect(self):
+        #  2##3    6##7
+        #  #  #    ####
+        #  1##4____5##8
+        w1 = Way(1, {}, [1, 2, 3, 4, 5, 6, 7, 8, 1])
+        w1.coords = [(0, 0), (0, 10), (10, 10), (10, 0), (20, 0), (20, 10), (30, 10), (30, 0), (0, 0)]
+        w2 = Way(2, {}, [15, 16, 17, 18, 15])
+        w2.coords = [(2, 2), (8, 2), (8, 8), (2, 8), (2, 2)]
+        yield self.check_broken_polygon, w1, w2
+
+        #  2##3    6##7
+        #  #  #    ####
+        #  1##4____5##8
+        w1 = Way(1, {}, [4, 1, 2, 3, 4, 5, 6, 7, 8, 4])
+        w1.coords = [(10, 0), (0, 0), (0, 10), (10, 10), (10, 0), (20, 0), (20, 10), (30, 10), (30, 0), (10, 0)]
+        yield self.check_broken_polygon, w1, w2
+        
+    def check_broken_polygon(self, w1, w2):
+        r = Relation(1, {}, [(1, 'way', 'outer'), (2, 'way', 'inner')])
+        builder = self.relation_builder(r, None, None)
+        rings = builder.build_rings([w1, w2])
+        eq_(len(rings), 2)
+        eq_(rings[0].geom.area, 200)
+        eq_(rings[1].geom.area, 36)
     
-    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)
     
-    builder.build_relation_geometry(rings)
+        eq_(r.geom.area, 200-36)
+
+    def test_broken_polygon_self_intersect_triangle(self):
+        #  2###
+        #  #    ###4
+        #  #    ###3
+        #  1###
+        # triangle with four points, minor overlapping
+        
+        w1 = Way(1, {}, [1, 2, 3, 4, 1])
+        w1.coords = [(0, 0), (0, 100), (100, 50 - 0.00001), (100, 50 + 0.00001), (0, 0)]
+        w2 = Way(2, {}, [15, 16, 17, 18, 15])
+        w2.coords = [(10, 45), (10, 55), (20, 55), (20, 45), (10, 45)]
+
+        r = Relation(1, {}, [(1, 'way', 'outer'), (2, 'way', 'inner')])
+        builder = self.relation_builder(r, None, None)
+        rings = builder.build_rings([w1, w2])
+        eq_(len(rings), 2)
+        assert_almost_equal(rings[0].geom.area, 100 * 100 / 2, 2)
+        eq_(rings[1].geom.area, 100)
     
-    eq_(r.geom.area, 100-36)
+        builder.build_relation_geometry(rings)
+        assert_almost_equal(r.geom.area, 100 * 100 / 2 - 100, 2)
 
-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)]
+        # larger overlapp
+        w1 = Way(1, {}, [1, 2, 3, 4, 1])
+        w1.coords = [(0, 0), (0, 100), (100, 50 - 1), (100, 50 + 1), (0, 0)]
+        w2 = Way(2, {}, [15, 16, 17, 18, 15])
+        w2.coords = [(10, 45), (10, 55), (20, 55), (20, 45), (10, 45)]
+
+        r = Relation(1, {}, [(1, 'way', 'outer'), (2, 'way', 'inner')])
+        builder = self.relation_builder(r, None, None)
+        rings = builder.build_rings([w1, w2])
+        eq_(len(rings), 2)
+        assert_almost_equal(rings[0].geom.area, 100 * 100 / 2, -3)
+        eq_(rings[1].geom.area, 100)
     
-    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)
+        assert_almost_equal(r.geom.area, 100 * 100 / 2 - 100, -3)
+
+        # #  2###    ###4
+        # #  #    ###   #
+        # #  #    ###   #
+        # #  1###    ###3
+        # # hourglass
+        # w1 = Way(1, {}, [1, 2, 3, 4, 1])
+        # w1.coords = [(0, 0), (0, 100), (100, 0), (100, 100), (0, 0)]
+        # w2 = Way(2, {}, [15, 16, 17, 18, 15])
+        # w2.coords = [(10, 45), (10, 55), (20, 55), (20, 45), (10, 45)]
+        # w3 = Way(3, {}, [25, 26, 27, 28, 25])
+        # w3.coords = [(80, 45), (80, 55), (90, 55), (90, 45), (80, 45)]
+        # 
+        # r = Relation(1, {}, [(1, 'way', 'outer'), (2, 'way', 'inner')])
+        # builder = self.relation_builder(r, None, None)
+        # rings = builder.build_rings([w1, w2, w3])
+        # eq_(len(rings), 3)
+        # print rings[0].geom.wkt, rings[0].geom.simplify(0.000001, False).wkt
+        # eq_(rings[0].geom.area, 100 * 100 / 2)
+        # eq_(rings[1].geom.area, 100)
+        # eq_(rings[2].geom.area, 100)
+        #     
+        # builder.build_relation_geometry(rings)
+        # assert_almost_equal(r.geom.area, 100 * 100 / 2 - 100, -3)
+
+    def test_simple_polygon_w_hole(self):
+        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)]
     
-    builder.build_relation_geometry(rings)
+        r = Relation(1, {}, [(1, 'way', 'outer'), (2, 'way', 'inner')])
+        builder = self.relation_builder(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)
     
-    eq_(r.geom.area, 100)
+        builder.build_relation_geometry(rings)
+    
+        eq_(r.geom.area, 100-36)
+
+    def test_polygon_w_multiple_holes(self):
+        w1 = Way(1, {'landusage': 'forest'}, [1, 2, 3, 4, 1])
+        w1.coords = [(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)]
+        w2 = Way(2, {'water': 'basin'}, [1, 2, 3, 4, 1])
+        w2.coords = [(1, 1), (2, 1), (2, 2), (1, 2), (1, 1)]
+        w3 = Way(3, {'landusage': 'scrub'}, [1, 2, 3, 4, 1])
+        w3.coords = [(3, 3), (4, 3), (4, 4), (3, 4), (3, 3)]
+    
+        r = Relation(1, {'landusage': 'forest'}, [
+            (1, 'way', 'outer'), (2, 'way', 'inner'), (3, 'way', 'inner')])
+        builder = self.relation_builder(r, None, None)
+        rings = builder.build_rings([w1, w2, w3])
+        eq_(len(rings), 3)
+        eq_(rings[0].geom.area, 100)
+        eq_(rings[1].geom.area, 1)
+        eq_(rings[2].geom.area, 1)
+    
+        builder.build_relation_geometry(rings)
+    
+        eq_(rings[0].inserted, True)
+        eq_(rings[1].inserted, False)
+        eq_(rings[2].inserted, False)
+    
+        eq_(r.geom.area, 100-1-1)
+
+
+    def test_polygon_w_nested_holes(self):
+        w1 = Way(1, {'landusage': 'forest'}, [1, 2, 3, 4, 1])
+        w1.coords = [(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)]
+        w2 = Way(2, {'landusage': 'scrub'}, [1, 2, 3, 4, 1])
+        w2.coords = [(1, 1), (9, 1), (9, 9), (1, 9), (1, 1)]
+        w3 = Way(3, {}, [5, 6, 7, 8, 5]) # with no tags
+        w3.coords = [(2, 2), (8, 2), (8, 8), (2, 8), (2, 2)]
+        w4 = Way(4, {'landusage': 'scrub'}, [9, 10, 11, 12, 9])
+        w4.coords = [(3, 3), (7, 3), (7, 7), (3, 7), (3, 3)]
+        w5 = Way(5, {'landusage': 'forest'}, [9, 10, 11, 12, 9])
+        w5.coords = [(4, 4), (6, 4), (6, 6), (4, 6), (4, 4)]
+    
+        r = Relation(1, {'landusage': 'forest'}, [
+            (1, 'way', 'outer'), (2, 'way', 'inner'), (3, 'way', 'inner'),
+            (4, 'way', 'inner'), (5, 'way', 'inner')])
+        builder = self.relation_builder(r, None, None)
+        rings = builder.build_rings([w1, w2, w3, w4, w5])
+        eq_(len(rings), 5)
+        eq_(rings[0].geom.area, 100)
+        eq_(rings[1].geom.area, 64)
+        eq_(rings[2].geom.area, 36)
+        eq_(rings[3].geom.area, 16)
+        eq_(rings[4].geom.area, 4)
+    
+        builder.build_relation_geometry(rings)
+
+        eq_(rings[0].inserted, True)
+        eq_(rings[1].inserted, False)
+        eq_(rings[2].inserted, True)
+        eq_(rings[3].inserted, False)
+        eq_(rings[4].inserted, True)
+    
+        eq_(r.geom.area, 100-64+36-16+4)
+
+    def test_polygon_w_touching_holes(self):
+        w1 = Way(1, {'landusage': 'forest'}, [1, 2, 3, 4, 1])
+        w1.coords = [(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)]
+        w2 = Way(2, {'landusage': 'scrub'}, [1, 2, 3, 4, 1])
+        w2.coords = [(1, 1), (5, 1), (5, 9), (1, 9), (1, 1)]
+        w3 = Way(3, {'water': 'basin'}, [1, 2, 3, 4, 1])
+        w3.coords = [(5, 1), (9, 1), (9, 9), (5, 9), (5, 1)]
+    
+        r = Relation(1, {'landusage': 'forest'}, [
+            (1, 'way', 'outer'), (2, 'way', 'inner'), (3, 'way', 'inner')])
+        builder = self.relation_builder(r, None, None)
+        rings = builder.build_rings([w1, w2, w3])
+        eq_(len(rings), 3)
+        eq_(rings[0].geom.area, 100)
+        eq_(rings[1].geom.area, 32)
+        eq_(rings[2].geom.area, 32)
+    
+        builder.build_relation_geometry(rings)
+
+        eq_(rings[0].inserted, True)
+        eq_(rings[1].inserted, False)
+        eq_(rings[2].inserted, False)
+    
+        eq_(r.geom.area, 100-64)
+
+    def test_touching_polygons_w_hole(self):
+        w1 = Way(1, {'water': 'riverbank'}, [1, 2, 3, 4, 1])
+        w1.coords = [(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)]
+        w2 = Way(2, {'water': 'riverbank'}, [2, 5, 6, 3, 2])
+        w2.coords = [(10, 0), (30, 0), (30, 10), (10, 10), (10, 0)]
+        w3 = Way(3, {'landusage': 'forest'}, [7, 8, 9, 10, 7])
+        w3.coords = [(2, 2), (8, 2), (8, 8), (2, 8), (2, 2)]
+
+        r = Relation(1, {'water': 'riverbank'}, [
+            (1, 'way', 'outer'), (2, 'way', 'outer'), (3, 'way', 'inner')])
+        builder = self.relation_builder(r, None, None)
+        rings = builder.build_rings([w1, w2, w3])
+        eq_(len(rings), 3)
+        eq_(rings[0].geom.area, 100)
+        eq_(rings[1].geom.area, 200)
+        eq_(rings[2].geom.area, 36)
+
+        builder.build_relation_geometry(rings)
+
+        eq_(rings[0].inserted, True)
+        eq_(rings[1].inserted, True)
+        eq_(rings[2].inserted, False)
+
+        eq_(r.geom.area, 100+200-36)
+
+    def test_simple_polygon_from_two_lines(self):
+        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 = self.relation_builder(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_inserted_ways_different_tags(self):
+        w1 = Way(1, {'landusage': 'forest'}, [1, 2, 3])
+        w1.coords = [(0, 0), (10, 0), (10, 10)]
+        w2 = Way(2, {'highway': 'secondary'}, [3, 4, 1])
+        w2.coords = [(10, 10), (0, 10), (0, 0)]
+    
+        r = Relation(1, {'landusage': 'forest'}, [(1, 'way', 'outer'), (2, 'way', 'inner')])
+        builder = self.relation_builder(r, None, None)
+        rings = builder.build_rings([w1, w2])
+        
+        builder.build_relation_geometry(rings)
+        
+        eq_(w1.inserted, True)
+        eq_(w2.inserted, False)
+
+    def test_inserted_multiple_tags(self):
+        w1 = Way(1, {'landusage': 'forest', 'highway': 'secondary'}, [1, 2, 3])
+        w1.coords = [(0, 0), (10, 0), (10, 10)]
+        w2 = Way(2, {'highway': 'secondary'}, [3, 4, 1])
+        w2.coords = [(10, 10), (0, 10), (0, 0)]
+    
+        r = Relation(1, {'landusage': 'forest'}, [(1, 'way', 'outer'), (2, 'way', 'inner')])
+        builder = self.relation_builder(r, None, None)
+        rings = builder.build_rings([w1, w2])
+        
+        builder.build_relation_geometry(rings)
+        
+        eq_(w1.inserted, False) # also highway=secondary
+        eq_(w2.inserted, False)
+    
+class TestUnionRelationBuilder(RelationBuilderTestBase):
+    relation_builder = UnionRelationBuilder
+
+
+class TestContainsRelationBuilder(RelationBuilderTestBase):
+    relation_builder = ContainsRelationBuilder
 
 
 def test_merge_rings():
diff --git a/imposm/test/test_tag_mapper.py b/imposm/test/test_tag_mapper.py
new file mode 100644
index 0000000..98ddda1
--- /dev/null
+++ b/imposm/test/test_tag_mapper.py
@@ -0,0 +1,140 @@
+# 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 imposm
+from imposm.mapping import TagMapper
+
+from nose.tools import eq_
+
+class TestTagMapper(object):
+    def __init__(self):
+        mapping_file = os.path.join(os.path.dirname(__file__), '..',
+            'defaultmapping.py')
+        mappings = {}
+        execfile(mapping_file, mappings)
+        self.tag_mapping = TagMapper([m for n, m in mappings.iteritems() 
+            if isinstance(m, imposm.mapping.Mapping)])
+    
+    def test_tag_filter_nodes(self):
+        tag_filter_for_nodes = self.tag_mapping.tag_filter_for_nodes()
+        tagfilter = lambda x: tag_filter_for_nodes(x) or x
+        
+        eq_(tagfilter({'name': 'foo'}), {})
+        eq_(tagfilter({'name': 'foo', 'unknown': 'baz'}), {})
+        eq_(tagfilter({'name': 'foo', 'place': 'unknown'}), {})
+        eq_(tagfilter({'name': 'foo', 'place': 'village'}), {'name': 'foo', 'place': 'village'})
+        eq_(tagfilter({'name': 'foo', 'place': 'village', 'population': '1000'}),
+            {'name': 'foo', 'place': 'village', 'population': '1000'})
+        eq_(tagfilter({'name': 'foo', 'place': 'village', 'highway': 'unknown'}),
+            {'name': 'foo', 'place': 'village'})
+        eq_(tagfilter({'name': 'foo', 'place': 'village', 'highway': 'bus_stop'}),
+            {'name': 'foo', 'place': 'village', 'highway': 'bus_stop'})
+
+    def test_tag_filter_ways(self):
+        tag_filter_for_ways = self.tag_mapping.tag_filter_for_ways()
+        tagfilter = lambda x: tag_filter_for_ways(x) or x
+        
+        eq_(tagfilter({'name': 'foo'}), {})
+        eq_(tagfilter({'name': 'foo', 'unknown': 'baz'}), {})
+        eq_(tagfilter({'name': 'foo', 'highway': 'unknown'}), {})
+        eq_(tagfilter({'name': 'foo', 'highway': 'track'}), {'name': 'foo', 'highway': 'track'})
+        eq_(tagfilter({'name': 'foo', 'highway': 'track', 'oneway': 'yes', 'tunnel': '1'}),
+            {'name': 'foo', 'highway': 'track', 'oneway': 'yes', 'tunnel': '1'})
+        eq_(tagfilter({'name': 'foo', 'place': 'village', 'highway': 'track'}),
+            {'name': 'foo', 'highway': 'track'})
+        eq_(tagfilter({'name': 'foo', 'railway': 'tram', 'highway': 'secondary'}),
+            {'name': 'foo', 'railway': 'tram', 'highway': 'secondary'})
+
+        # with __any__ value
+        eq_(tagfilter({'name': 'foo', 'building': 'yes'}),
+            {'name': 'foo', 'building': 'yes'})
+        eq_(tagfilter({'name': 'foo', 'building': 'whatever'}),
+            {'name': 'foo', 'building': 'whatever'})
+
+    def test_tag_filter_relations(self):
+        tag_filter_for_relations = self.tag_mapping.tag_filter_for_relations()
+        tagfilter = lambda x: tag_filter_for_relations(x) or x
+        
+        eq_(tagfilter({'name': 'foo'}), {})
+        eq_(tagfilter({'name': 'foo', 'unknown': 'baz'}), {})
+        eq_(tagfilter({'name': 'foo', 'landuse': 'unknown'}), {})
+        eq_(tagfilter({'name': 'foo', 'landuse': 'farm'}), {})
+        eq_(tagfilter({'name': 'foo', 'landuse': 'farm', 'type': 'multipolygon'}),
+            {'name': 'foo', 'landuse': 'farm', 'type': 'multipolygon'})
+
+        # skip multipolygon with filtered tags, otherwise tags from longest way would be used
+        eq_(tagfilter({'name': 'foo', 'landuse': 'unknown', 'type': 'multipolygon'}), {})
+        eq_(tagfilter({'name': 'foo', 'landuse': 'park', 'type': 'multipolygon'}),
+            {'name': 'foo', 'type': 'multipolygon', 'landuse': 'park'})
+
+        eq_(tagfilter({'name': 'foo', 'landuse': 'farm', 'boundary': 'administrative', 'type': 'multipolygon'}),
+            {'name': 'foo', 'landuse': 'farm', 'boundary': 'administrative', 'type': 'multipolygon'})
+        
+        # boundary relation for boundary
+        eq_(tagfilter({'name': 'foo', 'landuse': 'farm', 'boundary': 'administrative', 'type': 'boundary'}),
+            {'name': 'foo', 'landuse': 'farm', 'boundary': 'administrative', 'type': 'boundary'})
+        # boundary relation for non boundary
+        eq_(tagfilter({'name': 'foo', 'landuse': 'farm', 'type': 'boundary'}), {})
+
+        # skip boundary with filtered tags, otherwise tags from longest way would be used
+        eq_(tagfilter({'name': 'foo', 'boundary': 'unknown', 'type': 'boundary'}), {})
+        eq_(tagfilter({'name': 'foo', 'boundary': 'administrative', 'type': 'boundary'}),
+            {'name': 'foo', 'boundary': 'administrative', 'type': 'boundary'})
+
+    def test_mapping_for_nodes(self):
+        for_nodes = self.tag_mapping.for_nodes
+        eq_mapping(for_nodes({'unknown': 'baz'}), [])
+        eq_mapping(for_nodes({'place': 'unknown'}), [])
+        eq_mapping(for_nodes({'place': 'city'}), [(('place', 'city'), ('places',))])
+        eq_mapping(for_nodes({'place': 'city', 'highway': 'unknown'}), [(('place', 'city'), ('places',))])
+        eq_mapping(for_nodes({'place': 'city', 'highway': 'bus_stop'}), 
+            [(('place', 'city'), ('places',)), (('highway', 'bus_stop'), ('transport_points',))])
+
+    def test_mapping_for_ways(self):
+        for_ways = self.tag_mapping.for_ways
+        eq_mapping(for_ways({'unknown': 'baz'}), [])
+        eq_mapping(for_ways({'highway': 'unknown'}), [])
+        eq_mapping(for_ways({'highway': 'track'}), [(('highway', 'track'), ('minorroads',))])
+        eq_mapping(for_ways({'highway': 'secondary', 'railway': 'tram'}), 
+            [(('railway', 'tram'), ('railways',)), (('highway', 'secondary'), ('mainroads',))])
+        eq_mapping(for_ways({'highway': 'footway'}), 
+            [(('highway', 'footway'), ('minorroads',)), (('highway', 'footway'), ('landusages',))])
+
+        eq_mapping(for_ways({'highway': 'footway', 'landuse': 'park'}), 
+            [(('highway', 'footway'), ('minorroads',)), (('landuse', 'park'), ('landusages',))])
+
+    def test_mapping_for_relation(self):
+        for_relations = self.tag_mapping.for_relations
+        eq_mapping(for_relations({'unknown': 'baz'}), [])
+        eq_mapping(for_relations({'landuse': 'unknown'}), [])
+        eq_mapping(for_relations({'landuse': 'farm'}), [(('landuse', 'farm'), ('landusages',))])
+        eq_mapping(for_relations({'landuse': 'farm', 'highway': 'secondary'}),
+            [(('landuse', 'farm'), ('landusages',))])
+        
+        eq_mapping(for_relations({'landuse': 'farm', 'aeroway': 'apron'}),
+            [(('aeroway', 'apron'), ('transport_areas',)), (('landuse', 'farm'), ('landusages',))])
+
+        eq_mapping(for_relations({'boundary': 'administrative', 'admin_level': '8'}),
+            [(('boundary', 'administrative'), ('admin',))])
+
+
+
+
+def eq_mapping(actual_mappings, expected_mappings):
+    assert len(actual_mappings) == len(expected_mappings), '%s != %s' % (actual_mappings, expected_mappings)
+    actual_mappings = [(tags, tuple(m.name for m in mappings)) for tags, mappings in actual_mappings]
+    actual_mappings.sort()
+    expected_mappings.sort()
+    eq_(actual_mappings, expected_mappings)
diff --git a/imposm/version.py b/imposm/version.py
index b70c049..194eb17 100644
--- a/imposm/version.py
+++ b/imposm/version.py
@@ -12,4 +12,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-__version__ = '2.1.3'
+__version__ = '2.3.2'
diff --git a/imposm/writer.py b/imposm/writer.py
index 37aec0f..5b9067e 100644
--- a/imposm/writer.py
+++ b/imposm/writer.py
@@ -12,13 +12,10 @@
 # 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):
@@ -51,6 +48,7 @@ class ImposmWriter(object):
         self.cache.close_all()
 
     def relations(self):
+        self.cache.remove_inserted_way_cache()
         cache = self.cache.relations_cache()
         log = self.logger('relations', len(cache))
         inserted_way_queue = JoinableQueue()
@@ -66,12 +64,13 @@ class ImposmWriter(object):
         cache = self.cache.ways_cache()
         log = self.logger('ways', len(cache))
         self._write_elem(WayProcess, cache, log, self.pool_size)
+        self.cache.remove_inserted_way_cache()
 
     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):
@@ -80,25 +79,14 @@ class WayMarkerProcess(Process):
         self.queue = queue
         self.cache = cache
         self.logger = logger
-    
+
     def run(self):
-        inserted_ways = array.array('I')
+        inserted_ways = self.cache.inserted_ways_cache('w')
         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
+            inserted_ways.put(osmid)
+
+        inserted_ways.close()
+
diff --git a/internal.proto b/internal.proto
new file mode 100644
index 0000000..e05b984
--- /dev/null
+++ b/internal.proto
@@ -0,0 +1,11 @@
+package imposm.cache.internal;
+
+message DeltaCoords {
+   repeated sint64 ids = 1 [packed = true];
+   repeated sint64 lats = 2 [packed = true];
+   repeated sint64 lons = 3 [packed = true];
+}
+
+message DeltaList {
+   repeated sint64 ids = 1 [packed = true];
+}
diff --git a/setup.py b/setup.py
index 1b1d5ab..e9f7d04 100644
--- a/setup.py
+++ b/setup.py
@@ -19,6 +19,10 @@ if sys.version_info < (2, 6):
 class build_ext_with_cython(build_ext):
     def generate_c_file(self):
         try:
+            if (os.path.exists('imposm/cache/tc.c') and
+                os.path.getmtime('imposm/cache/tc.pyx') < os.path.getmtime('imposm/cache/tc.c')):
+                print 'imposm/cache/tc.c up to date'
+                return
             print 'creating imposm/cache/tc.c'
             proc = subprocess.Popen(
                 ['cython', 'imposm/cache/tc.pyx'],
@@ -37,7 +41,33 @@ class build_ext_with_cython(build_ext):
             print out
             raise DistutilsPlatformError("Failed to generate "
                 "C files with cython.")
+    def generate_protoc(self):
+        try:
+            if (os.path.exists('imposm/cache/internal.pb.cc') and 
+                os.path.getmtime('internal.proto') < os.path.getmtime('imposm/cache/internal.pb.cc')):
+                print 'imposm/cache/internal.pb.cc up to date'
+                return
+            print 'creating protofiles'
+            proc = subprocess.Popen(
+                ['protoc', '--cpp_out', 'imposm/cache/', 'internal.proto'],
+                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        except OSError, ex:
+            if ex.errno == errno.ENOENT:
+                print ("Could not find protoc command. Make sure protobuf is "
+                    "installed and your PATH environment is set.")
+                raise DistutilsPlatformError("Failed to generate protbuf "
+                    "CPP files with protoc.")
+            else:
+                raise
+        out = proc.communicate()[0]
+        result = proc.wait()
+        if result != 0:
+            print "Error during protbuf files generation with protoc:"
+            print out
+            raise DistutilsPlatformError("Failed to generate protbuf "
+                "CPP files with protoc.")
     def run(self):
+        self.generate_protoc()
         try:
             self.generate_c_file()
         except DistutilsPlatformError:
@@ -77,6 +107,7 @@ setup(
     ],
     ext_modules=[
         Extension("imposm.cache.tc", ["imposm/cache/tc.c"], libraries = ["tokyocabinet"]),
+        Extension("imposm.cache.internal", ["imposm/cache/internal.cc", "imposm/cache/internal.pb.cc"], libraries = ["protobuf"]),
     ],
     entry_points = {
         'console_scripts': [

-- 
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