示例#1
0
文件: reader.go 项目: Rachine/imposm3
func ReadPbf(cache *osmcache.OSMCache, progress *stats.Statistics,
	tagmapping *mapping.Mapping, pbfFile *pbf.Pbf,
	limiter *limit.Limiter,
) {
	nodes := make(chan []element.Node, 4)
	coords := make(chan []element.Node, 4)
	ways := make(chan []element.Way, 4)
	relations := make(chan []element.Relation, 4)

	withLimiter := false
	if limiter != nil {
		withLimiter = true
	}

	if pbfFile.Header.Time.Unix() != 0 {
		log.Printf("reading %s with data till %v", pbfFile.Filename, pbfFile.Header.Time.Local())
	}

	parser := pbf.NewParser(pbfFile, coords, nodes, ways, relations)

	// wait for all coords/nodes to be processed before continuing with
	// ways. required for -limitto checks
	coordsSync := sync.WaitGroup{}
	parser.FinishedCoords(func() {
		for i := 0; int64(i) < nCoords; i++ {
			coords <- nil
		}
		for i := 0; int64(i) < nNodes; i++ {
			nodes <- nil
		}
		coordsSync.Wait()
	})

	// wait for all ways to be processed before continuing with
	// relations. required for -limitto checks
	waysSync := sync.WaitGroup{}
	parser.FinishedWays(func() {
		for i := 0; int64(i) < nWays; i++ {
			ways <- nil
		}
		waysSync.Wait()
	})

	waitWriter := sync.WaitGroup{}

	for i := 0; int64(i) < nWays; i++ {
		waysSync.Add(1)
		waitWriter.Add(1)
		go func() {
			var skip, hit int

			m := tagmapping.WayTagFilter()
			for ws := range ways {
				if ws == nil {
					waysSync.Done()
					waysSync.Wait()
					continue
				}
				if skipWays {
					continue
				}
				for i, _ := range ws {
					m.Filter(&ws[i].Tags)
					if withLimiter {
						cached, err := cache.Coords.FirstRefIsCached(ws[i].Refs)
						if err != nil {
							log.Errorf("error while checking for cached refs of way %d: %v", ws[i].Id, err)
							cached = true // don't skip in case of error
						}
						if cached {
							hit += 1
						} else {
							ws[i].Id = osmcache.SKIP
							skip += 1
						}
					}
				}
				err := cache.Ways.PutWays(ws)
				if err != nil {
					log.Errorf("error while caching ways: %v", err)
				}
				progress.AddWays(len(ws))
			}

			waitWriter.Done()
		}()
	}

	for i := 0; int64(i) < nRels; i++ {
		waitWriter.Add(1)
		go func() {
			var skip, hit int

			m := tagmapping.RelationTagFilter()
			for rels := range relations {
				numWithTags := 0
				for i, _ := range rels {
					m.Filter(&rels[i].Tags)
					if len(rels[i].Tags) > 0 {
						numWithTags += 1
					}
					if withLimiter {
						cached, err := cache.FirstMemberIsCached(rels[i].Members)
						if err != nil {
							log.Errorf("error while checking for cached members of relation %d: %v", rels[i].Id, err)
							cached = true // don't skip in case of error
						}
						if cached {
							hit += 1
						} else {
							skip += 1
							rels[i].Id = osmcache.SKIP
						}
					}
				}
				err := cache.Relations.PutRelations(rels)
				if err != nil {
					log.Errorf("error while caching relation: %v", err)
				}
				progress.AddRelations(numWithTags)
			}

			waitWriter.Done()
		}()
	}

	for i := 0; int64(i) < nCoords; i++ {
		coordsSync.Add(1)
		waitWriter.Add(1)
		go func() {
			var skip, hit int
			g := geos.NewGeos()
			defer g.Finish()
			for nds := range coords {
				if nds == nil {
					coordsSync.Done()
					coordsSync.Wait()
					continue
				}
				if withLimiter {
					for i, _ := range nds {
						if !limiter.IntersectsBuffer(g, nds[i].Long, nds[i].Lat) {
							skip += 1
							nds[i].Id = osmcache.SKIP
						} else {
							hit += 1
						}
					}
				}
				cache.Coords.PutCoords(nds)
				progress.AddCoords(len(nds))
			}
			waitWriter.Done()
		}()
	}

	for i := 0; int64(i) < nNodes; i++ {
		coordsSync.Add(1)
		waitWriter.Add(1)
		go func() {
			g := geos.NewGeos()
			defer g.Finish()
			m := tagmapping.NodeTagFilter()
			for nds := range nodes {
				if nds == nil {
					coordsSync.Done()
					coordsSync.Wait()
					continue
				}
				numWithTags := 0
				for i, _ := range nds {
					m.Filter(&nds[i].Tags)
					if len(nds[i].Tags) > 0 {
						numWithTags += 1
					}
					if withLimiter {
						if !limiter.IntersectsBuffer(g, nds[i].Long, nds[i].Lat) {
							nds[i].Id = osmcache.SKIP
						}
					}
				}
				cache.Nodes.PutNodes(nds)
				progress.AddNodes(numWithTags)
			}
			waitWriter.Done()
		}()
	}

	parser.Parse()
	waitWriter.Wait()
}
示例#2
0
func Update(oscFile string, geometryLimiter *limit.Limiter, expireor expire.Expireor, osmCache *cache.OSMCache, diffCache *cache.DiffCache, force bool) error {
	state, err := diffstate.ParseFromOsc(oscFile)
	if err != nil {
		return err
	}
	lastState, err := diffstate.ParseLastState(config.BaseOptions.DiffDir)
	if err != nil {
		log.Warn(err)
	}

	if lastState != nil && lastState.Sequence != 0 && state != nil && state.Sequence <= lastState.Sequence {
		if !force {
			log.Warn(state, " already imported")
			return nil
		}
	}

	defer log.StopStep(log.StartStep(fmt.Sprintf("Processing %s", oscFile)))

	elems, errc := parser.Parse(oscFile)

	tagmapping, err := mapping.NewMapping(config.BaseOptions.MappingFile)
	if err != nil {
		return err
	}

	dbConf := database.Config{
		ConnectionParams: config.BaseOptions.Connection,
		Srid:             config.BaseOptions.Srid,
		// we apply diff imports on the Production schema
		ImportSchema:     config.BaseOptions.Schemas.Production,
		ProductionSchema: config.BaseOptions.Schemas.Production,
		BackupSchema:     config.BaseOptions.Schemas.Backup,
	}
	db, err := database.Open(dbConf, tagmapping)
	if err != nil {
		return errors.New("database open: " + err.Error())
	}
	defer db.Close()

	err = db.Begin()
	if err != nil {
		return err
	}

	delDb, ok := db.(database.Deleter)
	if !ok {
		return errors.New("database not deletable")
	}

	genDb, ok := db.(database.Generalizer)
	if ok {
		genDb.EnableGeneralizeUpdates()
	}

	deleter := NewDeleter(
		delDb,
		osmCache,
		diffCache,
		tagmapping.SingleIdSpace,
		tagmapping.PointMatcher(),
		tagmapping.LineStringMatcher(),
		tagmapping.PolygonMatcher(),
	)

	progress := stats.NewStatsReporter()

	relTagFilter := tagmapping.RelationTagFilter()
	wayTagFilter := tagmapping.WayTagFilter()
	nodeTagFilter := tagmapping.NodeTagFilter()

	relations := make(chan *element.Relation)
	ways := make(chan *element.Way)
	nodes := make(chan *element.Node)

	relWriter := writer.NewRelationWriter(osmCache, diffCache,
		tagmapping.SingleIdSpace,
		relations,
		db, progress,
		tagmapping.PolygonMatcher(),
		tagmapping.RelationMatcher(),
		tagmapping.RelationMemberMatcher(),
		config.BaseOptions.Srid)
	relWriter.SetLimiter(geometryLimiter)
	relWriter.SetExpireor(expireor)
	relWriter.Start()

	wayWriter := writer.NewWayWriter(osmCache, diffCache,
		tagmapping.SingleIdSpace,
		ways, db,
		progress,
		tagmapping.PolygonMatcher(),
		tagmapping.LineStringMatcher(),
		config.BaseOptions.Srid)
	wayWriter.SetLimiter(geometryLimiter)
	wayWriter.SetExpireor(expireor)
	wayWriter.Start()

	nodeWriter := writer.NewNodeWriter(osmCache, nodes, db,
		progress,
		tagmapping.PointMatcher(),
		config.BaseOptions.Srid)
	nodeWriter.SetLimiter(geometryLimiter)
	nodeWriter.SetExpireor(expireor)
	nodeWriter.Start()

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

	g := geos.NewGeos()

	for {
		select {
		case elem, ok := <-elems:
			if !ok {
				elems = nil
				break
			}
			if elem.Rel != nil {
				relTagFilter.Filter(&elem.Rel.Tags)
				progress.AddRelations(1)
			} else if elem.Way != nil {
				wayTagFilter.Filter(&elem.Way.Tags)
				progress.AddWays(1)
			} else if elem.Node != nil {
				nodeTagFilter.Filter(&elem.Node.Tags)
				if len(elem.Node.Tags) > 0 {
					progress.AddNodes(1)
				}
				progress.AddCoords(1)
			}

			// always delete, to prevent duplicate elements from overlap of initial
			// import and diff import
			if err := deleter.Delete(elem); err != nil {
				return diffError(err, "delete element", elem)
			}
			if elem.Del {
				if !elem.Add {
					// no new or modified elem -> remove from cache
					if elem.Rel != nil {
						if err := osmCache.Relations.DeleteRelation(elem.Rel.Id); err != nil && err != cache.NotFound {
							return diffError(err, "delete relation %v", elem.Rel)
						}
					} else if elem.Way != nil {
						if err := osmCache.Ways.DeleteWay(elem.Way.Id); err != nil && err != cache.NotFound {
							return diffError(err, "delete way %v", elem.Way)
						}
						if err := diffCache.Ways.Delete(elem.Way.Id); err != nil && err != cache.NotFound {
							return diffError(err, "delete way references %v", elem.Way)
						}
					} else if elem.Node != nil {
						if err := osmCache.Nodes.DeleteNode(elem.Node.Id); err != nil && err != cache.NotFound {
							return diffError(err, "delete node %v", elem.Node)
						}
						if err := osmCache.Coords.DeleteCoord(elem.Node.Id); err != nil && err != cache.NotFound {
							return diffError(err, "delete coord %v", elem.Node)
						}
					}
				} else if elem.Node != nil && elem.Node.Tags == nil {
					// handle modifies where a node drops all tags
					if err := osmCache.Nodes.DeleteNode(elem.Node.Id); err != nil && err != cache.NotFound {
						return diffError(err, "delete node %v", elem.Node)
					}
				}
			}
			if elem.Add {
				if elem.Rel != nil {
					// check if first member is cached to avoid caching
					// unneeded relations (typical outside of our coverage)
					cached, err := osmCache.FirstMemberIsCached(elem.Rel.Members)
					if err != nil {
						return diffError(err, "query first member %v", elem.Rel)
					}
					if cached {
						err := osmCache.Relations.PutRelation(elem.Rel)
						if err != nil {
							return diffError(err, "put relation %v", elem.Rel)
						}
						relIds[elem.Rel.Id] = struct{}{}
					}
				} else if elem.Way != nil {
					// check if first coord is cached to avoid caching
					// unneeded ways (typical outside of our coverage)
					cached, err := osmCache.Coords.FirstRefIsCached(elem.Way.Refs)
					if err != nil {
						return diffError(err, "query first ref %v", elem.Way)
					}
					if cached {
						err := osmCache.Ways.PutWay(elem.Way)
						if err != nil {
							return diffError(err, "put way %v", elem.Way)
						}
						wayIds[elem.Way.Id] = struct{}{}
					}
				} else if elem.Node != nil {
					addNode := true
					if geometryLimiter != nil {
						if !geometryLimiter.IntersectsBuffer(g, elem.Node.Long, elem.Node.Lat) {
							addNode = false
						}
					}
					if addNode {
						err := osmCache.Nodes.PutNode(elem.Node)
						if err != nil {
							return diffError(err, "put node %v", elem.Node)
						}
						err = osmCache.Coords.PutCoords([]element.Node{*elem.Node})
						if err != nil {
							return diffError(err, "put coord %v", elem.Node)
						}
						nodeIds[elem.Node.Id] = struct{}{}
					}
				}
			}
		case err, ok := <-errc:
			if !ok {
				errc = nil
				break
			}
			return diffError(err, "")
		}
		if errc == nil && elems == nil {
			break
		}
	}

	// mark member ways from deleted relations for re-insert
	for id, _ := range deleter.DeletedMemberWays() {
		wayIds[id] = struct{}{}
	}

	progress.Stop()
	log.StopStep(step)
	step = log.StartStep("Writing added/modified elements")

	progress = stats.NewStatsReporter()

	// mark depending ways for (re)insert
	for nodeId, _ := range nodeIds {
		dependers := diffCache.Coords.Get(nodeId)
		for _, way := range dependers {
			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] = struct{}{}
		}
	}

	for relId, _ := range relIds {
		rel, err := osmCache.Relations.GetRelation(relId)
		if err != nil {
			if err != cache.NotFound {
				return diffError(err, "could not get relation %v", relId)
			}
			continue
		}
		// insert new relation
		progress.AddRelations(1)
		// filter out unsupported relation types, otherwise they might
		// get inserted with the tags from an outer way
		if relTagFilter.Filter(&rel.Tags) {
			relations <- rel
		}
	}

	for wayId, _ := range wayIds {
		way, err := osmCache.Ways.GetWay(wayId)
		if err != nil {
			if err != cache.NotFound {
				return diffError(err, "could not get way %v", wayId)
			}
			continue
		}
		// insert new way
		progress.AddWays(1)
		ways <- way
	}

	for nodeId, _ := range nodeIds {
		node, err := osmCache.Nodes.GetNode(nodeId)
		if err != nil {
			if err != cache.NotFound {
				return diffError(err, "could not get node %v", nodeId)
			}
			// missing nodes can still be Coords
			// no `continue` here
		}
		if node != nil {
			// insert new node
			progress.AddNodes(1)
			nodes <- node
		}
	}

	close(relations)
	close(ways)
	close(nodes)

	nodeWriter.Wait()
	relWriter.Wait()
	wayWriter.Wait()

	if genDb != nil {
		genDb.GeneralizeUpdates()
	}

	err = db.End()
	if err != nil {
		return err
	}
	err = db.Close()
	if err != nil {
		return err
	}

	log.StopStep(step)

	progress.Stop()

	if state != nil {
		if lastState != nil {
			state.Url = lastState.Url
		}
		err = diffstate.WriteLastState(config.BaseOptions.DiffDir, state)
		if err != nil {
			log.Warn(err) // warn only
		}
	}
	return nil
}