From bebe776e54d8bdf55c61ed12bb519583efe03551 Mon Sep 17 00:00:00 2001 From: "Sascha L. Teichmann" Date: Mon, 1 Sep 2014 16:12:24 +0200 Subject: [PATCH] Added plain spatial query for LevelDB backend. --- leveldb.go | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++- misc.go | 12 ++++++++ sqlite.go | 7 ----- 3 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 misc.go diff --git a/leveldb.go b/leveldb.go index 7143386..e997bce 100644 --- a/leveldb.go +++ b/leveldb.go @@ -223,7 +223,85 @@ func (ldbs *LevelDBSession) AllKeys(hash []byte, done chan struct{}) (keys chan return } -func (ldbs *LevelDBSession) SpatialQuery(hash, first, second []byte, done chan struct{}) (blocks chan Block, err error) { +func (ldbs *LevelDBSession) SpatialQuery(hash, first, second []byte, done chan struct{}) (chan Block, error) { + if ldbs.backend.interleaved { + return ldbs.interleavedSpatialQuery(first, second, done) + } + return ldbs.plainSpatialQuery(first, second, done) +} + +func (ldbs *LevelDBSession) plainSpatialQuery(first, second []byte, done chan struct{}) (blocks chan Block, err error) { + + var ( + firstKey int64 + secondKey int64 + ) + if firstKey, err = common.DecodeStringFromBytes(first); err != nil { + return + } + if secondKey, err = common.DecodeStringFromBytes(second); err != nil { + return + } + c1 := common.PlainToCoord(firstKey) + c2 := common.PlainToCoord(secondKey) + c1, c2 = common.MinCoord(c1, c2), common.MaxCoord(c1, c2) + + blocks = make(chan Block) + + go func() { + defer close(blocks) + ldbs.backend.mutex.RLock() + defer ldbs.backend.mutex.RUnlock() + + ro := leveldb.NewReadOptions() + defer ro.Close() + ro.SetFillCache(false) + + it := ldbs.backend.db.NewIterator(ro) + defer it.Close() + + a, b := common.Coord{X: c1.X}, common.Coord{X: c2.X} + + var err error + + for a.Z = c1.Z; a.Z <= c2.Z; a.Z++ { + b.Z = a.Z + for a.Y = c1.Y; a.Y <= c2.Y; a.Y++ { + b.Y = a.Y + from, to := order(common.CoordToPlain(a), common.CoordToPlain(b)) + var encodedFrom []byte + if encodedFrom, err = common.EncodeStringToBytes(from); err != nil { + log.Printf("encoding key failed: %s", err) + return + } + it.Seek(encodedFrom) + for it.Valid() { + key := it.Key() + var decodedKey int64 + if decodedKey, err = common.DecodeStringFromBytes(key); err != nil { + log.Printf("decoding key failed: %s", err) + return + } + if decodedKey > to { + break + } + select { + case blocks <- Block{Key: key, Data: it.Value()}: + case <-done: + return + } + } + if err = it.GetError(); err != nil { + log.Printf("iterating failed: %s", err) + return + } + } + } + }() + return +} + +func (ldbs *LevelDBSession) interleavedSpatialQuery(first, second []byte, done chan struct{}) (blocks chan Block, err error) { err = ErrNotImplemented return } diff --git a/misc.go b/misc.go new file mode 100644 index 0000000..6c7b32c --- /dev/null +++ b/misc.go @@ -0,0 +1,12 @@ +// Copyright 2014 by Sascha L. Teichmann +// Use of this source code is governed by the MIT license +// that can be found in the LICENSE file. + +package main + +func order(a, b int64) (int64, int64) { + if a < b { + return a, b + } + return b, a +} diff --git a/sqlite.go b/sqlite.go index 38dbb05..3ce7c90 100644 --- a/sqlite.go +++ b/sqlite.go @@ -292,13 +292,6 @@ func (ss *SqliteSession) SpatialQuery(hash, first, second []byte, done chan stru return ss.plainSpatialQuery(first, second, done) } -func order(a, b int64) (int64, int64) { - if a < b { - return a, b - } - return b, a -} - func (ss *SqliteSession) interleavedSpatialQuery(first, second []byte, done chan struct{}) (blocks chan Block, err error) { var ( firstKey int64