mirror of
https://bitbucket.org/s_l_teichmann/mtsatellite
synced 2025-01-14 18:40:18 +01:00
Added some spatial query for plain sql backend.
This commit is contained in:
parent
caf2cbbcfe
commit
0021854000
@ -37,6 +37,34 @@ func (c Coord) Equals(o Coord) bool {
|
|||||||
return c.X == o.X && c.Y == o.Y && c.Z == o.Z
|
return c.X == o.X && c.Y == o.Y && c.Z == o.Z
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func minComponent(a, b int16) int16 {
|
||||||
|
if a < b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func maxComponent(a, b int16) int16 {
|
||||||
|
if a > b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func MinCoord(a, b Coord) Coord {
|
||||||
|
return Coord{
|
||||||
|
X: minComponent(a.X, b.X),
|
||||||
|
Y: minComponent(a.Y, b.Y),
|
||||||
|
Z: minComponent(a.Z, b.Z)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MaxCoord(a, b Coord) Coord {
|
||||||
|
return Coord{
|
||||||
|
X: maxComponent(a.X, b.X),
|
||||||
|
Y: maxComponent(a.Y, b.Y),
|
||||||
|
Z: maxComponent(a.Z, b.Z)}
|
||||||
|
}
|
||||||
|
|
||||||
// Constructs a database key out of byte slice.
|
// Constructs a database key out of byte slice.
|
||||||
func DecodeStringFromBytes(key []byte) (pos int64, err error) {
|
func DecodeStringFromBytes(key []byte) (pos int64, err error) {
|
||||||
return strconv.ParseInt(string(key), 10, 64)
|
return strconv.ParseInt(string(key), 10, 64)
|
||||||
|
93
sqlite.go
93
sqlite.go
@ -23,6 +23,7 @@ const (
|
|||||||
insertSql = "INSERT INTO blocks (pos, data) VALUES (?, ?)"
|
insertSql = "INSERT INTO blocks (pos, data) VALUES (?, ?)"
|
||||||
countSql = "SELECT count(*) FROM blocks"
|
countSql = "SELECT count(*) FROM blocks"
|
||||||
keysSql = "SELECT pos FROM blocks"
|
keysSql = "SELECT pos FROM blocks"
|
||||||
|
rangeSql = "SELECT pos, data FROM blocks WHERE pos BETWEEN ? AND ?"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SqliteBackend struct {
|
type SqliteBackend struct {
|
||||||
@ -36,6 +37,7 @@ type SqliteBackend struct {
|
|||||||
updateStmt *sql.Stmt
|
updateStmt *sql.Stmt
|
||||||
countStmt *sql.Stmt
|
countStmt *sql.Stmt
|
||||||
keysStmt *sql.Stmt
|
keysStmt *sql.Stmt
|
||||||
|
rangeStmt *sql.Stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
type SqliteSession struct {
|
type SqliteSession struct {
|
||||||
@ -94,6 +96,11 @@ func NewSqliteBackend(path string, interleaved bool) (sqlb *SqliteBackend, err e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if res.rangeStmt, err = res.db.Prepare(rangeSql); err != nil {
|
||||||
|
res.closeAll()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if interleaved {
|
if interleaved {
|
||||||
res.encoder = common.EncodeStringToBytesFromInterleaved
|
res.encoder = common.EncodeStringToBytesFromInterleaved
|
||||||
res.decoder = common.DecodeStringFromBytesToInterleaved
|
res.decoder = common.DecodeStringFromBytesToInterleaved
|
||||||
@ -131,6 +138,7 @@ func (sqlb *SqliteBackend) closeAll() error {
|
|||||||
closeStmt(&sqlb.existsStmt)
|
closeStmt(&sqlb.existsStmt)
|
||||||
closeStmt(&sqlb.countStmt)
|
closeStmt(&sqlb.countStmt)
|
||||||
closeStmt(&sqlb.keysStmt)
|
closeStmt(&sqlb.keysStmt)
|
||||||
|
closeStmt(&sqlb.rangeStmt)
|
||||||
return closeDB(&sqlb.db)
|
return closeDB(&sqlb.db)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,6 +284,89 @@ func (ss *SqliteSession) AllKeys(hash []byte, done chan struct{}) (keys chan []b
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ss *SqliteSession) SpatialQuery(hash, first, second []byte, done chan struct{}) (blocks chan Block, err error) {
|
func (ss *SqliteSession) SpatialQuery(hash, first, second []byte, done chan struct{}) (blocks chan Block, err error) {
|
||||||
err = ErrNotImplemented
|
|
||||||
|
// No implementation for the interleaved case, yet.
|
||||||
|
if ss.backend.interleaved {
|
||||||
|
err = ErrNotImplemented
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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) 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)
|
||||||
|
|
||||||
|
globalLock.RLock()
|
||||||
|
|
||||||
|
blocks = make(chan Block)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer globalLock.RUnlock()
|
||||||
|
defer close(blocks)
|
||||||
|
rangeStmt := ss.txStmt(ss.backend.rangeStmt)
|
||||||
|
|
||||||
|
a, b := common.Coord{X: c1.X}, common.Coord{X: c2.X}
|
||||||
|
|
||||||
|
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
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
rows *sql.Rows
|
||||||
|
)
|
||||||
|
// Ordering should not be necessary.
|
||||||
|
from, to := order(common.CoordToPlain(a), common.CoordToPlain(b))
|
||||||
|
if rows, err = rangeStmt.Query(from, to); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for rows.Next() {
|
||||||
|
var key int64
|
||||||
|
var data []byte
|
||||||
|
if err = rows.Scan(&key, &data); err != nil {
|
||||||
|
log.Printf("Error in range query: %s", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
var encodedKey []byte
|
||||||
|
if encodedKey, err = common.EncodeStringToBytes(key); err != nil {
|
||||||
|
log.Printf("Key encoding failed: %s", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case blocks <- Block{Key: encodedKey, Data: data}:
|
||||||
|
case <-done:
|
||||||
|
rows.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
log.Printf("Error in range query: %s", err)
|
||||||
|
}
|
||||||
|
rows.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user