Adds WithSync(...) option to turn on sync after write durability (#63)

* Added WithSync(...) option to turn  on sync after write durability

* Add Sync/NoSync benchmark variants for Put()
This commit is contained in:
James Mills 2019-08-12 06:47:46 +10:00 committed by GitHub
parent 8f56cffd86
commit c5a565cd82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 30 deletions

@ -155,6 +155,12 @@ func (b *Bitcask) Put(key, value []byte) error {
return err return err
} }
if b.config.sync {
if err := b.curr.Sync(); err != nil {
return err
}
}
item := b.keydir.Add(key, b.curr.FileID(), offset, n) item := b.keydir.Add(key, b.curr.FileID(), offset, n)
b.trie.Add(string(key), item) b.trie.Add(string(key), item)

@ -566,18 +566,6 @@ func BenchmarkPut(b *testing.B) {
b.Fatal(err) b.Fatal(err)
} }
testdir, err := ioutil.TempDir(currentDir, "bitcask_bench")
if err != nil {
b.Fatal(err)
}
defer os.RemoveAll(testdir)
db, err := Open(testdir)
if err != nil {
b.Fatal(err)
}
defer db.Close()
tests := []benchmarkTestCase{ tests := []benchmarkTestCase{
{"128B", 128}, {"128B", 128},
{"256B", 256}, {"256B", 256},
@ -589,20 +577,43 @@ func BenchmarkPut(b *testing.B) {
{"32K", 32768}, {"32K", 32768},
} }
for _, tt := range tests { variants := map[string][]Option{
b.Run(tt.name, func(b *testing.B) { "NoSync": []Option{
b.SetBytes(int64(tt.size)) WithSync(false),
},
"Sync": []Option{
WithSync(true),
},
}
key := []byte("foo") for name, options := range variants {
value := []byte(strings.Repeat(" ", tt.size)) testdir, err := ioutil.TempDir(currentDir, "bitcask_bench")
b.ResetTimer() if err != nil {
for i := 0; i < b.N; i++ { b.Fatal(err)
err := db.Put(key, value) }
if err != nil { defer os.RemoveAll(testdir)
b.Fatal(err)
db, err := Open(testdir, options...)
if err != nil {
b.Fatal(err)
}
defer db.Close()
for _, tt := range tests {
b.Run(tt.name+name, func(b *testing.B) {
b.SetBytes(int64(tt.size))
key := []byte("foo")
value := []byte(strings.Repeat(" ", tt.size))
b.ResetTimer()
for i := 0; i < b.N; i++ {
err := db.Put(key, value)
if err != nil {
b.Fatal(err)
}
} }
} })
}) }
} }
} }

@ -24,25 +24,29 @@ type config struct {
maxDatafileSize int maxDatafileSize int
maxKeySize int maxKeySize int
maxValueSize int maxValueSize int
sync bool
} }
func (c *config) MarshalJSON() ([]byte, error) { func (c *config) MarshalJSON() ([]byte, error) {
return json.Marshal(struct { return json.Marshal(struct {
MaxDatafileSize int `json:"max_datafile_size"` MaxDatafileSize int `json:"max_datafile_size"`
MaxKeySize int `json:"max_key_size"` MaxKeySize int `json:"max_key_size"`
MaxValueSize int `json:"max_value_size"` MaxValueSize int `json:"max_value_size"`
Sync bool `json:"sync"`
}{ }{
MaxDatafileSize: c.maxDatafileSize, MaxDatafileSize: c.maxDatafileSize,
MaxKeySize: c.maxKeySize, MaxKeySize: c.maxKeySize,
MaxValueSize: c.maxValueSize, MaxValueSize: c.maxValueSize,
Sync: c.sync,
}) })
} }
func getConfig(path string) (*config, error) { func getConfig(path string) (*config, error) {
type Config struct { type Config struct {
MaxDatafileSize int `json:"max_datafile_size"` MaxDatafileSize int `json:"max_datafile_size"`
MaxKeySize int `json:"max_key_size"` MaxKeySize int `json:"max_key_size"`
MaxValueSize int `json:"max_value_size"` MaxValueSize int `json:"max_value_size"`
Sync bool `json:"sync"`
} }
var cfg Config var cfg Config
@ -60,6 +64,7 @@ func getConfig(path string) (*config, error) {
maxDatafileSize: cfg.MaxDatafileSize, maxDatafileSize: cfg.MaxDatafileSize,
maxKeySize: cfg.MaxKeySize, maxKeySize: cfg.MaxKeySize,
maxValueSize: cfg.MaxValueSize, maxValueSize: cfg.MaxValueSize,
sync: cfg.Sync,
}, nil }, nil
} }
@ -94,3 +99,12 @@ func WithMaxValueSize(size int) Option {
return nil return nil
} }
} }
// WithSync causes Sync() to be called on every key/value written increasing
// durability and saftey at the expense of performance
func WithSync(sync bool) Option {
return func(cfg *config) error {
cfg.sync = sync
return nil
}
}