fix updating nodes in DeltaCoordsCache

Updating an existing node in the DeltaCoordsCache resulted in duplicate
nodes instead of a single updated node. GetCoord returned the first node,
depending on the sort order.
master
Oliver Tonnhofer 2014-04-25 11:18:20 +02:00
parent e4d1156ff8
commit 96b5f1c394
5 changed files with 155 additions and 16 deletions

51
cache/delta.go vendored
View File

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

76
cache/delta_test.go vendored
View File

@ -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)
}

View File

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

View File

@ -165,6 +165,15 @@
<way id="51011" />
</delete>
<!-- update zig-zag line with coords internaly cached in differend deltacoords bunches -->
<modify>
<node id="60001" version="1" timestamp="2011-11-11T00:11:11Z" lat="0" lon="20.00"/>
<node id="60002" version="1" timestamp="2011-11-11T00:11:11Z" lat="0" lon="20.01"/>
<node id="60003" version="1" timestamp="2011-11-11T00:11:11Z" lat="0" lon="20.02"/>
<node id="61004" version="1" timestamp="2011-11-11T00:11:11Z" lat="0" lon="20.03"/>
<node id="62005" version="1" timestamp="2011-11-11T00:11:11Z" lat="0" lon="20.04"/>
<node id="63006" version="1" timestamp="2011-11-11T00:11:11Z" lat="0" lon="20.05"/>
<node id="64007" version="1" timestamp="2011-11-11T00:11:11Z" lat="0" lon="20.06"/>
<node id="64008" version="1" timestamp="2011-11-11T00:11:11Z" lat="0" lon="20.10"/>
</modify>
</osmChange>

View File

@ -898,4 +898,24 @@
<tag k="building" v="mp"/>
</relation>
<!-- zig-zag line with coords internaly cached in differend deltacoords bunches -->
<node id="60001" version="1" timestamp="2011-11-11T00:11:11Z" lat="0.01" lon="20.00"/>
<node id="60002" version="1" timestamp="2011-11-11T00:11:11Z" lat="0.00" lon="20.01"/>
<node id="60003" version="1" timestamp="2011-11-11T00:11:11Z" lat="0.01" lon="20.02"/>
<node id="61004" version="1" timestamp="2011-11-11T00:11:11Z" lat="0.00" lon="20.03"/>
<node id="62005" version="1" timestamp="2011-11-11T00:11:11Z" lat="0.01" lon="20.04"/>
<node id="63006" version="1" timestamp="2011-11-11T00:11:11Z" lat="0.00" lon="20.05"/>
<node id="64007" version="1" timestamp="2011-11-11T00:11:11Z" lat="0.01" lon="20.06"/>
<node id="64008" version="1" timestamp="2011-11-11T00:11:11Z" lat="0.00" lon="20.10"/>
<way id="60000" version="1" timestamp="2011-11-11T00:11:11Z">
<nd ref="60001"/>
<nd ref="60002"/>
<nd ref="60003"/>
<nd ref="61004"/>
<nd ref="62005"/>
<nd ref="63006"/>
<nd ref="64007"/>
<nd ref="64008"/>
<tag k="highway" v="residential"/>
</way>
</osm>