Skip to content

Commit

Permalink
initial import
Browse files Browse the repository at this point in the history
  • Loading branch information
kyleterry committed Jan 28, 2016
0 parents commit 64ff505
Show file tree
Hide file tree
Showing 5 changed files with 652 additions and 0 deletions.
Empty file added LICENSE
Empty file.
Empty file added README.md
Empty file.
147 changes: 147 additions & 0 deletions goleg_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package goleg

import (
"bytes"
"io/ioutil"
"os"
"strconv"
"testing"
)

func openRandomDB(features int) (Database, string, error) {
name, err := ioutil.TempDir("/tmp", "goleg")
if err != nil {
return Database{}, "", err
}

//F_APPENDONLY|F_AOL_FFLUSH|F_LZ4|F_SPLAYTREE
database, err := Open(name, "test", features)
if err != nil {
return Database{}, "", err
}

return database, name, nil
}

func cleanTemp(dir string) {
os.RemoveAll(dir)
}

func TestOpen(t *testing.T) {
if testing.Short() {
t.Skip("Skipping in short mode")
}

database, dir, err := openRandomDB(F_APPENDONLY)
if err != nil {
t.Fatalf("Can't open database: %s", err.Error())
}

database.Close()
cleanTemp(dir)
}

const JARN = 10

func TestJar(t *testing.T) {
if testing.Short() {
t.Skip("Skipping in short mode")
}

database, dir, err := openRandomDB(F_LZ4 | F_SPLAYTREE)
if err != nil {
t.Fatalf("Can't open database: %s", err.Error())
}

for i := 0; i < JARN; i++ {
if database.Jar("record"+strconv.Itoa(i), []byte("value"+strconv.Itoa(i))) != 0 {
t.Fatalf("Can't jar value #%d", i)
}
}

database.Close()
cleanTemp(dir)
}

func TestUnjar(t *testing.T) {
database, dir, err := openRandomDB(F_LZ4 | F_SPLAYTREE)
if err != nil {
t.Fatalf("Can't open database: %s", err.Error())
}

for i := 0; i < JARN; i++ {
if database.Jar("record"+strconv.Itoa(i), []byte("value"+strconv.Itoa(i))) != 0 {
t.Fatalf("Can't jar value #%d", i)
}
}

for i := 0; i < JARN; i++ {
val := database.Unjar("record" + strconv.Itoa(i))
if !bytes.Equal(val, []byte("value"+strconv.Itoa(i))) {
t.Errorf("Value #%d doesn't match", i)
}
}

database.Close()
cleanTemp(dir)
}

func TestFullKeyDump(t *testing.T) {
database, _, err := openRandomDB(F_LZ4 | F_SPLAYTREE)
if err != nil {
t.Fatalf("Can't open database: %s", err.Error())
}

for i := 0; i < JARN; i++ {
if database.Jar("record"+strconv.Itoa(i), []byte("value"+strconv.Itoa(i))) != 0 {
t.Fatalf("Can't jar value #%d", i)
}
}

gotKeys, keys := database.DumpKeys()

if !gotKeys {
t.Fatal("Didn't get keys and should have")
}

var j int
for i := 0; i <= JARN; i++ {
for _, key := range keys {
if key == "record"+strconv.Itoa(i) {
j++
}
}
}
if j != JARN {
t.Fatal("One or more keys did not dump")
}
}

func TestBulkUnjarOnlyReturnsKeysWeGiveIt(t *testing.T) {
database, _, err := openRandomDB(F_LZ4 | F_SPLAYTREE)
if err != nil {
t.Fatalf("Can't open database: %s", err.Error())
}

keys := []string{"key0", "key1", "key2", "key3"}

for i, key := range keys {
if database.Jar(key, []byte("value"+strconv.Itoa(i))) != 0 {
t.Fatalf("Can't jar value #%d", i)
}
}

subset := keys[1:] //sans key0

values := database.BulkUnjar(subset)

if l := len(values); l != 3 {
t.Fatalf("Expected a length of 3, got %d", l)
}

for i, value := range values {
if subset[i][3] != string(value)[5] {
t.Fatalf("Expected %s, got %s", subset[i][3], string(value)[5])
}
}
}
160 changes: 160 additions & 0 deletions highlevel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package goleg

/*
#include "oleg.h"
*/
import "C"
import (
"errors"
"sync"
"time"
)

type Database struct {
db *C.ol_database
RecordCount *C.int
mutex *sync.Mutex
}

func Open(path, name string, features int) (Database, error) {
var database Database
database.db = COpen(path, name, features)
if database.db == nil {
return Database{}, errors.New("Can't open database (NULL returned)")
}
database.RecordCount = &database.db.rcrd_cnt
database.mutex = &sync.Mutex{}
return database, nil
}

func (d Database) Close() int {
d.mutex.Lock()
defer d.mutex.Unlock()
return CClose(d.db)
}

func (d Database) Unjar(key string) []byte {
d.mutex.Lock()
var dsize uintptr
var ret = CUnjar(d.db, key, uintptr(len(key)), &dsize)
d.mutex.Unlock()
return ret
}

func (d Database) Jar(key string, value []byte) int {
d.mutex.Lock()
var ret = CJar(d.db, key, uintptr(len(key)), value, uintptr(len(value)))
d.mutex.Unlock()
return ret
}

func (d Database) Scoop(key string) int {
d.mutex.Lock()
var ret = CScoop(d.db, key, uintptr(len(key)))
d.mutex.Unlock()
return ret
}

func (d Database) Uptime() int {
d.mutex.Lock()
var ret = CUptime(d.db)
d.mutex.Unlock()
return ret
}

func (d Database) Expiration(key string) (time.Time, bool) {
d.mutex.Lock()
var time, exists = CSniff(d.db, key, uintptr(len(key)))
d.mutex.Unlock()
return time, exists
}

func (d Database) Spoil(key string, expiration time.Time) int {
d.mutex.Lock()
var ret = CSpoil(d.db, key, uintptr(len(key)), expiration)
d.mutex.Unlock()
return ret
}

func (d Database) Exists(key string) bool {
d.mutex.Lock()
var ret = CExists(d.db, key, uintptr(len(key))) == 0
d.mutex.Unlock()
return ret
}

func (d Database) Squish() bool {
d.mutex.Lock()
var ret = CSquish(d.db) == 1
d.mutex.Unlock()
return ret
}

func (d Database) PrefixMatch(prefix string) (bool, []string) {
d.mutex.Lock()
len, out := CPrefixMatch(d.db, prefix, uintptr(len(prefix)))
d.mutex.Unlock()
return len >= 0, out
}

func (d Database) DumpKeys() (bool, []string) {
d.mutex.Lock()
len, out := CDumpKeys(d.db)
d.mutex.Unlock()
return len >= 0, out
}

func (d Database) First() (bool, string, []byte) {
d.mutex.Lock()
node := CNodeFirst(d.db)
if node == nil {
d.mutex.Unlock()
return false, "", nil
}
var exists, key, data = CNodeGet(d.db, node)
d.mutex.Unlock()
return exists, key, data
}

func (d Database) Last() (bool, string, []byte) {
d.mutex.Lock()
node := CNodeLast(d.db)
if node == nil {
d.mutex.Unlock()
return false, "", nil
}
var exists, key, data = CNodeGet(d.db, node)
d.mutex.Unlock()
return exists, key, data
}

func (d Database) Next(key string) (bool, string, []byte) {
d.mutex.Lock()
node := CNodeNext(d.db, key, uintptr(len(key)))
if node == nil {
d.mutex.Unlock()
return false, "", nil
}
var exists, next_key, data = CNodeGet(d.db, node)
d.mutex.Unlock()
return exists, next_key, data
}

func (d Database) Prev(key string) (bool, string, []byte) {
d.mutex.Lock()
node := CNodePrev(d.db, key, uintptr(len(key)))
if node == nil {
d.mutex.Unlock()
return false, "", nil
}
var exists, prev_key, data = CNodeGet(d.db, node)
d.mutex.Unlock()
return exists, prev_key, data
}

func (d Database) BulkUnjar(keys []string) [][]byte {
d.mutex.Lock()
out := CBulkUnjar(d.db, keys)
d.mutex.Unlock()
return out
}
Loading

0 comments on commit 64ff505

Please sign in to comment.