From caf2cbbcfed75a4682df6ef22c55b6ef506ba34f Mon Sep 17 00:00:00 2001 From: "Sascha L. Teichmann" Date: Mon, 1 Sep 2014 00:19:47 +0200 Subject: [PATCH] Introduced non standard HSPATIAL hash first second which performs a spatial query between coords first and second. TODO: Implement in backends. Write documentation. --- backend.go | 10 ++++++++++ connection.go | 37 +++++++++++++++++++++++++++++++------ leveldb.go | 5 +++++ parser.go | 16 ++++++++++++++++ sqlite.go | 5 +++++ 5 files changed, 67 insertions(+), 6 deletions(-) diff --git a/backend.go b/backend.go index 0f4f2e2..ac4e507 100644 --- a/backend.go +++ b/backend.go @@ -4,12 +4,22 @@ package main +import "errors" + +var ErrNotImplemented = errors.New("Not implemented") + type ( + Block struct { + Key []byte + Data []byte + } + Session interface { Fetch(hash, key []byte) ([]byte, error) InTransaction() bool Store(hash, key, value []byte) (bool, error) AllKeys(hash []byte, done chan struct{}) (chan []byte, int, error) + SpatialQuery(hash, first, second []byte, done chan struct{}) (chan Block, error) BeginTransaction() error CommitTransaction() error Close() error diff --git a/connection.go b/connection.go index accb9b4..b834030 100644 --- a/connection.go +++ b/connection.go @@ -112,10 +112,6 @@ func (c *Connection) Hkeys(hash []byte) bool { return c.writeError(err) } - if err != nil { - return c.writeError(err) - } - if n == 0 { return c.writeEmptyArray() } @@ -126,15 +122,44 @@ func (c *Connection) Hkeys(hash []byte) bool { } for key := range keys { - if err := c.writeBulkString(key); err != nil { + if err = c.writeBulkString(key); err != nil { logError(err) - close(keys) return false } } return true } +func (c *Connection) HSpatial(hash, first, second []byte) bool { + var ( + err error + blocks chan Block + done = make(chan struct{}) + ) + defer close(done) + + if blocks, err = c.session.SpatialQuery(hash, first, second, done); err != nil { + return c.writeError(err) + } + + for block := range blocks { + if err = c.writeBulkString(block.Key); err != nil { + logError(err) + return false + } + if err = c.writeBulkString(block.Data); err != nil { + logError(err) + return false + } + } + + if err = c.writeBulkString(nil); err != nil { + logError(err) + return false + } + return true +} + func (c *Connection) writeError(err error) bool { logError(err) if _, err = c.conn.Write(redisError); err != nil { diff --git a/leveldb.go b/leveldb.go index 47fa8b1..7143386 100644 --- a/leveldb.go +++ b/leveldb.go @@ -222,3 +222,8 @@ 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) { + err = ErrNotImplemented + return +} diff --git a/parser.go b/parser.go index 45921ca..1bb9e74 100644 --- a/parser.go +++ b/parser.go @@ -127,6 +127,7 @@ type RedisCommands interface { Multi() bool Exec() bool Hkeys(hash []byte) bool + HSpatial(hash, first, second []byte) bool } type RedisCommandExecutor struct { @@ -217,6 +218,21 @@ func (rce *RedisCommandExecutor) execute() bool { return false } return rce.commands.Hkeys(hash) + + case "HSPATIAL": + if l < 4 { + log.Println("WARN: Missing argments for HSPATIAL.") + return false + } + hash, ok1 := rce.args[1].([]byte) + first, ok2 := rce.args[2].([]byte) + second, ok3 := rce.args[3].([]byte) + + if !ok1 || !ok2 || !ok3 { + log.Println("WARN: HSET data are not byte slices.") + return false + } + return rce.commands.HSpatial(hash, first, second) } log.Printf("WARN: unknown command: '%s'\n", cmd) return false diff --git a/sqlite.go b/sqlite.go index d27bc0a..1dd7f97 100644 --- a/sqlite.go +++ b/sqlite.go @@ -274,3 +274,8 @@ func (ss *SqliteSession) AllKeys(hash []byte, done chan struct{}) (keys chan []b return } + +func (ss *SqliteSession) SpatialQuery(hash, first, second []byte, done chan struct{}) (blocks chan Block, err error) { + err = ErrNotImplemented + return +}