Added experimental support for HKEYS to make minetestmapper happy.

This commit is contained in:
Sascha L. Teichmann 2014-08-11 14:56:01 +02:00
parent 720a6f497c
commit d321d1888b
5 changed files with 133 additions and 0 deletions

View File

@ -8,6 +8,7 @@ type Session interface {
Fetch(hash, key []byte) ([]byte, error) Fetch(hash, key []byte) ([]byte, error)
InTransaction() bool InTransaction() bool
Store(hash, key, value []byte) (bool, error) Store(hash, key, value []byte) (bool, error)
AllKeys(hash []byte) (chan []byte, int, error)
BeginTransaction() error BeginTransaction() error
CommitTransaction() error CommitTransaction() error
Close() error Close() error

View File

@ -99,6 +99,37 @@ func (c *Connection) Exec() bool {
return c.writeBoolArray(arr) return c.writeBoolArray(arr)
} }
func (c *Connection) Hkeys(hash []byte) bool {
var err error
var n int
var keys chan []byte
if keys, n, err = c.session.AllKeys(hash); err != nil {
return c.writeError(err)
}
if err != nil {
return c.writeError(err)
}
if n == 0 {
return c.writeEmptyArray()
}
if _, err := c.conn.Write([]byte(fmt.Sprintf("*%d\r\n", n))); err != nil {
logError(err)
return false
}
for key := range keys {
if err := c.writeBulkString(key); err != nil {
logError(err)
close(keys)
return false
}
}
return true
}
func (c *Connection) writeError(err error) bool { func (c *Connection) writeError(err error) bool {
logError(err) logError(err)
if _, err = c.conn.Write(redisError); err != nil { if _, err = c.conn.Write(redisError); err != nil {

View File

@ -150,3 +150,41 @@ func (ldbs *LevelDBSession) CommitTransaction() (err error) {
}) })
return return
} }
func (ldbs *LevelDBSession) AllKeys(hash []byte) (keys chan []byte, n int, err error) {
ldbs.backend.mutex.RLock()
ro := leveldb.NewReadOptions()
ro.SetFillCache(false)
it := ldbs.backend.db.NewIterator(ro)
for ; it.Valid(); it.Next() {
n++
}
if err = it.GetError(); err != nil {
ro.Close()
it.Close()
ldbs.backend.mutex.RUnlock()
return
}
it.Close()
keys = make(chan []byte)
go func() {
ldbs.backend.mutex.RUnlock()
defer ro.Close()
defer close(keys)
it := ldbs.backend.db.NewIterator(ro)
defer it.Close()
for ; it.Valid(); it.Next() {
keys <- it.Key()
}
if err := it.GetError(); err != nil {
log.Printf("WARN: %s\n", err)
}
}()
return
}

View File

@ -126,6 +126,7 @@ type RedisCommands interface {
Hset(hash, key, block []byte) bool Hset(hash, key, block []byte) bool
Multi() bool Multi() bool
Exec() bool Exec() bool
Hkeys(hash []byte) bool
} }
type RedisCommandExecutor struct { type RedisCommandExecutor struct {
@ -204,6 +205,18 @@ func (rce *RedisCommandExecutor) execute() bool {
case "EXEC": case "EXEC":
return rce.commands.Exec() return rce.commands.Exec()
case "HKEYS":
if l < 2 {
log.Println("WARN: Missing argments for HKEYS.")
return false
}
hash, ok := rce.args[1].([]byte)
if !ok {
log.Println("WARN: HKEYS data are not byte slices.")
return false
}
return rce.commands.Hkeys(hash)
} }
log.Printf("WARN: unknown command: '%s'\n", cmd) log.Printf("WARN: unknown command: '%s'\n", cmd)
return false return false

View File

@ -19,6 +19,8 @@ const (
existsSql = "SELECT 1 FROM blocks WHERE pos = ?" existsSql = "SELECT 1 FROM blocks WHERE pos = ?"
updateSql = "UPDATE blocks SET data = ? WHERE pos = ?" updateSql = "UPDATE blocks SET data = ? WHERE pos = ?"
insertSql = "INSERT INTO blocks (pos, data) VALUES (?, ?)" insertSql = "INSERT INTO blocks (pos, data) VALUES (?, ?)"
countSql = "SELECT count(*) FROM blocks"
keysSql = "SELECT pos FROM blocks"
) )
type SqliteBackend struct { type SqliteBackend struct {
@ -27,6 +29,8 @@ type SqliteBackend struct {
fetchStmt *sql.Stmt fetchStmt *sql.Stmt
insertStmt *sql.Stmt insertStmt *sql.Stmt
updateStmt *sql.Stmt updateStmt *sql.Stmt
countStmt *sql.Stmt
keysStmt *sql.Stmt
} }
type SqliteSession struct { type SqliteSession struct {
@ -75,6 +79,16 @@ func NewSqliteBackend(path string) (sqlb *SqliteBackend, err error) {
return return
} }
if res.countStmt, err = res.db.Prepare(countSql); err != nil {
res.closeAll()
return
}
if res.keysStmt, err = res.db.Prepare(keysSql); err != nil {
res.closeAll()
return
}
sqlb = &res sqlb = &res
return return
} }
@ -102,6 +116,8 @@ func (sqlb *SqliteBackend) closeAll() error {
closeStmt(&sqlb.insertStmt) closeStmt(&sqlb.insertStmt)
closeStmt(&sqlb.updateStmt) closeStmt(&sqlb.updateStmt)
closeStmt(&sqlb.existsStmt) closeStmt(&sqlb.existsStmt)
closeStmt(&sqlb.countStmt)
closeStmt(&sqlb.keysStmt)
return closeDB(&sqlb.db) return closeDB(&sqlb.db)
} }
@ -198,3 +214,37 @@ func (ss *SqliteSession) CommitTransaction() error {
ss.tx = nil ss.tx = nil
return tx.Commit() return tx.Commit()
} }
func (ss *SqliteSession) AllKeys(hash []byte) (keys chan []byte, n int, err error) {
globalLock.Lock()
defer globalLock.Unlock()
countStmt := ss.txStmt(ss.backend.countStmt)
if err = countStmt.QueryRow().Scan(&n); err != nil {
if err == sql.ErrNoRows {
err = nil
}
return
}
keysStmt := ss.txStmt(ss.backend.keysStmt)
var rows *sql.Rows
if rows, err = keysStmt.Query(); err != nil {
return
}
keys = make(chan []byte)
go func() {
defer rows.Close()
defer close(keys)
for rows.Next() {
var key []byte
if err := rows.Scan(&key); err != nil {
log.Printf("WARN: %s", err)
break
}
keys <- key
}
}()
return
}