diff --git a/.gitignore b/.gitignore index 1cb77a7..21d34b3 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ vendor *.swp *.swo +testdata diff --git a/db_test.go b/db_test.go index a195b5e..e95467e 100644 --- a/db_test.go +++ b/db_test.go @@ -3,6 +3,7 @@ package storage import ( "bytes" "io/ioutil" + "net" "os" "path" "testing" @@ -37,13 +38,38 @@ func TestImplementations(t *testing.T) { } defer os.RemoveAll(dir) - bolt, _ := NewBolt(path.Join(dir, "bolt")) - leveldb, _ := NewLevelDB(path.Join(dir, "leveldb")) - cases := []DB{ - &mock{m: make(map[string][]byte)}, - NewMap(), - bolt, - leveldb, + cases := make([]DB, 0) + cases = append(cases, &mock{m: make(map[string][]byte)}) + cases = append(cases, NewMap()) + + if bolt, err := NewBolt(path.Join(dir, "bolt")); err != nil { + t.Errorf("cannot make bolt: %v", err) + } else { + cases = append(cases, bolt) + } + + if leveldb, err := NewLevelDB(path.Join(dir, "leveldb")); err != nil { + t.Errorf("cannot make leveldb: %v", err) + } else { + cases = append(cases, leveldb) + } + + riakLN, err := net.Listen("tcp", "localhost:8087") + if err == nil { + defer riakLN.Close() + go func() { + for { + conn, err := riakLN.Accept() + if err == nil { + conn.Close() + } + } + }() + } + if riak, err := NewRiak("localhost:8087"); err != nil { + t.Errorf("cannot make riak: %v", err) + } else { + cases = append(cases, riak) } validKey := "key" @@ -51,12 +77,17 @@ func TestImplementations(t *testing.T) { for _, db := range cases { if err := db.Set(validKey, validValue); err != nil { - t.Fatalf("cannot set %T: %v", db, err) + t.Errorf("cannot set %T: %v", db, err) } if v, err := db.Get(validKey); err != nil { - t.Fatalf("cannot get %T: %v", db, err) + t.Errorf("cannot get %T: %v", db, err) } else if !bytes.Equal(v, validValue) { - t.Fatalf("wrong get %T: %q vs %q", db, v, validValue) + t.Errorf("wrong get %T: %q vs %q", db, v, validValue) + } else { + t.Logf("%18T GET: %s", db, v) + } + if err := db.Close(); err != nil { + t.Errorf("cannot close %T: %v", db, err) } } } diff --git a/errors.go b/errors.go index 18157e9..0c6962a 100644 --- a/errors.go +++ b/errors.go @@ -5,3 +5,5 @@ import "errors" var ErrNotFound = errors.New("not found") var ErrNotImpl = errors.New("not implemented") + +var ErrCantConnect = errors.New("cannot connect") diff --git a/map.go b/map.go index 19defe8..55a3e38 100644 --- a/map.go +++ b/map.go @@ -6,15 +6,15 @@ import ( type Map map[string][]byte -func NewMap() Map { +func NewMap() *Map { m := make(map[string][]byte) n := Map(m) - return n + return &n } -func (m Map) String() string { +func (m *Map) String() string { s := "" - for k, v := range m { + for k, v := range *m { if s != "" { s += ",\n" } @@ -23,25 +23,25 @@ func (m Map) String() string { return s } -func (m Map) Close() error { +func (m *Map) Close() error { m = nil return nil } -func (m Map) Get(key string) ([]byte, error) { - if _, ok := m[key]; !ok { +func (m *Map) Get(key string) ([]byte, error) { + if _, ok := (*m)[key]; !ok { return nil, ErrNotFound } - return m[key], nil + return (*m)[key], nil } -func (m Map) Set(key string, value []byte) error { +func (m *Map) Set(key string, value []byte) error { if value == nil { - if _, ok := m[key]; ok { - delete(m, key) + if _, ok := (*m)[key]; ok { + delete(*m, key) } return nil } - m[key] = value + (*m)[key] = value return nil } diff --git a/riak.go b/riak.go new file mode 100644 index 0000000..87dc2eb --- /dev/null +++ b/riak.go @@ -0,0 +1,64 @@ +package storage + +import ( + riak "github.com/basho/riak-go-client" +) + +type Riak struct { + db *riak.Client +} + +func NewRiak(addr string, addrs ...string) (*Riak, error) { + clientOpts := &riak.NewClientOptions{ + RemoteAddresses: append(addrs, addr), + } + + db, err := riak.NewClient(clientOpts) + if err != nil { + return nil, err + } + + ok, err := db.Ping() + if !ok { + return nil, ErrCantConnect + } + + return &Riak{ + db: db, + }, err +} + +func (r *Riak) Get(key string) ([]byte, error) { + obj := &riak.Object{} + + cmd, err := riak.NewFetchValueCommandBuilder(). + WithBucket(DefaultNamespace). + WithKey(key). + Build() + if err != nil { + return nil, err + } + + err = r.db.Execute(cmd) + return obj.Value, err +} + +func (r *Riak) Set(key string, value []byte) error { + obj := &riak.Object{ + Value: value, + } + + cmd, err := riak.NewStoreValueCommandBuilder(). + WithBucket(DefaultNamespace). + WithContent(obj). + Build() + if err != nil { + return err + } + + return r.db.Execute(cmd) +} + +func (r *Riak) Close() error { + return r.db.Stop() +}