Compare commits

..

7 Commits

Author SHA1 Message Date
James Mills
1298240f53 Unexport some internal implemtnation details 2019-03-18 17:31:31 +10:00
James Mills
2a35976cdd Ooops 2019-03-17 14:00:15 +10:00
James Mills
6fe6fe0689 Refactored configuration option handling. Fixes #3 2019-03-17 13:53:30 +10:00
James Mills
e83608b903 Fixed missing error handling opening new Datafile(s) during Put() Fixes #4 2019-03-17 13:47:07 +10:00
James Mills
67ab944db7 Refactored some internals and removed timestamp field (unsure why it was needed in the original paper) 2019-03-16 12:40:24 +10:00
James Mills
cb00b11dd7 Increase no. of goroutines to catch more race conditions in tests 2019-03-16 12:33:07 +10:00
James Mills
e9c858d43f Add CRC Checksum checks on reading values back 2019-03-16 12:16:23 +10:00
17 changed files with 133 additions and 128 deletions

View File

@@ -13,11 +13,11 @@ dev: build
build: clean generate build: clean generate
@go build \ @go build \
-tags "netgo static_build" -installsuffix netgo \ -tags "netgo static_build" -installsuffix netgo \
-ldflags "-w -X $(shell go list).Version=$(VERSION) -X $(shell go list).Commit=$(COMMIT)" \ -ldflags "-w -X $(shell go list)/internal.Version=$(VERSION) -X $(shell go list)/internal.Commit=$(COMMIT)" \
./cmd/bitcask/... ./cmd/bitcask/...
@go build \ @go build \
-tags "netgo static_build" -installsuffix netgo \ -tags "netgo static_build" -installsuffix netgo \
-ldflags "-w -X $(shell go list).Version=$(VERSION) -X $(shell go list).Commit=$(COMMIT)" \ -ldflags "-w -X $(shell go list)/internal.Version=$(VERSION) -X $(shell go list)/internal.Commit=$(COMMIT)" \
./cmd/bitcaskd/... ./cmd/bitcaskd/...
generate: generate:

View File

@@ -2,25 +2,27 @@ package bitcask
import ( import (
"fmt" "fmt"
"hash/crc32"
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"time"
"github.com/gofrs/flock" "github.com/gofrs/flock"
"github.com/prologic/trie" "github.com/prologic/trie"
"github.com/prologic/bitcask/internal"
) )
type Bitcask struct { type Bitcask struct {
*flock.Flock *flock.Flock
opts Options config *config
path string path string
curr *Datafile curr *internal.Datafile
keydir *Keydir keydir *internal.Keydir
datafiles []*Datafile datafiles []*internal.Datafile
trie *trie.Trie trie *trie.Trie
maxDatafileSize int64 maxDatafileSize int64
@@ -43,41 +45,46 @@ func (b *Bitcask) Sync() error {
} }
func (b *Bitcask) Get(key string) ([]byte, error) { func (b *Bitcask) Get(key string) ([]byte, error) {
var df *Datafile var df *internal.Datafile
item, ok := b.keydir.Get(key) item, ok := b.keydir.Get(key)
if !ok { if !ok {
return nil, fmt.Errorf("error: key not found %s", key) return nil, fmt.Errorf("error: key not found %s", key)
} }
if item.FileID == b.curr.id { if item.FileID == b.curr.FileID() {
df = b.curr df = b.curr
} else { } else {
df = b.datafiles[item.FileID] df = b.datafiles[item.FileID]
} }
e, err := df.ReadAt(item.Index) e, err := df.ReadAt(item.Offset)
if err != nil { if err != nil {
return nil, err return nil, err
} }
checksum := crc32.ChecksumIEEE(e.Value)
if checksum != e.Checksum {
return nil, fmt.Errorf("error: checksum falied %s %d != %d", key, e.Checksum, checksum)
}
return e.Value, nil return e.Value, nil
} }
func (b *Bitcask) Put(key string, value []byte) error { func (b *Bitcask) Put(key string, value []byte) error {
if len(key) > b.opts.MaxKeySize { if len(key) > b.config.MaxKeySize {
return fmt.Errorf("error: key too large %d > %d", len(key), b.opts.MaxKeySize) return fmt.Errorf("error: key too large %d > %d", len(key), b.config.MaxKeySize)
} }
if len(value) > b.opts.MaxValueSize { if len(value) > b.config.MaxValueSize {
return fmt.Errorf("error: value too large %d > %d", len(value), b.opts.MaxValueSize) return fmt.Errorf("error: value too large %d > %d", len(value), b.config.MaxValueSize)
} }
index, err := b.put(key, value) offset, err := b.put(key, value)
if err != nil { if err != nil {
return err return err
} }
item := b.keydir.Add(key, b.curr.id, index, time.Now().Unix()) item := b.keydir.Add(key, b.curr.FileID(), offset)
b.trie.Add(key, item) b.trie.Add(key, item)
return nil return nil
@@ -126,18 +133,22 @@ func (b *Bitcask) put(key string, value []byte) (int64, error) {
return -1, err return -1, err
} }
df, err := NewDatafile(b.path, b.curr.id, true) df, err := internal.NewDatafile(b.path, b.curr.FileID(), true)
if err != nil {
return -1, err
}
b.datafiles = append(b.datafiles, df) b.datafiles = append(b.datafiles, df)
id := b.curr.id + 1 id := b.curr.FileID() + 1
curr, err := NewDatafile(b.path, id, false) curr, err := internal.NewDatafile(b.path, id, false)
if err != nil { if err != nil {
return -1, err return -1, err
} }
b.curr = curr b.curr = curr
} }
e := NewEntry(key, value) e := internal.NewEntry(key, value)
return b.curr.Write(e) return b.curr.Write(e)
} }
@@ -147,12 +158,12 @@ func (b *Bitcask) setMaxDatafileSize(size int64) error {
} }
func Merge(path string, force bool) error { func Merge(path string, force bool) error {
fns, err := getDatafiles(path) fns, err := internal.GetDatafiles(path)
if err != nil { if err != nil {
return err return err
} }
ids, err := parseIds(fns) ids, err := internal.ParseIds(fns)
if err != nil { if err != nil {
return err return err
} }
@@ -182,9 +193,9 @@ func Merge(path string, force bool) error {
id := ids[i] id := ids[i]
keydir := NewKeydir() keydir := internal.NewKeydir()
df, err := NewDatafile(path, id, true) df, err := internal.NewDatafile(path, id, true)
if err != nil { if err != nil {
return err return err
} }
@@ -205,10 +216,10 @@ func Merge(path string, force bool) error {
continue continue
} }
keydir.Add(e.Key, ids[i], e.Index, e.Timestamp) keydir.Add(e.Key, ids[i], e.Offset)
} }
tempdf, err := NewDatafile(temp, id, false) tempdf, err := internal.NewDatafile(temp, id, false)
if err != nil { if err != nil {
return err return err
} }
@@ -216,7 +227,7 @@ func Merge(path string, force bool) error {
for key := range keydir.Keys() { for key := range keydir.Keys() {
item, _ := keydir.Get(key) item, _ := keydir.Get(key)
e, err := df.ReadAt(item.Index) e, err := df.ReadAt(item.Offset)
if err != nil { if err != nil {
return err return err
} }
@@ -252,7 +263,7 @@ func Merge(path string, force bool) error {
return nil return nil
} }
func Open(path string, options ...func(*Bitcask) error) (*Bitcask, error) { func Open(path string, options ...option) (*Bitcask, error) {
if err := os.MkdirAll(path, 0755); err != nil { if err := os.MkdirAll(path, 0755); err != nil {
return nil, err return nil, err
} }
@@ -262,23 +273,23 @@ func Open(path string, options ...func(*Bitcask) error) (*Bitcask, error) {
return nil, err return nil, err
} }
fns, err := getDatafiles(path) fns, err := internal.GetDatafiles(path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ids, err := parseIds(fns) ids, err := internal.ParseIds(fns)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var datafiles []*Datafile var datafiles []*internal.Datafile
keydir := NewKeydir() keydir := internal.NewKeydir()
trie := trie.New() trie := trie.New()
for i, fn := range fns { for i, fn := range fns {
df, err := NewDatafile(path, ids[i], true) df, err := internal.NewDatafile(path, ids[i], true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -291,14 +302,14 @@ func Open(path string, options ...func(*Bitcask) error) (*Bitcask, error) {
} }
defer f.Close() defer f.Close()
hint, err := NewKeydirFromBytes(f) hint, err := internal.NewKeydirFromBytes(f)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for key := range hint.Keys() { for key := range hint.Keys() {
item, _ := hint.Get(key) item, _ := hint.Get(key)
_ = keydir.Add(key, item.FileID, item.Index, item.Timestamp) _ = keydir.Add(key, item.FileID, item.Offset)
trie.Add(key, item) trie.Add(key, item)
} }
} else { } else {
@@ -317,7 +328,7 @@ func Open(path string, options ...func(*Bitcask) error) (*Bitcask, error) {
continue continue
} }
item := keydir.Add(e.Key, ids[i], e.Index, e.Timestamp) item := keydir.Add(e.Key, ids[i], e.Offset)
trie.Add(e.Key, item) trie.Add(e.Key, item)
} }
} }
@@ -328,14 +339,14 @@ func Open(path string, options ...func(*Bitcask) error) (*Bitcask, error) {
id = ids[(len(ids) - 1)] id = ids[(len(ids) - 1)]
} }
curr, err := NewDatafile(path, id, false) curr, err := internal.NewDatafile(path, id, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
bitcask := &Bitcask{ bitcask := &Bitcask{
Flock: flock.New(filepath.Join(path, "lock")), Flock: flock.New(filepath.Join(path, "lock")),
opts: NewDefaultOptions(), config: NewDefaultConfig(),
path: path, path: path,
curr: curr, curr: curr,
keydir: keydir, keydir: keydir,
@@ -345,8 +356,8 @@ func Open(path string, options ...func(*Bitcask) error) (*Bitcask, error) {
maxDatafileSize: DefaultMaxDatafileSize, maxDatafileSize: DefaultMaxDatafileSize,
} }
for _, option := range options { for _, opt := range options {
err = option(bitcask) err = opt(bitcask.config)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -287,10 +287,9 @@ func TestConcurrent(t *testing.T) {
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
go f(wg, 2) go f(wg, 2)
wg.Add(1)
go f(wg, 3) go f(wg, 3)
wg.Add(1) go f(wg, 5)
wg.Add(3)
wg.Wait() wg.Wait()
}) })
@@ -310,10 +309,9 @@ func TestConcurrent(t *testing.T) {
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
go f(wg, 100) go f(wg, 100)
wg.Add(1)
go f(wg, 100) go f(wg, 100)
wg.Add(1) go f(wg, 100)
wg.Add(3)
wg.Wait() wg.Wait()
}) })

View File

@@ -8,13 +8,13 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/prologic/bitcask" "github.com/prologic/bitcask/internal"
) )
// RootCmd represents the base command when called without any subcommands // RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{ var RootCmd = &cobra.Command{
Use: "bitcask", Use: "bitcask",
Version: bitcask.FullVersion(), Version: internal.FullVersion(),
Short: "Command-line tools for bitcask", Short: "Command-line tools for bitcask",
Long: `This is the command-line tool to interact with a bitcask database. Long: `This is the command-line tool to interact with a bitcask database.

View File

@@ -10,6 +10,7 @@ import (
"github.com/tidwall/redcon" "github.com/tidwall/redcon"
"github.com/prologic/bitcask" "github.com/prologic/bitcask"
"github.com/prologic/bitcask/internal"
) )
var ( var (
@@ -43,7 +44,7 @@ func main() {
} }
if version { if version {
fmt.Printf("bitcaskd version %s", bitcask.FullVersion()) fmt.Printf("bitcaskd version %s", internal.FullVersion())
os.Exit(0) os.Exit(0)
} }
@@ -60,7 +61,7 @@ func main() {
os.Exit(1) os.Exit(1)
} }
log.WithField("bind", bind).WithField("path", path).Infof("starting bitcaskd v%s", bitcask.FullVersion()) log.WithField("bind", bind).WithField("path", path).Infof("starting bitcaskd v%s", internal.FullVersion())
err = redcon.ListenAndServe(bind, err = redcon.ListenAndServe(bind,
func(conn redcon.Conn, cmd redcon.Command) { func(conn redcon.Conn, cmd redcon.Command) {

View File

@@ -1,17 +0,0 @@
package bitcask
import (
"hash/crc32"
pb "github.com/prologic/bitcask/proto"
)
func NewEntry(key string, value []byte) pb.Entry {
crc := crc32.ChecksumIEEE(value)
return pb.Entry{
CRC: crc,
Key: key,
Value: value,
}
}

View File

@@ -1,16 +1,15 @@
package bitcask package internal
import ( import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"sync" "sync"
"time"
"github.com/pkg/errors" "github.com/pkg/errors"
pb "github.com/prologic/bitcask/proto" pb "github.com/prologic/bitcask/internal/proto"
"github.com/prologic/bitcask/streampb" "github.com/prologic/bitcask/internal/streampb"
) )
const ( const (
@@ -72,6 +71,10 @@ func NewDatafile(path string, id int, readonly bool) (*Datafile, error) {
}, nil }, nil
} }
func (df *Datafile) FileID() int {
return df.id
}
func (df *Datafile) Name() string { func (df *Datafile) Name() string {
return df.r.Name() return df.r.Name()
} }
@@ -128,8 +131,7 @@ func (df *Datafile) Write(e pb.Entry) (int64, error) {
df.Lock() df.Lock()
defer df.Unlock() defer df.Unlock()
e.Index = df.offset e.Offset = df.offset
e.Timestamp = time.Now().Unix()
n, err := df.enc.Encode(&e) n, err := df.enc.Encode(&e)
if err != nil { if err != nil {
@@ -137,5 +139,5 @@ func (df *Datafile) Write(e pb.Entry) (int64, error) {
} }
df.offset += n df.offset += n
return e.Index, nil return e.Offset, nil
} }

17
internal/entry.go Normal file
View File

@@ -0,0 +1,17 @@
package internal
import (
"hash/crc32"
pb "github.com/prologic/bitcask/internal/proto"
)
func NewEntry(key string, value []byte) pb.Entry {
checksum := crc32.ChecksumIEEE(value)
return pb.Entry{
Checksum: checksum,
Key: key,
Value: value,
}
}

View File

@@ -1,4 +1,4 @@
package bitcask package internal
import ( import (
"bytes" "bytes"
@@ -9,9 +9,8 @@ import (
) )
type Item struct { type Item struct {
FileID int FileID int
Index int64 Offset int64
Timestamp int64
} }
type Keydir struct { type Keydir struct {
@@ -25,11 +24,10 @@ func NewKeydir() *Keydir {
} }
} }
func (k *Keydir) Add(key string, fileid int, index, timestamp int64) Item { func (k *Keydir) Add(key string, fileid int, offset int64) Item {
item := Item{ item := Item{
FileID: fileid, FileID: fileid,
Index: index, Offset: offset,
Timestamp: timestamp,
} }
k.Lock() k.Lock()

View File

@@ -19,11 +19,10 @@ var _ = math.Inf
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Entry struct { type Entry struct {
CRC uint32 `protobuf:"varint,1,opt,name=CRC,proto3" json:"CRC,omitempty"` Checksum uint32 `protobuf:"varint,1,opt,name=Checksum,proto3" json:"Checksum,omitempty"`
Key string `protobuf:"bytes,2,opt,name=Key,proto3" json:"Key,omitempty"` Key string `protobuf:"bytes,2,opt,name=Key,proto3" json:"Key,omitempty"`
Index int64 `protobuf:"varint,3,opt,name=Index,proto3" json:"Index,omitempty"` Offset int64 `protobuf:"varint,3,opt,name=Offset,proto3" json:"Offset,omitempty"`
Value []byte `protobuf:"bytes,4,opt,name=Value,proto3" json:"Value,omitempty"` Value []byte `protobuf:"bytes,4,opt,name=Value,proto3" json:"Value,omitempty"`
Timestamp int64 `protobuf:"varint,5,opt,name=Timestamp,proto3" json:"Timestamp,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@@ -33,7 +32,7 @@ func (m *Entry) Reset() { *m = Entry{} }
func (m *Entry) String() string { return proto.CompactTextString(m) } func (m *Entry) String() string { return proto.CompactTextString(m) }
func (*Entry) ProtoMessage() {} func (*Entry) ProtoMessage() {}
func (*Entry) Descriptor() ([]byte, []int) { func (*Entry) Descriptor() ([]byte, []int) {
return fileDescriptor_entry_4f5906245d08394f, []int{0} return fileDescriptor_entry_3e91842c99935ae2, []int{0}
} }
func (m *Entry) XXX_Unmarshal(b []byte) error { func (m *Entry) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Entry.Unmarshal(m, b) return xxx_messageInfo_Entry.Unmarshal(m, b)
@@ -53,9 +52,9 @@ func (m *Entry) XXX_DiscardUnknown() {
var xxx_messageInfo_Entry proto.InternalMessageInfo var xxx_messageInfo_Entry proto.InternalMessageInfo
func (m *Entry) GetCRC() uint32 { func (m *Entry) GetChecksum() uint32 {
if m != nil { if m != nil {
return m.CRC return m.Checksum
} }
return 0 return 0
} }
@@ -67,9 +66,9 @@ func (m *Entry) GetKey() string {
return "" return ""
} }
func (m *Entry) GetIndex() int64 { func (m *Entry) GetOffset() int64 {
if m != nil { if m != nil {
return m.Index return m.Offset
} }
return 0 return 0
} }
@@ -81,28 +80,20 @@ func (m *Entry) GetValue() []byte {
return nil return nil
} }
func (m *Entry) GetTimestamp() int64 {
if m != nil {
return m.Timestamp
}
return 0
}
func init() { func init() {
proto.RegisterType((*Entry)(nil), "proto.Entry") proto.RegisterType((*Entry)(nil), "proto.Entry")
} }
func init() { proto.RegisterFile("entry.proto", fileDescriptor_entry_4f5906245d08394f) } func init() { proto.RegisterFile("entry.proto", fileDescriptor_entry_3e91842c99935ae2) }
var fileDescriptor_entry_4f5906245d08394f = []byte{ var fileDescriptor_entry_3e91842c99935ae2 = []byte{
// 134 bytes of a gzipped FileDescriptorProto // 126 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4e, 0xcd, 0x2b, 0x29, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4e, 0xcd, 0x2b, 0x29,
0xaa, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x53, 0x4a, 0xa5, 0x5c, 0xac, 0xae, 0xaa, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x53, 0x4a, 0xc9, 0x5c, 0xac, 0xae,
0x20, 0x51, 0x21, 0x01, 0x2e, 0x66, 0xe7, 0x20, 0x67, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xde, 0x20, 0x20, 0x51, 0x21, 0x29, 0x2e, 0x0e, 0xe7, 0x8c, 0xd4, 0xe4, 0xec, 0xe2, 0xd2, 0x5c, 0x09, 0x46,
0x10, 0x13, 0x24, 0xe2, 0x9d, 0x5a, 0x29, 0xc1, 0xa4, 0xc0, 0xa8, 0xc1, 0x19, 0x04, 0x62, 0x0a, 0x05, 0x46, 0x0d, 0xde, 0x20, 0x38, 0x5f, 0x48, 0x80, 0x8b, 0xd9, 0x3b, 0xb5, 0x52, 0x82, 0x49,
0x89, 0x70, 0xb1, 0x7a, 0xe6, 0xa5, 0xa4, 0x56, 0x48, 0x30, 0x2b, 0x30, 0x6a, 0x30, 0x07, 0x41, 0x81, 0x51, 0x83, 0x33, 0x08, 0xc4, 0x14, 0x12, 0xe3, 0x62, 0xf3, 0x4f, 0x4b, 0x2b, 0x4e, 0x2d,
0x38, 0x20, 0xd1, 0xb0, 0xc4, 0x9c, 0xd2, 0x54, 0x09, 0x16, 0x05, 0x46, 0x0d, 0x9e, 0x20, 0x08, 0x91, 0x60, 0x56, 0x60, 0xd4, 0x60, 0x0e, 0x82, 0xf2, 0x84, 0x44, 0xb8, 0x58, 0xc3, 0x12, 0x73,
0x47, 0x48, 0x86, 0x8b, 0x33, 0x24, 0x33, 0x37, 0xb5, 0xb8, 0x24, 0x31, 0xb7, 0x40, 0x82, 0x15, 0x4a, 0x53, 0x25, 0x58, 0x14, 0x18, 0x35, 0x78, 0x82, 0x20, 0x9c, 0x24, 0x36, 0xb0, 0x5d, 0xc6,
0xac, 0x1e, 0x21, 0x90, 0xc4, 0x06, 0xb6, 0xdd, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x07, 0x99, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x76, 0xd2, 0x3e, 0x83, 0x81, 0x00, 0x00, 0x00,
0x47, 0xb9, 0x93, 0x00, 0x00, 0x00,
} }

View File

@@ -3,9 +3,8 @@ syntax = "proto3";
package proto; package proto;
message Entry { message Entry {
uint32 CRC = 1; uint32 Checksum = 1;
string Key = 2; string Key = 2;
int64 Index = 3; int64 Offset = 3;
bytes Value = 4; bytes Value = 4;
int64 Timestamp = 5;
} }

View File

@@ -1,4 +1,4 @@
package bitcask package internal
import ( import (
"fmt" "fmt"
@@ -8,7 +8,7 @@ import (
"strings" "strings"
) )
func getDatafiles(path string) ([]string, error) { func GetDatafiles(path string) ([]string, error) {
fns, err := filepath.Glob(fmt.Sprintf("%s/*.data", path)) fns, err := filepath.Glob(fmt.Sprintf("%s/*.data", path))
if err != nil { if err != nil {
return nil, err return nil, err
@@ -17,7 +17,7 @@ func getDatafiles(path string) ([]string, error) {
return fns, nil return fns, nil
} }
func parseIds(fns []string) ([]int, error) { func ParseIds(fns []string) ([]int, error) {
var ids []int var ids []int
for _, fn := range fns { for _, fn := range fns {
fn = filepath.Base(fn) fn = filepath.Base(fn)

View File

@@ -1,4 +1,4 @@
package bitcask package internal
import ( import (
"fmt" "fmt"

View File

@@ -1,4 +1,4 @@
package bitcask package internal
import ( import (
"fmt" "fmt"

View File

@@ -6,37 +6,42 @@ const (
DefaultMaxValueSize = 1 << 16 // 65KB DefaultMaxValueSize = 1 << 16 // 65KB
) )
type Options struct { // Option ...
type Option option
type option func(*config) error
type config struct {
MaxDatafileSize int MaxDatafileSize int
MaxKeySize int MaxKeySize int
MaxValueSize int MaxValueSize int
} }
func NewDefaultOptions() Options { func NewDefaultConfig() *config {
return Options{ return &config{
MaxDatafileSize: DefaultMaxDatafileSize, MaxDatafileSize: DefaultMaxDatafileSize,
MaxKeySize: DefaultMaxKeySize, MaxKeySize: DefaultMaxKeySize,
MaxValueSize: DefaultMaxValueSize, MaxValueSize: DefaultMaxValueSize,
} }
} }
func WithMaxDatafileSize(size int) func(*Bitcask) error { func WithMaxDatafileSize(size int) option {
return func(b *Bitcask) error { return func(cfg *config) error {
b.opts.MaxDatafileSize = size cfg.MaxDatafileSize = size
return nil return nil
} }
} }
func WithMaxKeySize(size int) func(*Bitcask) error { func WithMaxKeySize(size int) option {
return func(b *Bitcask) error { return func(cfg *config) error {
b.opts.MaxKeySize = size cfg.MaxKeySize = size
return nil return nil
} }
} }
func WithMaxValueSize(size int) func(*Bitcask) error { func WithMaxValueSize(size int) option {
return func(b *Bitcask) error { return func(cfg *config) error {
b.opts.MaxValueSize = size cfg.MaxValueSize = size
return nil return nil
} }
} }