mirror of
https://github.com/gogrlx/bitcask.git
synced 2026-04-05 12:32:44 -07:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
962e53af17 | ||
|
|
7a427a237a | ||
|
|
8bf169c96f | ||
|
|
c1488fed2a | ||
|
|
d6e806e655 |
17
README.md
17
README.md
@@ -6,13 +6,13 @@
|
||||
[](https://godoc.org/github.com/prologic/bitcask)
|
||||
[](https://sourcegraph.com/github.com/prologic/bitcask?badge)
|
||||
|
||||
A Bitcask (LSM+WAL) Key/Value Store written in Go.
|
||||
A high performance Key/Value store written in [Go](https://golang.org) with a predictable read/write performance and high throughput. Uses a [Bitcask](https://en.wikipedia.org/wiki/Bitcask) on-disk layout (LSM+WAL) similar to [Riak](https://riak.com/).
|
||||
|
||||
## Features
|
||||
|
||||
* Embeddable
|
||||
* Builtin CLI
|
||||
* Builtin Redis-compatible server
|
||||
* Embeddable (`import "github.com/prologic/bitcask"`)
|
||||
* Builtin CLI (`bitcask`)
|
||||
* Builtin Redis-compatible server (`bitcaskd`)
|
||||
* Predictable read/write performance
|
||||
* Low latecny
|
||||
* High throughput (See: [Performance](README.md#Performance)
|
||||
@@ -34,16 +34,13 @@ $ go get github.com/prologic/bitcask
|
||||
```#!go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/prologic/bitcask"
|
||||
)
|
||||
import "github.com/prologic/bitcask"
|
||||
|
||||
func main() {
|
||||
db, _ := bitcask.Open("/tmp/db")
|
||||
defer db.Close()
|
||||
db.Set("Hello", []byte("World"))
|
||||
db.Close()
|
||||
val, _ := db.Get("hello")
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -79,6 +79,11 @@ func (b *Bitcask) Get(key string) ([]byte, error) {
|
||||
return e.Value, nil
|
||||
}
|
||||
|
||||
func (b *Bitcask) Has(key string) bool {
|
||||
_, ok := b.keydir.Get(key)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (b *Bitcask) Put(key string, value []byte) error {
|
||||
if len(key) > b.config.MaxKeySize {
|
||||
return ErrKeyTooLarge
|
||||
|
||||
@@ -40,6 +40,30 @@ func TestAll(t *testing.T) {
|
||||
assert.Equal([]byte("bar"), val)
|
||||
})
|
||||
|
||||
t.Run("Has", func(t *testing.T) {
|
||||
assert.True(db.Has("foo"))
|
||||
})
|
||||
|
||||
t.Run("Fold", func(t *testing.T) {
|
||||
var (
|
||||
keys []string
|
||||
values [][]byte
|
||||
)
|
||||
|
||||
err := db.Fold(func(key string) error {
|
||||
value, err := db.Get(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keys = append(keys, key)
|
||||
values = append(values, value)
|
||||
return nil
|
||||
})
|
||||
assert.NoError(err)
|
||||
assert.Equal([]string{"foo"}, keys)
|
||||
assert.Equal([][]byte{[]byte("bar")}, values)
|
||||
})
|
||||
|
||||
t.Run("Delete", func(t *testing.T) {
|
||||
err := db.Delete("foo")
|
||||
assert.NoError(err)
|
||||
@@ -174,7 +198,7 @@ func TestMaxValueSize(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestMerge(t *testing.T) {
|
||||
func TestOpenMerge(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
testdir, err := ioutil.TempDir("", "bitcask")
|
||||
@@ -187,7 +211,7 @@ func TestMerge(t *testing.T) {
|
||||
)
|
||||
|
||||
t.Run("Open", func(t *testing.T) {
|
||||
db, err = Open(testdir, WithMaxDatafileSize(1024))
|
||||
db, err = Open(testdir, WithMaxDatafileSize(32))
|
||||
assert.NoError(err)
|
||||
})
|
||||
|
||||
@@ -245,6 +269,77 @@ func TestMerge(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestMergeOpen(t *testing.T) {
|
||||
var (
|
||||
db *Bitcask
|
||||
err error
|
||||
)
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
testdir, err := ioutil.TempDir("", "bitcask")
|
||||
assert.NoError(err)
|
||||
|
||||
t.Run("Setup", func(t *testing.T) {
|
||||
t.Run("Open", func(t *testing.T) {
|
||||
db, err = Open(testdir, WithMaxDatafileSize(32))
|
||||
assert.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("Put", func(t *testing.T) {
|
||||
for i := 0; i < 1024; i++ {
|
||||
err = db.Put(string(i), []byte(strings.Repeat(" ", 1024)))
|
||||
assert.NoError(err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Get", func(t *testing.T) {
|
||||
for i := 0; i < 32; i++ {
|
||||
err = db.Put(string(i), []byte(strings.Repeat(" ", 1024)))
|
||||
assert.NoError(err)
|
||||
val, err := db.Get(string(i))
|
||||
assert.NoError(err)
|
||||
assert.Equal([]byte(strings.Repeat(" ", 1024)), val)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Sync", func(t *testing.T) {
|
||||
err = db.Sync()
|
||||
assert.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("Close", func(t *testing.T) {
|
||||
err = db.Close()
|
||||
assert.NoError(err)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Merge", func(t *testing.T) {
|
||||
t.Run("Merge", func(t *testing.T) {
|
||||
err = Merge(testdir, true)
|
||||
assert.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("Open", func(t *testing.T) {
|
||||
db, err = Open(testdir)
|
||||
assert.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("Get", func(t *testing.T) {
|
||||
for i := 0; i < 32; i++ {
|
||||
val, err := db.Get(string(i))
|
||||
assert.NoError(err)
|
||||
assert.Equal([]byte(strings.Repeat(" ", 1024)), val)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Close", func(t *testing.T) {
|
||||
err = db.Close()
|
||||
assert.NoError(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestConcurrent(t *testing.T) {
|
||||
var (
|
||||
db *Bitcask
|
||||
|
||||
Reference in New Issue
Block a user