diff --git a/cache/delta.go b/cache/delta.go
index 901d576..b338df9 100644
--- a/cache/delta.go
+++ b/cache/delta.go
@@ -93,6 +93,35 @@ func (b *coordsBunch) DeleteCoord(id int64) {
}
}
+// PutCoord puts a single coord into the coords bunch. This function
+// does support updating nodes.
+func (b *coordsBunch) PutCoord(node element.Node) {
+ idx := sort.Search(len(b.coords), func(i int) bool {
+ return b.coords[i].Id >= node.Id
+ })
+ if idx < len(b.coords) {
+ if b.coords[idx].Id == node.Id {
+ // overwrite
+ b.coords[idx] = node
+ } else {
+ // insert
+ b.coords = append(b.coords, node)
+ copy(b.coords[idx+1:], b.coords[idx:])
+ b.coords[idx] = node
+ }
+ } else {
+ // append
+ b.coords = append(b.coords, node)
+ }
+}
+
+// PutCoords puts multiple coords into the coords bunch. This bulk function
+// does not support duplicate or updated nodes.
+func (b *coordsBunch) PutCoords(nodes []element.Node) {
+ b.coords = append(b.coords, nodes...)
+ sort.Sort(byId(b.coords))
+}
+
type DeltaCoordsCache struct {
cache
lruList *list.List
@@ -247,8 +276,14 @@ func (self *DeltaCoordsCache) PutCoords(nodes []element.Node) error {
if err != nil {
return err
}
- bunch.coords = append(bunch.coords, nodes[start:i]...)
- sort.Sort(byId(bunch.coords))
+ if self.linearImport {
+ bunch.PutCoords(nodes[start:i])
+ } else {
+ for _, node := range nodes[start:i] {
+ // single inserts to handle updated coords
+ bunch.PutCoord(node)
+ }
+ }
bunch.needsWrite = true
bunch.Unlock()
}
@@ -260,8 +295,16 @@ func (self *DeltaCoordsCache) PutCoords(nodes []element.Node) error {
if err != nil {
return err
}
- bunch.coords = append(bunch.coords, nodes[start:]...)
- sort.Sort(byId(bunch.coords))
+
+ if self.linearImport {
+ bunch.PutCoords(nodes[start:])
+ } else {
+ for _, node := range nodes[start:] {
+ // single inserts to handle updated coords
+ bunch.PutCoord(node)
+ }
+ }
+
bunch.needsWrite = true
bunch.Unlock()
return nil
diff --git a/cache/delta_test.go b/cache/delta_test.go
index a7e524a..f635292 100644
--- a/cache/delta_test.go
+++ b/cache/delta_test.go
@@ -112,20 +112,76 @@ func checkReadWriteDeltaCoords(t *testing.T, withLinearImport bool) {
}
}
- _, err = cache.GetCoord(999999)
- if err != NotFound {
- t.Error("missing node returned not NotFound")
- }
+ // test overwrite
+ insertAndCheck(t, cache, 100, 50, 50)
// test delete
- cache.PutCoords([]element.Node{mknode(999999)})
-
_, err = cache.GetCoord(999999)
- if err == NotFound {
- t.Error("missing coord")
+ if err != NotFound {
+ t.Error("found missing node")
}
- err = cache.DeleteCoord(999999)
+ insertAndCheck(t, cache, 999999, 10, 10)
+ deleteAndCheck(t, cache, 999999)
+}
+
+func insertAndCheck(t *testing.T, cache *DeltaCoordsCache, id int64, lon, lat float64) {
+ newNode := mknode(id)
+ newNode.Long = lon
+ newNode.Lat = lat
+
+ err := cache.PutCoords([]element.Node{newNode})
if err != nil {
- t.Fatal(err)
+ t.Errorf("error during PutCoords for %v: %s", newNode, err)
+ }
+
+ result, err := cache.GetCoord(id)
+ if err != nil {
+ t.Errorf("got error after getting inserted node %d: %s", id, err)
+ }
+ if result == nil || result.Long != lon || result.Lat != lat {
+ t.Errorf("invalid coords %f, %f != %v", lon, lat, result)
}
}
+
+func deleteAndCheck(t *testing.T, cache *DeltaCoordsCache, id int64) {
+ err := cache.DeleteCoord(id)
+ if err != nil {
+ t.Errorf("error during DeleteCoord for %d: %s", id, err)
+ }
+
+ result, err := cache.GetCoord(id)
+ if err != NotFound {
+ t.Error("found deleted coord", result)
+ }
+}
+
+func TestSingleUpdate(t *testing.T) {
+ cache_dir, _ := ioutil.TempDir("", "imposm3_test")
+ defer os.RemoveAll(cache_dir)
+
+ cache, err := newDeltaCoordsCache(cache_dir)
+ if err != nil {
+ t.Fatal()
+ }
+
+ // insert and update in empty batch
+ insertAndCheck(t, cache, 123, 10, 10)
+ insertAndCheck(t, cache, 123, 10, 11)
+
+ // insert and update in same batch
+ insertAndCheck(t, cache, 1, 1, 1)
+ insertAndCheck(t, cache, 2, 2, 2)
+ insertAndCheck(t, cache, 3, 3, 3)
+ insertAndCheck(t, cache, 4, 4, 4)
+ insertAndCheck(t, cache, 3, 10, 11)
+ insertAndCheck(t, cache, 2, 10, 11)
+ insertAndCheck(t, cache, 1, 10, 11)
+ insertAndCheck(t, cache, 4, 10, 11)
+ // repeat after flushing
+ cache.Flush()
+ insertAndCheck(t, cache, 1, 1, 1)
+ insertAndCheck(t, cache, 2, 2, 2)
+ insertAndCheck(t, cache, 3, 3, 3)
+ insertAndCheck(t, cache, 4, 4, 4)
+
+}
diff --git a/test/imposm_system_test.py b/test/imposm_system_test.py
index eda7506..a71b694 100644
--- a/test/imposm_system_test.py
+++ b/test/imposm_system_test.py
@@ -446,6 +446,11 @@ def test_relation_with_gap():
park = query_row(db_conf, 'osm_landusages', -7301)
assert park['geometry'].is_valid, park
+def test_updated_nodes1():
+ """Zig-Zag line is inserted."""
+ road = query_row(db_conf, 'osm_roads', 60000)
+ assert_almost_equal(road['geometry'].length, 14035.61150207768)
+
#######################################################################
def test_update():
"""Diff import applies"""
@@ -588,6 +593,12 @@ def test_duplicate_ids2():
assert query_row(db_conf, 'osm_buildings', -51011)['type'] == 'mp'
assert query_row(db_conf, 'osm_buildings', 51011) == None
+def test_updated_way2():
+ """All nodes of straightened way are updated."""
+ road = query_row(db_conf, 'osm_roads', 60000)
+ # new length 0.1 degree
+ assert_almost_equal(road['geometry'].length, 20037508.342789244/180.0/10.0)
+
#######################################################################
def test_deploy_and_revert_deploy():
"""Revert deploy succeeds"""
diff --git a/test/test.osc b/test/test.osc
index 117c623..79e2a4f 100644
--- a/test/test.osc
+++ b/test/test.osc
@@ -165,6 +165,15 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/test.osm b/test/test.osm
index 58eac63..db7de05 100644
--- a/test/test.osm
+++ b/test/test.osm
@@ -898,4 +898,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+