changeset 2465:86c7a023400e octree-diff

Started experimental octree diff branch.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 25 Feb 2019 17:02:33 +0100
parents 123e7f43b676
children a1e751c08c56
files cmd/octreediff/db.go cmd/octreediff/main.go pkg/octree/cache.go pkg/octree/loader.go
diffstat 4 files changed, 203 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/octreediff/db.go	Mon Feb 25 17:02:33 2019 +0100
@@ -0,0 +1,52 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2018 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+package main
+
+import (
+	"database/sql"
+	"flag"
+
+	"github.com/jackc/pgx"
+	"github.com/jackc/pgx/stdlib"
+)
+
+var (
+	dbhost     = flag.String("dbhost", "localhost", "database host")
+	dbport     = flag.Uint("dbport", 5432, "database port")
+	dbname     = flag.String("dbname", "gemma", "database user")
+	dbuser     = flag.String("dbuser", "scott", "database user")
+	dbpassword = flag.String("dbpw", "tiger", "database password")
+	dbssl      = flag.String("dbssl", "prefer", "database SSL mode")
+)
+
+func run(fn func(*sql.DB) error) error {
+
+	// To ease SSL config ride a bit on parsing.
+	cc, err := pgx.ParseConnectionString("sslmode=" + *dbssl)
+	if err != nil {
+		return err
+	}
+
+	// Do the rest manually to allow whitespace in user/password.
+	cc.Host = *dbhost
+	cc.Port = uint16(*dbport)
+	cc.User = *dbuser
+	cc.Password = *dbpassword
+	cc.Database = *dbname
+
+	db := stdlib.OpenDB(cc)
+	defer db.Close()
+
+	return fn(db)
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/octreediff/main.go	Mon Feb 25 17:02:33 2019 +0100
@@ -0,0 +1,149 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2018 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+package main
+
+import (
+	"context"
+	"database/sql"
+	"flag"
+	"fmt"
+	"log"
+	"runtime"
+	"sync"
+	"time"
+
+	"gemma.intevation.de/gemma/pkg/common"
+	"gemma.intevation.de/gemma/pkg/octree"
+)
+
+var (
+	bottleneck = flag.String("bottleneck", "", "name of the bottleneck")
+	first      = flag.String("first", "", "date of the first sounding result")
+	second     = flag.String("second", "", "date of the second sounding result")
+)
+
+const (
+	loadOctreeSQL = `
+SELECT sr.octree_index
+FROM waterway.sounding_results sr JOIN waterway.bottlenecks bn
+  ON sr.bottleneck_id = bn.id
+WHERE bn.bottleneck_id = $1 AND sr.date_info = $2::date
+  AND sr.octree_index IS NOT NULL`
+)
+
+func check(err error) {
+	if err != nil {
+		log.Fatalf("error: %v\n", err)
+	}
+}
+
+func process(bottleneck string, firstDate, secondDate time.Time) error {
+	start := time.Now()
+	defer func() { log.Printf("processing took %v\n", time.Since(start)) }()
+
+	ctx := context.Background()
+
+	return run(func(db *sql.DB) error {
+
+		conn, err := db.Conn(ctx)
+		if err != nil {
+			return err
+		}
+		defer conn.Close()
+
+		type load struct {
+			date time.Time
+			data []byte
+			err  *error
+			dst  **octree.Tree
+		}
+
+		out := make(chan *load)
+		wg := new(sync.WaitGroup)
+
+		n := runtime.NumCPU()
+		if n > 2 {
+			n = 2
+		}
+
+		for i := 0; i < n; i++ {
+			wg.Add(1)
+			go func() {
+				defer wg.Done()
+				for l := range out {
+					if *l.err == nil {
+						*l.dst, *l.err = octree.Deserialize(l.data)
+					}
+				}
+			}()
+		}
+
+		var firstErr, secondErr error
+		var first, second *octree.Tree
+
+		for _, l := range []*load{
+			{date: firstDate, dst: &first, err: &firstErr},
+			{date: secondDate, dst: &second, err: &secondErr},
+		} {
+			var data []byte
+			if err := conn.QueryRowContext(
+				ctx,
+				loadOctreeSQL,
+				bottleneck,
+				l.date,
+			).Scan(&data); err != nil {
+				*l.err = err
+			} else {
+				l.data = data
+			}
+			out <- l
+		}
+		close(out)
+
+		wg.Wait()
+
+		if firstErr != nil || secondErr != nil {
+			if firstErr != nil && secondErr != nil {
+				return fmt.Errorf("%v, %v", firstErr, secondErr)
+			}
+			if firstErr != nil {
+				return firstErr
+			}
+			return secondErr
+		}
+
+		log.Printf("loading took %v\n", time.Since(start))
+
+		// TODO: Do the diff.
+		_, _ = first, second
+
+		return nil
+	})
+}
+
+func main() {
+
+	flag.Parse()
+
+	firstDate, err := time.Parse(common.DateFormat, *first)
+	check(err)
+	secondDate, err := time.Parse(common.DateFormat, *second)
+	check(err)
+
+	if *bottleneck == "" {
+		log.Fatalln("Missing bottleneck name")
+	}
+
+	check(process(*bottleneck, firstDate, secondDate))
+}
--- a/pkg/octree/cache.go	Mon Feb 25 16:16:33 2019 +0100
+++ b/pkg/octree/cache.go	Mon Feb 25 17:02:33 2019 +0100
@@ -139,7 +139,7 @@
 		}
 	}
 
-	tree, err := deserialize(data)
+	tree, err := Deserialize(data)
 	if err != nil {
 		return nil, err
 	}
--- a/pkg/octree/loader.go	Mon Feb 25 16:16:33 2019 +0100
+++ b/pkg/octree/loader.go	Mon Feb 25 17:02:33 2019 +0100
@@ -111,7 +111,7 @@
 	return tree, nil
 }
 
-func deserialize(data []byte) (*Tree, error) {
+func Deserialize(data []byte) (*Tree, error) {
 	return loadReader(
 		bufio.NewReader(
 			snappy.NewReader(