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
import (
"github.com/jmhodges/levigo"
"log"
"os"
"path/filepath"
@ -9,6 +8,8 @@ import (
"sort"
"sync"
"github.com/jmhodges/levigo"
"github.com/omniscale/imposm3/cache/binary"
"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] }
type DiffCache struct {
Dir string
Coords *CoordsRefIndex
Ways *WaysRefIndex
opened bool
Dir string
Coords *CoordsRefIndex // Stores which ways a coord references
CoordsRel *CoordsRelRefIndex // Stores which relations a coord references
Ways *WaysRefIndex // Stores which relations a way references
opened bool
}
func NewDiffCache(dir string) *DiffCache {
@ -36,6 +38,10 @@ func (c *DiffCache) Close() {
c.Coords.Close()
c.Coords = nil
}
if c.CoordsRel != nil {
c.CoordsRel.Close()
c.CoordsRel = nil
}
if c.Ways != nil {
c.Ways.Close()
c.Ways = nil
@ -46,6 +52,9 @@ func (c *DiffCache) Flush() {
if c.Coords != nil {
c.Coords.Flush()
}
if c.CoordsRel != nil {
c.CoordsRel.Flush()
}
if c.Ways != nil {
c.Ways.Flush()
}
@ -58,6 +67,11 @@ func (c *DiffCache) Open() error {
c.Close()
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"))
if err != nil {
c.Close()
@ -74,6 +88,9 @@ func (c *DiffCache) Exists() bool {
if _, err := os.Stat(filepath.Join(c.Dir, "coords_index")); !os.IsNotExist(err) {
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) {
return true
}
@ -87,6 +104,9 @@ func (c *DiffCache) Remove() error {
if err := os.RemoveAll(filepath.Join(c.Dir, "coords_index")); err != nil {
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 {
return err
}
@ -198,6 +218,9 @@ func newRefIndex(path string, opts *cacheOptions) (*bunchRefCache, error) {
type CoordsRefIndex struct {
bunchRefCache
}
type CoordsRelRefIndex struct {
bunchRefCache
}
type WaysRefIndex struct {
bunchRefCache
}
@ -210,6 +233,14 @@ func newCoordsRefIndex(dir string) (*CoordsRefIndex, error) {
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) {
cache, err := newRefIndex(dir, &globalCacheOptions.WaysIndex)
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) {
for _, member := range members {
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 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.Start()
nodeIds := make(map[int64]bool)
wayIds := make(map[int64]bool)
relIds := make(map[int64]bool)
nodeIds := make(map[int64]struct{})
wayIds := make(map[int64]struct{})
relIds := make(map[int64]struct{})
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 {
return diffError(err, "put relation %v", elem.Rel)
}
relIds[elem.Rel.Id] = true
relIds[elem.Rel.Id] = struct{}{}
}
} else if elem.Way != nil {
// 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 {
return diffError(err, "put way %v", elem.Way)
}
wayIds[elem.Way.Id] = true
wayIds[elem.Way.Id] = struct{}{}
}
} else if elem.Node != nil {
addNode := true
@ -283,7 +283,7 @@ func Update(oscFile string, geometryLimiter *limit.Limiter, expireor expire.Expi
if err != nil {
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
for id, _ := range deleter.DeletedMemberWays() {
wayIds[id] = true
wayIds[id] = struct{}{}
}
progress.Stop()
@ -314,16 +314,22 @@ func Update(oscFile string, geometryLimiter *limit.Limiter, expireor expire.Expi
for nodeId, _ := range nodeIds {
dependers := diffCache.Coords.Get(nodeId)
for _, way := range dependers {
wayIds[way] = true
wayIds[way] = struct{}{}
}
}
// 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 {
dependers := diffCache.Ways.Get(wayId)
// mark depending relations for (re)insert
for _, rel := range dependers {
relIds[rel] = true
relIds[rel] = struct{}{}
}
}

View File

@ -225,4 +225,11 @@
</relation>
</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>

View File

@ -1019,6 +1019,26 @@
<tag k="building" v="mp"/>
</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 -->
<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"/>

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) {
// 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) {
// All nodes of straightened way are updated.

View File

@ -9,4 +9,36 @@
<tag k="name" v="new name"/>
</way>
</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>

View File

@ -128,4 +128,16 @@
<tag k="type" v="route_master"/>
</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>

View File

@ -2,7 +2,6 @@ package test
import (
"database/sql"
"strconv"
"testing"
@ -92,6 +91,7 @@ func TestRouteRelation_MemberGeomUpdated2(t *testing.T) {
t.Fatal(g.Length())
}
// tag from member is updated
rows = ts.queryDynamic(t, "osm_route_members", "osm_id = -100902 AND member = 100503")
if len(rows) != 1 {
t.Fatal(rows)
@ -99,16 +99,31 @@ func TestRouteRelation_MemberGeomUpdated2(t *testing.T) {
if rows[0]["name"] != "new name" {
t.Error(rows[0])
}
}
func TestRouteRelation_MemberNotUpdated(t *testing.T) {
// check that member is not updated if no node/way changed
rows := ts.queryDynamic(t, "osm_route_members", "osm_id = -100903 AND member = 100501")
// member is removed
rows = ts.queryDynamic(t, "osm_route_members", "osm_id = -100902 AND member = 100512")
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 {
t.Fatal(rows)
}
if id, err := strconv.ParseInt(rows[0]["id"], 10, 32); err != nil || id > 27 {
t.Error("member was re-inserted", rows)
if rows[0]["role"] != "halt" {
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 {
rw.diffCache.Ways.AddFromMembers(r.Id, allMembers)
rw.diffCache.CoordsRel.AddFromMembers(r.Id, allMembers)
for _, member := range allMembers {
if member.Way != nil {
rw.diffCache.Coords.AddFromWay(member.Way)