update relations when member node changed

master
Oliver Tonnhofer 2016-01-08 16:08:00 +01:00
parent 8eae74a6da
commit 766118b324
10 changed files with 178 additions and 21 deletions

53
cache/diff.go vendored
View File

@ -1,7 +1,6 @@
package cache package cache
import ( import (
"github.com/jmhodges/levigo"
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
@ -9,6 +8,8 @@ import (
"sort" "sort"
"sync" "sync"
"github.com/jmhodges/levigo"
"github.com/omniscale/imposm3/cache/binary" "github.com/omniscale/imposm3/cache/binary"
"github.com/omniscale/imposm3/element" "github.com/omniscale/imposm3/element"
) )
@ -20,10 +21,11 @@ func (a byInt64) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byInt64) Less(i, j int) bool { return a[i] < a[j] } func (a byInt64) Less(i, j int) bool { return a[i] < a[j] }
type DiffCache struct { type DiffCache struct {
Dir string Dir string
Coords *CoordsRefIndex Coords *CoordsRefIndex // Stores which ways a coord references
Ways *WaysRefIndex CoordsRel *CoordsRelRefIndex // Stores which relations a coord references
opened bool Ways *WaysRefIndex // Stores which relations a way references
opened bool
} }
func NewDiffCache(dir string) *DiffCache { func NewDiffCache(dir string) *DiffCache {
@ -36,6 +38,10 @@ func (c *DiffCache) Close() {
c.Coords.Close() c.Coords.Close()
c.Coords = nil c.Coords = nil
} }
if c.CoordsRel != nil {
c.CoordsRel.Close()
c.CoordsRel = nil
}
if c.Ways != nil { if c.Ways != nil {
c.Ways.Close() c.Ways.Close()
c.Ways = nil c.Ways = nil
@ -46,6 +52,9 @@ func (c *DiffCache) Flush() {
if c.Coords != nil { if c.Coords != nil {
c.Coords.Flush() c.Coords.Flush()
} }
if c.CoordsRel != nil {
c.CoordsRel.Flush()
}
if c.Ways != nil { if c.Ways != nil {
c.Ways.Flush() c.Ways.Flush()
} }
@ -58,6 +67,11 @@ func (c *DiffCache) Open() error {
c.Close() c.Close()
return err return err
} }
c.CoordsRel, err = newCoordsRelRefIndex(filepath.Join(c.Dir, "coords_rel_index"))
if err != nil {
c.Close()
return err
}
c.Ways, err = newWaysRefIndex(filepath.Join(c.Dir, "ways_index")) c.Ways, err = newWaysRefIndex(filepath.Join(c.Dir, "ways_index"))
if err != nil { if err != nil {
c.Close() c.Close()
@ -74,6 +88,9 @@ func (c *DiffCache) Exists() bool {
if _, err := os.Stat(filepath.Join(c.Dir, "coords_index")); !os.IsNotExist(err) { if _, err := os.Stat(filepath.Join(c.Dir, "coords_index")); !os.IsNotExist(err) {
return true return true
} }
if _, err := os.Stat(filepath.Join(c.Dir, "coords_rel_index")); !os.IsNotExist(err) {
return true
}
if _, err := os.Stat(filepath.Join(c.Dir, "ways_index")); !os.IsNotExist(err) { if _, err := os.Stat(filepath.Join(c.Dir, "ways_index")); !os.IsNotExist(err) {
return true return true
} }
@ -87,6 +104,9 @@ func (c *DiffCache) Remove() error {
if err := os.RemoveAll(filepath.Join(c.Dir, "coords_index")); err != nil { if err := os.RemoveAll(filepath.Join(c.Dir, "coords_index")); err != nil {
return err return err
} }
if err := os.RemoveAll(filepath.Join(c.Dir, "coords_rel_index")); err != nil {
return err
}
if err := os.RemoveAll(filepath.Join(c.Dir, "ways_index")); err != nil { if err := os.RemoveAll(filepath.Join(c.Dir, "ways_index")); err != nil {
return err return err
} }
@ -198,6 +218,9 @@ func newRefIndex(path string, opts *cacheOptions) (*bunchRefCache, error) {
type CoordsRefIndex struct { type CoordsRefIndex struct {
bunchRefCache bunchRefCache
} }
type CoordsRelRefIndex struct {
bunchRefCache
}
type WaysRefIndex struct { type WaysRefIndex struct {
bunchRefCache bunchRefCache
} }
@ -210,6 +233,14 @@ func newCoordsRefIndex(dir string) (*CoordsRefIndex, error) {
return &CoordsRefIndex{*cache}, nil return &CoordsRefIndex{*cache}, nil
} }
func newCoordsRelRefIndex(dir string) (*CoordsRelRefIndex, error) {
cache, err := newRefIndex(dir, &globalCacheOptions.CoordsIndex)
if err != nil {
return nil, err
}
return &CoordsRelRefIndex{*cache}, nil
}
func newWaysRefIndex(dir string) (*WaysRefIndex, error) { func newWaysRefIndex(dir string) (*WaysRefIndex, error) {
cache, err := newRefIndex(dir, &globalCacheOptions.WaysIndex) cache, err := newRefIndex(dir, &globalCacheOptions.WaysIndex)
if err != nil { if err != nil {
@ -365,6 +396,18 @@ func (index *CoordsRefIndex) DeleteFromWay(way *element.Way) {
} }
} }
func (index *CoordsRelRefIndex) AddFromMembers(relId int64, members []element.Member) {
for _, member := range members {
if member.Type == element.NODE {
if index.linearImport {
index.addc <- idRef{id: member.Id, ref: relId}
} else {
index.Add(member.Id, relId)
}
}
}
}
func (index *WaysRefIndex) AddFromMembers(relId int64, members []element.Member) { func (index *WaysRefIndex) AddFromMembers(relId int64, members []element.Member) {
for _, member := range members { for _, member := range members {
if member.Type == element.WAY { if member.Type == element.WAY {

View File

@ -258,6 +258,15 @@ func (d *Deleter) Delete(delElem parser.DiffElem) error {
} }
} }
} }
dependers = d.diffCache.CoordsRel.Get(delElem.Node.Id)
for _, rel := range dependers {
if _, ok := d.deletedRelations[rel]; ok {
continue
}
if err := d.deleteRelation(rel, false, false); err != nil {
return err
}
}
} }
if !delElem.Add { if !delElem.Add {
if err := d.diffCache.Coords.Delete(delElem.Node.Id); err != nil { if err := d.diffCache.Coords.Delete(delElem.Node.Id); err != nil {

View File

@ -175,9 +175,9 @@ func Update(oscFile string, geometryLimiter *limit.Limiter, expireor expire.Expi
nodeWriter.SetExpireor(expireor) nodeWriter.SetExpireor(expireor)
nodeWriter.Start() nodeWriter.Start()
nodeIds := make(map[int64]bool) nodeIds := make(map[int64]struct{})
wayIds := make(map[int64]bool) wayIds := make(map[int64]struct{})
relIds := make(map[int64]bool) relIds := make(map[int64]struct{})
step := log.StartStep("Parsing changes, updating cache and removing elements") step := log.StartStep("Parsing changes, updating cache and removing elements")
@ -251,7 +251,7 @@ func Update(oscFile string, geometryLimiter *limit.Limiter, expireor expire.Expi
if err != nil { if err != nil {
return diffError(err, "put relation %v", elem.Rel) return diffError(err, "put relation %v", elem.Rel)
} }
relIds[elem.Rel.Id] = true relIds[elem.Rel.Id] = struct{}{}
} }
} else if elem.Way != nil { } else if elem.Way != nil {
// check if first coord is cached to avoid caching // check if first coord is cached to avoid caching
@ -265,7 +265,7 @@ func Update(oscFile string, geometryLimiter *limit.Limiter, expireor expire.Expi
if err != nil { if err != nil {
return diffError(err, "put way %v", elem.Way) return diffError(err, "put way %v", elem.Way)
} }
wayIds[elem.Way.Id] = true wayIds[elem.Way.Id] = struct{}{}
} }
} else if elem.Node != nil { } else if elem.Node != nil {
addNode := true addNode := true
@ -283,7 +283,7 @@ func Update(oscFile string, geometryLimiter *limit.Limiter, expireor expire.Expi
if err != nil { if err != nil {
return diffError(err, "put coord %v", elem.Node) return diffError(err, "put coord %v", elem.Node)
} }
nodeIds[elem.Node.Id] = true nodeIds[elem.Node.Id] = struct{}{}
} }
} }
} }
@ -301,7 +301,7 @@ func Update(oscFile string, geometryLimiter *limit.Limiter, expireor expire.Expi
// mark member ways from deleted relations for re-insert // mark member ways from deleted relations for re-insert
for id, _ := range deleter.DeletedMemberWays() { for id, _ := range deleter.DeletedMemberWays() {
wayIds[id] = true wayIds[id] = struct{}{}
} }
progress.Stop() progress.Stop()
@ -314,16 +314,22 @@ func Update(oscFile string, geometryLimiter *limit.Limiter, expireor expire.Expi
for nodeId, _ := range nodeIds { for nodeId, _ := range nodeIds {
dependers := diffCache.Coords.Get(nodeId) dependers := diffCache.Coords.Get(nodeId)
for _, way := range dependers { for _, way := range dependers {
wayIds[way] = true wayIds[way] = struct{}{}
} }
} }
// mark depending relations for (re)insert // mark depending relations for (re)insert
for nodeId, _ := range nodeIds {
dependers := diffCache.CoordsRel.Get(nodeId)
for _, rel := range dependers {
relIds[rel] = struct{}{}
}
}
for wayId, _ := range wayIds { for wayId, _ := range wayIds {
dependers := diffCache.Ways.Get(wayId) dependers := diffCache.Ways.Get(wayId)
// mark depending relations for (re)insert // mark depending relations for (re)insert
for _, rel := range dependers { for _, rel := range dependers {
relIds[rel] = true relIds[rel] = struct{}{}
} }
} }

View File

@ -225,4 +225,11 @@
</relation> </relation>
</create> </create>
<!-- test that relations are updated after modified node -->
<modify>
<node id="52101" version="1" timestamp="2011-11-11T00:11:11Z" lat="61" lon="10"/>
</modify>
</osmChange> </osmChange>

View File

@ -1019,6 +1019,26 @@
<tag k="building" v="mp"/> <tag k="building" v="mp"/>
</relation> </relation>
<!-- test that relations are updated after modified node -->
<node id="52101" version="1" timestamp="2011-11-11T00:11:11Z" lat="62" lon="10"/>
<node id="52102" version="1" timestamp="2011-11-11T00:11:11Z" lat="62" lon="11"/>
<node id="52103" version="1" timestamp="2011-11-11T00:11:11Z" lat="64" lon="10"/>
<node id="52104" version="1" timestamp="2011-11-11T00:11:11Z" lat="64" lon="11"/>
<way id="52111" version="1" timestamp="2011-11-11T00:11:11Z">
<nd ref="52101"/>
<nd ref="52102"/>
<nd ref="52103"/>
<nd ref="52104"/>
<nd ref="52101"/>
<tag k="building" v="yes"/>
</way>
<relation id="52121" version="1" timestamp="2011-11-11T00:11:11Z">
<member type="way" ref="52111" role="outer"/>
<tag k="type" v="multipolygon"/>
</relation>
<!-- zig-zag line with coords internaly cached in differend deltacoords bunches --> <!-- 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="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="60002" version="1" timestamp="2011-11-11T00:11:11Z" lat="0.00" lon="20.01"/>

View File

@ -297,6 +297,12 @@ func TestDuplicateIds(t *testing.T) {
}) })
} }
func TestRelationUpdatedByNode(t *testing.T) {
// Relations was updated after modified node.
assertArea(t, checkElem{"osm_buildings", -52121, "yes", nil}, 13653930440.868315)
}
func TestGeneralizedBananaPolygonIsValid(t *testing.T) { func TestGeneralizedBananaPolygonIsValid(t *testing.T) {
// Generalized polygons are valid. // Generalized polygons are valid.
@ -605,6 +611,12 @@ func TestDuplicateIds2(t *testing.T) {
}) })
} }
func TestRelationUpdatedByNode2(t *testing.T) {
// Relations was updated after modified node.
assertArea(t, checkElem{"osm_buildings", -52121, "yes", nil}, 16276875196.653734)
}
func TestUpdatedWay2(t *testing.T) { func TestUpdatedWay2(t *testing.T) {
// All nodes of straightened way are updated. // All nodes of straightened way are updated.

View File

@ -9,4 +9,36 @@
<tag k="name" v="new name"/> <tag k="name" v="new name"/>
</way> </way>
</modify> </modify>
<modify>
<relation id="100902" version="23" timestamp="2015-06-02T04:13:19Z">
<member type="node" ref="100104" role="stop_entry_only"/>
<member type="way" ref="100514" role="platform_entry_only"/>
<member type="node" ref="100103" role="stop"/>
<member type="way" ref="100513" role="platform"/>
<member type="node" ref="100102" role="halt"/> <!-- changed role -->
<!-- <member type="way" ref="100512" role="platform"/> removed -->
<member type="node" ref="100101" role="stop_exit_only"/>
<member type="way" ref="100511" role="platform_exit_only"/>
<member type="way" ref="100503" role=""/>
<member type="way" ref="100502" role=""/>
<member type="way" ref="100501" role=""/>
<tag k="colour" v="#F5A9E1"/>
<tag k="from" v="B"/>
<tag k="name" v="Bus 301: B =&gt; A"/>
<tag k="network" v="ABC"/>
<tag k="ref" v="301"/>
<tag k="route" v="bus"/>
<tag k="to" v="A"/>
<tag k="type" v="route"/>
</relation>
</modify>
<modify>
<!-- modified node updates relation -->
<node id="110101" version="1" timestamp="2015-12-31T23:59:99Z" lat="53.0" lon="8.200">
<tag k="name" v="Stop2"/>
</node>
</modify>
</osmChange> </osmChange>

View File

@ -128,4 +128,16 @@
<tag k="type" v="route_master"/> <tag k="type" v="route_master"/>
</relation> </relation>
<!-- modified node updates relation -->
<node id="110101" version="1" timestamp="2015-12-31T23:59:99Z" lat="53.0" lon="8.200">
<tag k="name" v="Stop"/>
</node>
<relation id="110901" version="23" timestamp="2015-06-02T04:13:19Z">
<member type="node" ref="110101" role="stop"/>
<tag k="route" v="bus"/>
<tag k="type" v="route"/>
</relation>
</osm> </osm>

View File

@ -2,7 +2,6 @@ package test
import ( import (
"database/sql" "database/sql"
"strconv"
"testing" "testing"
@ -92,6 +91,7 @@ func TestRouteRelation_MemberGeomUpdated2(t *testing.T) {
t.Fatal(g.Length()) t.Fatal(g.Length())
} }
// tag from member is updated
rows = ts.queryDynamic(t, "osm_route_members", "osm_id = -100902 AND member = 100503") rows = ts.queryDynamic(t, "osm_route_members", "osm_id = -100902 AND member = 100503")
if len(rows) != 1 { if len(rows) != 1 {
t.Fatal(rows) t.Fatal(rows)
@ -99,16 +99,31 @@ func TestRouteRelation_MemberGeomUpdated2(t *testing.T) {
if rows[0]["name"] != "new name" { if rows[0]["name"] != "new name" {
t.Error(rows[0]) t.Error(rows[0])
} }
}
func TestRouteRelation_MemberNotUpdated(t *testing.T) { // member is removed
// check that member is not updated if no node/way changed rows = ts.queryDynamic(t, "osm_route_members", "osm_id = -100902 AND member = 100512")
rows := ts.queryDynamic(t, "osm_route_members", "osm_id = -100903 AND member = 100501") if len(rows) != 0 {
t.Fatal(rows)
}
// role from member is updated
rows = ts.queryDynamic(t, "osm_route_members", "osm_id = -100902 AND member = 100102")
if len(rows) != 1 { if len(rows) != 1 {
t.Fatal(rows) t.Fatal(rows)
} }
if id, err := strconv.ParseInt(rows[0]["id"], 10, 32); err != nil || id > 27 { if rows[0]["role"] != "halt" {
t.Error("member was re-inserted", rows) t.Error(rows[0])
} }
} }
func TestRouteRelation_MemberUpdatedByNode(t *testing.T) {
// check that member is updated after node was modified
rows := ts.queryDynamic(t, "osm_route_members", "osm_id = -110901 AND member = 110101")
if len(rows) != 1 {
t.Fatal(rows)
}
if rows[0]["name"] != "Stop2" {
t.Error(rows[0])
}
}

View File

@ -115,6 +115,7 @@ NextRel:
if inserted && rw.diffCache != nil { if inserted && rw.diffCache != nil {
rw.diffCache.Ways.AddFromMembers(r.Id, allMembers) rw.diffCache.Ways.AddFromMembers(r.Id, allMembers)
rw.diffCache.CoordsRel.AddFromMembers(r.Id, allMembers)
for _, member := range allMembers { for _, member := range allMembers {
if member.Way != nil { if member.Way != nil {
rw.diffCache.Coords.AddFromWay(member.Way) rw.diffCache.Coords.AddFromWay(member.Way)