2012-12-26 17:07:30 +04:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2013-05-02 20:45:33 +04:00
|
|
|
"flag"
|
2013-05-16 14:17:21 +04:00
|
|
|
"fmt"
|
2013-04-08 23:45:13 +04:00
|
|
|
"goposm/cache"
|
2013-05-15 15:00:42 +04:00
|
|
|
"goposm/database"
|
|
|
|
_ "goposm/database/postgis"
|
2013-04-08 23:45:13 +04:00
|
|
|
"goposm/element"
|
2013-05-08 18:45:14 +04:00
|
|
|
"goposm/geom"
|
|
|
|
"goposm/geom/geos"
|
2013-05-14 12:04:11 +04:00
|
|
|
"goposm/mapping"
|
2013-02-12 22:45:49 +04:00
|
|
|
"goposm/parser"
|
2013-05-08 18:45:14 +04:00
|
|
|
"goposm/proj"
|
2013-05-06 13:03:52 +04:00
|
|
|
"goposm/stats"
|
2013-05-14 18:15:35 +04:00
|
|
|
"goposm/writer"
|
2013-04-16 23:14:19 +04:00
|
|
|
"log"
|
2013-05-02 22:37:31 +04:00
|
|
|
"os"
|
2013-04-08 23:45:13 +04:00
|
|
|
"runtime"
|
2013-05-02 22:37:31 +04:00
|
|
|
"runtime/pprof"
|
2013-05-10 13:22:17 +04:00
|
|
|
"strconv"
|
2013-05-13 12:21:12 +04:00
|
|
|
"strings"
|
2013-04-08 23:45:13 +04:00
|
|
|
"sync"
|
2013-05-13 12:21:12 +04:00
|
|
|
"time"
|
2012-12-26 17:07:30 +04:00
|
|
|
)
|
|
|
|
|
2013-05-07 13:42:05 +04:00
|
|
|
var skipCoords, skipNodes, skipWays bool
|
2013-05-10 13:22:17 +04:00
|
|
|
var dbImportBatchSize int64
|
2013-05-07 13:42:05 +04:00
|
|
|
|
|
|
|
func init() {
|
|
|
|
if os.Getenv("GOPOSM_SKIP_COORDS") != "" {
|
|
|
|
skipCoords = true
|
|
|
|
}
|
|
|
|
if os.Getenv("GOPOSM_SKIP_NODES") != "" {
|
|
|
|
skipNodes = true
|
|
|
|
}
|
|
|
|
if os.Getenv("GOPOSM_SKIP_WAYS") != "" {
|
|
|
|
skipWays = true
|
|
|
|
}
|
2013-05-10 13:22:17 +04:00
|
|
|
|
|
|
|
dbImportBatchSize, _ = strconv.ParseInt(
|
|
|
|
os.Getenv("GOPOSM_DBIMPORT_BATCHSIZE"), 10, 32)
|
|
|
|
|
|
|
|
if dbImportBatchSize == 0 {
|
|
|
|
dbImportBatchSize = 4096
|
|
|
|
}
|
2013-05-07 13:42:05 +04:00
|
|
|
}
|
|
|
|
|
2013-05-10 12:57:06 +04:00
|
|
|
type ErrorLevel interface {
|
|
|
|
Level() int
|
|
|
|
}
|
|
|
|
|
2013-05-14 12:04:11 +04:00
|
|
|
func parse(cache *cache.OSMCache, progress *stats.Statistics, tagmapping *mapping.Mapping, filename string) {
|
2013-04-11 21:50:20 +04:00
|
|
|
nodes := make(chan []element.Node)
|
2013-05-02 20:45:33 +04:00
|
|
|
coords := make(chan []element.Node)
|
2013-04-11 21:50:20 +04:00
|
|
|
ways := make(chan []element.Way)
|
2013-04-20 18:50:23 +04:00
|
|
|
relations := make(chan []element.Relation)
|
2013-04-08 23:45:13 +04:00
|
|
|
|
|
|
|
positions := parser.PBFBlockPositions(filename)
|
|
|
|
|
|
|
|
waitParser := sync.WaitGroup{}
|
2013-04-20 18:50:23 +04:00
|
|
|
for i := 0; i < runtime.NumCPU(); i++ {
|
2013-04-08 23:45:13 +04:00
|
|
|
waitParser.Add(1)
|
|
|
|
go func() {
|
|
|
|
for pos := range positions {
|
2013-05-05 22:14:39 +04:00
|
|
|
parser.ParseBlock(
|
|
|
|
pos,
|
|
|
|
coords,
|
|
|
|
nodes,
|
|
|
|
ways,
|
|
|
|
relations,
|
|
|
|
)
|
2013-04-08 23:45:13 +04:00
|
|
|
}
|
2013-05-05 22:14:39 +04:00
|
|
|
//runtime.GC()
|
2013-04-08 23:45:13 +04:00
|
|
|
waitParser.Done()
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
waitCounter := sync.WaitGroup{}
|
2013-05-04 18:27:05 +04:00
|
|
|
|
2013-04-20 18:50:23 +04:00
|
|
|
for i := 0; i < runtime.NumCPU(); i++ {
|
2013-04-11 21:50:20 +04:00
|
|
|
waitCounter.Add(1)
|
|
|
|
go func() {
|
2013-05-14 12:04:11 +04:00
|
|
|
m := tagmapping.WayTagFilter()
|
2013-04-11 21:50:20 +04:00
|
|
|
for ws := range ways {
|
2013-05-07 13:42:05 +04:00
|
|
|
if skipWays {
|
|
|
|
continue
|
|
|
|
}
|
2013-05-17 13:42:19 +04:00
|
|
|
for i, w := range ws {
|
|
|
|
ok := m.Filter(w.Tags)
|
|
|
|
if !ok {
|
|
|
|
ws[i].Tags = nil
|
|
|
|
}
|
2013-05-07 12:13:09 +04:00
|
|
|
}
|
2013-05-04 18:27:05 +04:00
|
|
|
cache.Ways.PutWays(ws)
|
2013-05-06 13:03:52 +04:00
|
|
|
progress.AddWays(len(ws))
|
2013-04-11 21:50:20 +04:00
|
|
|
}
|
|
|
|
waitCounter.Done()
|
|
|
|
}()
|
|
|
|
}
|
2013-04-20 18:50:23 +04:00
|
|
|
for i := 0; i < runtime.NumCPU(); i++ {
|
|
|
|
waitCounter.Add(1)
|
|
|
|
go func() {
|
2013-05-14 12:04:11 +04:00
|
|
|
m := tagmapping.RelationTagFilter()
|
2013-04-20 18:50:23 +04:00
|
|
|
for rels := range relations {
|
2013-05-17 13:42:19 +04:00
|
|
|
for i, r := range rels {
|
|
|
|
ok := m.Filter(r.Tags)
|
|
|
|
if !ok {
|
|
|
|
rels[i].Tags = nil
|
|
|
|
}
|
2013-05-07 12:13:09 +04:00
|
|
|
}
|
2013-05-04 18:27:05 +04:00
|
|
|
cache.Relations.PutRelations(rels)
|
2013-05-06 13:03:52 +04:00
|
|
|
progress.AddRelations(len(rels))
|
2013-04-20 18:50:23 +04:00
|
|
|
}
|
|
|
|
waitCounter.Done()
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
for i := 0; i < runtime.NumCPU(); i++ {
|
2013-04-08 23:45:13 +04:00
|
|
|
waitCounter.Add(1)
|
|
|
|
go func() {
|
2013-05-02 20:45:33 +04:00
|
|
|
for nds := range coords {
|
2013-05-07 13:42:05 +04:00
|
|
|
if skipCoords {
|
|
|
|
continue
|
|
|
|
}
|
2013-05-04 18:27:05 +04:00
|
|
|
cache.Coords.PutCoords(nds)
|
2013-05-06 13:03:52 +04:00
|
|
|
progress.AddCoords(len(nds))
|
2013-04-08 23:45:13 +04:00
|
|
|
}
|
2013-05-02 20:45:33 +04:00
|
|
|
waitCounter.Done()
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
for i := 0; i < 2; i++ {
|
|
|
|
waitCounter.Add(1)
|
|
|
|
go func() {
|
2013-05-14 12:04:11 +04:00
|
|
|
m := tagmapping.NodeTagFilter()
|
2013-05-02 20:45:33 +04:00
|
|
|
for nds := range nodes {
|
2013-05-07 13:42:05 +04:00
|
|
|
if skipNodes {
|
|
|
|
continue
|
|
|
|
}
|
2013-05-07 12:13:09 +04:00
|
|
|
for _, nd := range nds {
|
2013-05-13 15:58:44 +04:00
|
|
|
ok := m.Filter(nd.Tags)
|
2013-05-07 12:13:09 +04:00
|
|
|
if !ok {
|
|
|
|
nd.Tags = nil
|
|
|
|
}
|
|
|
|
}
|
2013-05-04 18:27:05 +04:00
|
|
|
n, _ := cache.Nodes.PutNodes(nds)
|
2013-05-06 13:03:52 +04:00
|
|
|
progress.AddNodes(n)
|
2013-05-02 20:45:33 +04:00
|
|
|
}
|
2013-04-08 23:45:13 +04:00
|
|
|
waitCounter.Done()
|
|
|
|
}()
|
|
|
|
}
|
2013-05-02 20:45:33 +04:00
|
|
|
|
2013-04-08 23:45:13 +04:00
|
|
|
waitParser.Wait()
|
2013-05-02 20:45:33 +04:00
|
|
|
close(coords)
|
2013-04-08 23:45:13 +04:00
|
|
|
close(nodes)
|
|
|
|
close(ways)
|
|
|
|
close(relations)
|
|
|
|
waitCounter.Wait()
|
|
|
|
}
|
|
|
|
|
2013-05-06 13:10:37 +04:00
|
|
|
var (
|
2013-05-06 14:51:30 +04:00
|
|
|
cpuprofile = flag.String("cpuprofile", "", "filename of cpu profile output")
|
2013-05-13 12:21:12 +04:00
|
|
|
memprofile = flag.String("memprofile", "", "dir name of mem profile output and interval (fname:interval)")
|
2013-05-06 14:51:30 +04:00
|
|
|
cachedir = flag.String("cachedir", "/tmp/goposm", "cache directory")
|
|
|
|
overwritecache = flag.Bool("overwritecache", false, "overwritecache")
|
|
|
|
appendcache = flag.Bool("appendcache", false, "append cache")
|
|
|
|
read = flag.String("read", "", "read")
|
|
|
|
write = flag.Bool("write", false, "write")
|
2013-05-10 12:09:52 +04:00
|
|
|
connection = flag.String("connection", "", "connection parameters")
|
2013-05-10 13:21:00 +04:00
|
|
|
diff = flag.Bool("diff", false, "enable diff support")
|
2013-05-13 15:58:44 +04:00
|
|
|
mappingFile = flag.String("mapping", "", "mapping file")
|
2013-05-06 13:10:37 +04:00
|
|
|
)
|
|
|
|
|
2012-12-26 17:07:30 +04:00
|
|
|
func main() {
|
2013-05-06 16:20:00 +04:00
|
|
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
2013-05-06 13:10:37 +04:00
|
|
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
if *cpuprofile != "" {
|
|
|
|
f, err := os.Create(*cpuprofile)
|
2013-05-05 22:14:39 +04:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
pprof.StartCPUProfile(f)
|
|
|
|
defer pprof.StopCPUProfile()
|
2013-05-02 22:37:31 +04:00
|
|
|
}
|
2013-05-05 22:14:39 +04:00
|
|
|
|
2013-05-13 12:21:12 +04:00
|
|
|
if *memprofile != "" {
|
|
|
|
parts := strings.Split(*memprofile, string(os.PathListSeparator))
|
|
|
|
var interval time.Duration
|
|
|
|
|
|
|
|
if len(parts) < 2 {
|
|
|
|
interval, _ = time.ParseDuration("1m")
|
|
|
|
} else {
|
|
|
|
var err error
|
|
|
|
interval, err = time.ParseDuration(parts[1])
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
go stats.MemProfiler(parts[0], interval)
|
|
|
|
}
|
|
|
|
|
2013-05-06 14:51:30 +04:00
|
|
|
osmCache := cache.NewOSMCache(*cachedir)
|
|
|
|
|
|
|
|
if *read != "" && osmCache.Exists() {
|
|
|
|
if *overwritecache {
|
|
|
|
log.Println("removing existing cache", *cachedir)
|
|
|
|
err := osmCache.Remove()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("unable to remove cache:", err)
|
|
|
|
}
|
|
|
|
} else if !*appendcache {
|
|
|
|
log.Fatal("cache already exists use -appendcache or -overwritecache")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err := osmCache.Open()
|
2013-05-02 22:37:31 +04:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2013-05-05 22:14:39 +04:00
|
|
|
defer osmCache.Close()
|
2013-05-04 18:27:05 +04:00
|
|
|
|
2013-05-06 13:03:52 +04:00
|
|
|
progress := stats.StatsReporter()
|
|
|
|
|
2013-05-14 12:04:11 +04:00
|
|
|
tagmapping, err := mapping.NewMapping(*mappingFile)
|
2013-05-13 15:58:44 +04:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2013-05-06 14:51:30 +04:00
|
|
|
if *read != "" {
|
2013-05-13 10:08:52 +04:00
|
|
|
osmCache.Coords.SetLinearImport(true)
|
2013-05-14 12:04:11 +04:00
|
|
|
parse(osmCache, progress, tagmapping, *read)
|
2013-05-13 10:08:52 +04:00
|
|
|
osmCache.Coords.SetLinearImport(false)
|
2013-05-10 15:55:14 +04:00
|
|
|
progress.Reset()
|
2013-05-14 11:26:28 +04:00
|
|
|
osmCache.Coords.Flush()
|
2013-05-06 14:51:30 +04:00
|
|
|
}
|
2013-05-02 22:37:31 +04:00
|
|
|
|
2013-05-06 14:51:30 +04:00
|
|
|
if *write {
|
2013-05-06 16:20:00 +04:00
|
|
|
progress.Reset()
|
|
|
|
|
|
|
|
diffCache := cache.NewDiffCache(*cachedir)
|
|
|
|
if err = diffCache.Remove(); err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
if err = diffCache.Open(); err != nil {
|
2013-05-06 14:51:30 +04:00
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2013-05-06 12:21:03 +04:00
|
|
|
|
2013-05-06 14:51:30 +04:00
|
|
|
waitFill := sync.WaitGroup{}
|
2013-05-08 18:45:14 +04:00
|
|
|
wayChan := make(chan []element.Way)
|
|
|
|
waitDb := &sync.WaitGroup{}
|
2013-05-15 15:00:42 +04:00
|
|
|
conf := database.Config{
|
|
|
|
Type: "postgis",
|
2013-05-13 12:55:08 +04:00
|
|
|
ConnectionParams: *connection,
|
|
|
|
Srid: 3857,
|
|
|
|
}
|
2013-05-15 15:00:42 +04:00
|
|
|
pg, err := database.Open(conf)
|
2013-05-08 18:45:14 +04:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2013-05-14 18:15:35 +04:00
|
|
|
|
|
|
|
err = pg.Init(tagmapping)
|
2013-05-10 12:26:13 +04:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2013-05-14 18:15:35 +04:00
|
|
|
writeDBChan := make(chan writer.InsertBatch)
|
|
|
|
writeChan := make(chan writer.InsertElement)
|
|
|
|
waitBuffer := sync.WaitGroup{}
|
|
|
|
|
2013-05-06 14:51:30 +04:00
|
|
|
for i := 0; i < runtime.NumCPU(); i++ {
|
2013-05-08 18:45:14 +04:00
|
|
|
waitDb.Add(1)
|
|
|
|
go func() {
|
2013-05-14 18:15:35 +04:00
|
|
|
writer.DBWriter(pg, writeDBChan)
|
2013-05-08 18:45:14 +04:00
|
|
|
waitDb.Done()
|
|
|
|
}()
|
|
|
|
}
|
2013-05-06 12:21:03 +04:00
|
|
|
|
2013-05-14 18:15:35 +04:00
|
|
|
waitBuffer.Add(1)
|
|
|
|
go func() {
|
|
|
|
writer.BufferInsertElements(writeChan, writeDBChan)
|
|
|
|
waitBuffer.Done()
|
|
|
|
}()
|
|
|
|
|
2013-05-17 13:42:19 +04:00
|
|
|
rel := osmCache.Relations.Iter()
|
|
|
|
polygons := tagmapping.PolygonMatcher()
|
|
|
|
|
|
|
|
for r := range rel {
|
|
|
|
progress.AddRelations(1)
|
|
|
|
err := osmCache.Ways.FillMembers(r.Members)
|
|
|
|
if err == cache.NotFound {
|
|
|
|
fmt.Println("missing ways for relation", r.Id)
|
|
|
|
} else if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
for _, m := range r.Members {
|
|
|
|
if m.Way == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
err := osmCache.Coords.FillWay(m.Way)
|
|
|
|
if err == cache.NotFound {
|
|
|
|
fmt.Println("missing nodes for way", m.Way.Id, "in relation", r.Id)
|
|
|
|
} else if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err = geom.BuildRelation(r)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if matches := polygons.Match(r.OSMElem); len(matches) > 0 {
|
|
|
|
for _, match := range matches {
|
|
|
|
row := match.Row(&r.OSMElem)
|
|
|
|
writeChan <- writer.InsertElement{match.Table, row}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// way := osmCache.Ways.Iter()
|
|
|
|
way := make(chan *element.Way)
|
|
|
|
close(way)
|
2013-05-08 18:45:14 +04:00
|
|
|
for i := 0; i < runtime.NumCPU(); i++ {
|
|
|
|
waitFill.Add(1)
|
2013-05-06 14:51:30 +04:00
|
|
|
go func() {
|
2013-05-14 18:15:35 +04:00
|
|
|
lineStrings := tagmapping.LineStringMatcher()
|
|
|
|
polygons := tagmapping.PolygonMatcher()
|
2013-05-08 18:45:14 +04:00
|
|
|
geos := geos.NewGEOS()
|
|
|
|
defer geos.Finish()
|
|
|
|
|
2013-05-06 14:51:30 +04:00
|
|
|
for w := range way {
|
2013-05-06 16:20:00 +04:00
|
|
|
progress.AddWays(1)
|
2013-05-16 17:48:22 +04:00
|
|
|
err := osmCache.Coords.FillWay(w)
|
|
|
|
if err != nil {
|
2013-05-06 14:51:30 +04:00
|
|
|
continue
|
|
|
|
}
|
2013-05-08 18:45:14 +04:00
|
|
|
proj.NodesToMerc(w.Nodes)
|
2013-05-14 18:15:35 +04:00
|
|
|
if matches := lineStrings.Match(w.OSMElem); len(matches) > 0 {
|
2013-05-15 15:25:29 +04:00
|
|
|
// make copy to avoid interference with polygon matches
|
|
|
|
way := element.Way(*w)
|
|
|
|
way.Geom, err = geom.LineStringWKB(geos, way.Nodes)
|
2013-05-13 17:19:39 +04:00
|
|
|
if err != nil {
|
|
|
|
if err, ok := err.(ErrorLevel); ok {
|
|
|
|
if err.Level() <= 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
log.Println(err)
|
|
|
|
continue
|
|
|
|
}
|
2013-05-14 18:15:35 +04:00
|
|
|
for _, match := range matches {
|
|
|
|
row := match.Row(&way.OSMElem)
|
|
|
|
writeChan <- writer.InsertElement{match.Table, row}
|
|
|
|
}
|
|
|
|
|
2013-05-13 17:19:39 +04:00
|
|
|
}
|
|
|
|
if w.IsClosed() {
|
2013-05-14 18:15:35 +04:00
|
|
|
if matches := polygons.Match(w.OSMElem); len(matches) > 0 {
|
2013-05-15 15:25:29 +04:00
|
|
|
way := element.Way(*w)
|
|
|
|
way.Geom, err = geom.PolygonWKB(geos, way.Nodes)
|
2013-05-13 17:19:39 +04:00
|
|
|
if err != nil {
|
|
|
|
if err, ok := err.(ErrorLevel); ok {
|
|
|
|
if err.Level() <= 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
log.Println(err)
|
2013-05-10 12:57:06 +04:00
|
|
|
continue
|
|
|
|
}
|
2013-05-14 18:15:35 +04:00
|
|
|
for _, match := range matches {
|
|
|
|
row := match.Row(&way.OSMElem)
|
|
|
|
writeChan <- writer.InsertElement{match.Table, row}
|
|
|
|
}
|
2013-05-10 12:57:06 +04:00
|
|
|
}
|
2013-05-08 18:45:14 +04:00
|
|
|
}
|
|
|
|
|
2013-05-10 13:21:00 +04:00
|
|
|
if *diff {
|
2013-05-13 11:54:00 +04:00
|
|
|
diffCache.Coords.AddFromWay(w)
|
2013-05-06 12:21:03 +04:00
|
|
|
}
|
|
|
|
}
|
2013-05-06 14:51:30 +04:00
|
|
|
waitFill.Done()
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
waitFill.Wait()
|
2013-05-08 18:45:14 +04:00
|
|
|
close(wayChan)
|
2013-05-15 15:21:31 +04:00
|
|
|
diffCache.Coords.Close()
|
|
|
|
|
|
|
|
nodes := osmCache.Nodes.Iter()
|
|
|
|
points := tagmapping.PointMatcher()
|
|
|
|
geos := geos.NewGEOS()
|
|
|
|
defer geos.Finish()
|
|
|
|
for n := range nodes {
|
|
|
|
progress.AddNodes(1)
|
|
|
|
if matches := points.Match(n.OSMElem); len(matches) > 0 {
|
|
|
|
proj.NodeToMerc(n)
|
2013-05-15 15:25:29 +04:00
|
|
|
n.Geom, err = geom.PointWKB(geos, *n)
|
2013-05-15 15:21:31 +04:00
|
|
|
if err != nil {
|
|
|
|
if err, ok := err.(ErrorLevel); ok {
|
|
|
|
if err.Level() <= 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
log.Println(err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
for _, match := range matches {
|
2013-05-15 15:25:29 +04:00
|
|
|
row := match.Row(&n.OSMElem)
|
2013-05-15 15:21:31 +04:00
|
|
|
writeChan <- writer.InsertElement{match.Table, row}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
// fmt.Println(r)
|
|
|
|
}
|
2013-05-14 18:15:35 +04:00
|
|
|
close(writeChan)
|
|
|
|
waitBuffer.Wait()
|
|
|
|
close(writeDBChan)
|
2013-05-08 18:45:14 +04:00
|
|
|
waitDb.Wait()
|
2013-05-15 15:21:31 +04:00
|
|
|
|
2013-05-02 22:37:31 +04:00
|
|
|
}
|
2013-05-10 15:55:14 +04:00
|
|
|
progress.Stop()
|
2013-05-06 14:51:30 +04:00
|
|
|
|
2013-04-08 23:45:13 +04:00
|
|
|
//parser.PBFStats(os.Args[1])
|
2012-12-26 17:07:30 +04:00
|
|
|
}
|