mirror of
https://github.com/gogrlx/bitcask.git
synced 2026-04-04 12:02:46 -07:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0c913ccee | ||
|
|
6b372d8334 | ||
|
|
3c1808cad3 | ||
|
|
5d1dd6657a | ||
|
|
1ba9ca46e3 | ||
|
|
2a419c46d2 | ||
|
|
e543fc38fb | ||
|
|
82e26449fa | ||
|
|
bce2721be4 | ||
|
|
f2b5515e03 | ||
|
|
8b684b635d |
13
AUTHORS
Normal file
13
AUTHORS
Normal file
@@ -0,0 +1,13 @@
|
||||
# Entries should be added alphabetically in the form:
|
||||
# Name or Organization <email address>
|
||||
# The email address is not required for organizations.
|
||||
|
||||
Awn Umar <awn@spacetime.dev>
|
||||
Christian Muehlhaeuser <muesli@gmail.com>
|
||||
Ignacio Hagopian <jsign.uy@gmail.com>
|
||||
James Mills <prologic@shortcircuit.net.au>
|
||||
Jesse Donat <donatj@gmail.com>
|
||||
Kebert Xela kebertxela
|
||||
panyun panyun
|
||||
Whemoon Jang <palindrom615@gmail.com>
|
||||
Yury Fedorov orlangure
|
||||
@@ -1,8 +1,12 @@
|
||||
# Contributing
|
||||
|
||||
No preference. If you know hot to use Github and contributed to open source projects before then:
|
||||
No preference. If you know how to use Github and have contributed to open source projects before then:
|
||||
|
||||
* File an issue
|
||||
* Submit a pull request
|
||||
* File an issue + Submit a pull request
|
||||
* Use this project somewhere :)
|
||||
|
||||
Be sure to add yourself to the [AUTHORS](/AUTHORS) file when you submit your PR(s). Every contribution counts no how big or small!
|
||||
|
||||
Thanks for using Bitcask!
|
||||
|
||||
66
README.md
66
README.md
@@ -128,36 +128,56 @@ Benchmarks run on a 11" Macbook with a 1.4Ghz Intel Core i7:
|
||||
```#!sh
|
||||
$ make bench
|
||||
...
|
||||
BenchmarkGet/128B-4 300000 4071 ns/op 31.43 MB/s 608 B/op 7 allocs/op
|
||||
BenchmarkGet/256B-4 300000 4700 ns/op 54.46 MB/s 992 B/op 7 allocs/op
|
||||
BenchmarkGet/512B-4 300000 4915 ns/op 104.17 MB/s 1824 B/op 7 allocs/op
|
||||
BenchmarkGet/1K-4 200000 5064 ns/op 202.20 MB/s 3488 B/op 7 allocs/op
|
||||
BenchmarkGet/2K-4 200000 6276 ns/op 326.31 MB/s 6816 B/op 7 allocs/op
|
||||
BenchmarkGet/4K-4 200000 8960 ns/op 457.11 MB/s 13984 B/op 7 allocs/op
|
||||
BenchmarkGet/8K-4 100000 12465 ns/op 657.16 MB/s 27296 B/op 7 allocs/op
|
||||
BenchmarkGet/16K-4 100000 19233 ns/op 851.84 MB/s 53408 B/op 7 allocs/op
|
||||
BenchmarkGet/32K-4 50000 33106 ns/op 989.77 MB/s 114848 B/op 7 allocs/op
|
||||
goos: darwin
|
||||
goarch: amd64
|
||||
pkg: github.com/prologic/bitcask
|
||||
|
||||
BenchmarkPut/128B-4 100000 13659 ns/op 9.37 MB/s 409 B/op 6 allocs/op
|
||||
BenchmarkPut/256B-4 100000 14854 ns/op 17.23 MB/s 539 B/op 6 allocs/op
|
||||
BenchmarkPut/512B-4 100000 20823 ns/op 24.59 MB/s 829 B/op 6 allocs/op
|
||||
BenchmarkPut/1K-4 50000 28086 ns/op 36.46 MB/s 1411 B/op 6 allocs/op
|
||||
BenchmarkPut/2K-4 30000 40797 ns/op 50.20 MB/s 2574 B/op 6 allocs/op
|
||||
BenchmarkPut/4K-4 20000 75518 ns/op 54.24 MB/s 5155 B/op 6 allocs/op
|
||||
BenchmarkPut/8K-4 10000 122544 ns/op 66.85 MB/s 9811 B/op 6 allocs/op
|
||||
BenchmarkPut/16K-4 10000 201167 ns/op 81.44 MB/s 18851 B/op 6 allocs/op
|
||||
BenchmarkPut/32K-4 5000 350850 ns/op 93.40 MB/s 41565 B/op 7 allocs/op
|
||||
BenchmarkGet/128B-4 300000 3913 ns/op 32.71 MB/s 387 B/op 4 allocs/op
|
||||
BenchmarkGet/128BWithPool-4 300000 4143 ns/op 30.89 MB/s 227 B/op 3 allocs/op
|
||||
BenchmarkGet/256B-4 300000 3919 ns/op 65.31 MB/s 643 B/op 4 allocs/op
|
||||
BenchmarkGet/256BWithPool-4 300000 4270 ns/op 59.95 MB/s 355 B/op 3 allocs/op
|
||||
BenchmarkGet/512B-4 300000 4248 ns/op 120.52 MB/s 1187 B/op 4 allocs/op
|
||||
BenchmarkGet/512BWithPool-4 300000 4676 ns/op 109.48 MB/s 611 B/op 3 allocs/op
|
||||
BenchmarkGet/1K-4 200000 5248 ns/op 195.10 MB/s 2275 B/op 4 allocs/op
|
||||
BenchmarkGet/1KWithPool-4 200000 5270 ns/op 194.28 MB/s 1123 B/op 3 allocs/op
|
||||
BenchmarkGet/2K-4 200000 6229 ns/op 328.74 MB/s 4451 B/op 4 allocs/op
|
||||
BenchmarkGet/2KWithPool-4 200000 6282 ns/op 325.99 MB/s 2147 B/op 3 allocs/op
|
||||
BenchmarkGet/4K-4 200000 9027 ns/op 453.74 MB/s 9059 B/op 4 allocs/op
|
||||
BenchmarkGet/4KWithPool-4 200000 8906 ns/op 459.87 MB/s 4195 B/op 3 allocs/op
|
||||
BenchmarkGet/8K-4 100000 12024 ns/op 681.28 MB/s 17763 B/op 4 allocs/op
|
||||
BenchmarkGet/8KWithPool-4 200000 11103 ns/op 737.79 MB/s 8291 B/op 3 allocs/op
|
||||
BenchmarkGet/16K-4 100000 16844 ns/op 972.65 MB/s 34915 B/op 4 allocs/op
|
||||
BenchmarkGet/16KWithPool-4 100000 14575 ns/op 1124.10 MB/s 16483 B/op 3 allocs/op
|
||||
BenchmarkGet/32K-4 50000 27770 ns/op 1179.97 MB/s 73827 B/op 4 allocs/op
|
||||
BenchmarkGet/32KWithPool-4 100000 24495 ns/op 1337.74 MB/s 32867 B/op 3 allocs/op
|
||||
|
||||
BenchmarkScan-4 1000000 1867 ns/op 493 B/op 25 allocs/op
|
||||
BenchmarkPut/128B-4 100000 17492 ns/op 7.32 MB/s 441 B/op 6 allocs/op
|
||||
BenchmarkPut/256B-4 100000 17234 ns/op 14.85 MB/s 571 B/op 6 allocs/op
|
||||
BenchmarkPut/512B-4 100000 22837 ns/op 22.42 MB/s 861 B/op 6 allocs/op
|
||||
BenchmarkPut/1K-4 50000 30333 ns/op 33.76 MB/s 1443 B/op 6 allocs/op
|
||||
BenchmarkPut/2K-4 30000 45304 ns/op 45.21 MB/s 2606 B/op 6 allocs/op
|
||||
BenchmarkPut/4K-4 20000 83953 ns/op 48.79 MB/s 5187 B/op 6 allocs/op
|
||||
BenchmarkPut/8K-4 10000 142142 ns/op 57.63 MB/s 9845 B/op 6 allocs/op
|
||||
BenchmarkPut/16K-4 5000 206722 ns/op 79.26 MB/s 18884 B/op 6 allocs/op
|
||||
BenchmarkPut/32K-4 5000 361108 ns/op 90.74 MB/s 41582 B/op 7 allocs/op
|
||||
|
||||
BenchmarkScan-4 1000000 1679 ns/op 408 B/op 16 allocs/op
|
||||
PASS
|
||||
```
|
||||
|
||||
For 128B values:
|
||||
|
||||
* ~400,000 reads/sec
|
||||
* ~130,000 writes/sec
|
||||
* ~200,000 reads/sec
|
||||
* ~50,000 writes/sec
|
||||
|
||||
The full benchmark above shows linear performance as you increase key/value sizes.
|
||||
The full benchmark above shows linear performance as you increase key/value sizes. Memory pooling starts to become advantageous for larger values.
|
||||
|
||||
## Contributors
|
||||
|
||||
Thank you to all those that have contributed to this project, battle-tested it, used it in their own projects or pdocuts, fixed bugs, improved performance and even fix tiny tpyos in documentation! Thank you and keep contirbuting!
|
||||
|
||||
You can find an [AUTHORS](/AUTHORS) file where we keep a list of contributors to the project. If you contriibute a PR please consider adding your name there. There is also Github's own [Contributors](https://github.com/prologic/bitcask/graphs/contributors) statistics.
|
||||
|
||||
## License
|
||||
|
||||
bitcask is licensed under the [MIT License](https://github.com/prologic/bitcask/blob/master/LICENSE)
|
||||
bitcask is licensed under the term of the [MIT License](https://github.com/prologic/bitcask/blob/master/LICENSE)
|
||||
|
||||
41
bitcask.go
41
bitcask.go
@@ -1,6 +1,7 @@
|
||||
package bitcask
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
@@ -10,8 +11,8 @@ import (
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/derekparker/trie"
|
||||
"github.com/gofrs/flock"
|
||||
"github.com/prologic/trie"
|
||||
|
||||
"github.com/prologic/bitcask/internal"
|
||||
)
|
||||
@@ -245,6 +246,28 @@ func (b *Bitcask) put(key string, value []byte) (int64, int64, error) {
|
||||
return b.curr.Write(e)
|
||||
}
|
||||
|
||||
func (b *Bitcask) readConfig() error {
|
||||
if internal.Exists(filepath.Join(b.path, "config.json")) {
|
||||
data, err := ioutil.ReadFile(filepath.Join(b.path, "config.json"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &b.config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Bitcask) writeConfig() error {
|
||||
data, err := json.Marshal(b.config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(filepath.Join(b.path, "config.json"), data, 0600)
|
||||
}
|
||||
|
||||
func (b *Bitcask) reopen() error {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
@@ -407,13 +430,23 @@ func (b *Bitcask) Merge() error {
|
||||
// Options can be provided with the `WithXXX` functions that provide
|
||||
// configuration options as functions.
|
||||
func Open(path string, options ...Option) (*Bitcask, error) {
|
||||
var (
|
||||
cfg *config
|
||||
err error
|
||||
)
|
||||
|
||||
if err := os.MkdirAll(path, 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg, err = getConfig(path)
|
||||
if err != nil {
|
||||
cfg = newDefaultConfig()
|
||||
}
|
||||
|
||||
bitcask := &Bitcask{
|
||||
Flock: flock.New(filepath.Join(path, "lock")),
|
||||
config: newDefaultConfig(),
|
||||
config: cfg,
|
||||
options: options,
|
||||
path: path,
|
||||
}
|
||||
@@ -435,6 +468,10 @@ func Open(path string, options ...Option) (*Bitcask, error) {
|
||||
return nil, ErrDatabaseLocked
|
||||
}
|
||||
|
||||
if err := bitcask.writeConfig(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := bitcask.reopen(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
142
cmd/bitcask/export.go
Normal file
142
cmd/bitcask/export.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/prologic/bitcask"
|
||||
)
|
||||
|
||||
var errNotAllDataWritten = errors.New("error: not all data written")
|
||||
|
||||
var exportCmd = &cobra.Command{
|
||||
Use: "export",
|
||||
Aliases: []string{"backup", "dump"},
|
||||
Short: "Export a database",
|
||||
Long: `This command allows you to export or dump/backup a database's
|
||||
key/values into a long-term portable archival format suitable for backup and
|
||||
restore purposes or migrating from older on-disk formats of Bitcask.
|
||||
|
||||
All key/value pairs are base64 encoded and serialized as JSON one pair per
|
||||
line to form an output stream to either standard output or a file. You can
|
||||
optionally compress the output with standard compression tools such as gzip.`,
|
||||
Args: cobra.RangeArgs(0, 1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var output string
|
||||
|
||||
path := viper.GetString("path")
|
||||
|
||||
if len(args) == 1 {
|
||||
output = args[0]
|
||||
} else {
|
||||
output = "-"
|
||||
}
|
||||
|
||||
os.Exit(export(path, output))
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(exportCmd)
|
||||
|
||||
exportCmd.PersistentFlags().IntP(
|
||||
"with-max-datafile-size", "", bitcask.DefaultMaxDatafileSize,
|
||||
"Maximum size of each datafile",
|
||||
)
|
||||
exportCmd.PersistentFlags().IntP(
|
||||
"with-max-key-size", "", bitcask.DefaultMaxKeySize,
|
||||
"Maximum size of each key",
|
||||
)
|
||||
exportCmd.PersistentFlags().IntP(
|
||||
"with-max-value-size", "", bitcask.DefaultMaxValueSize,
|
||||
"Maximum size of each value",
|
||||
)
|
||||
}
|
||||
|
||||
type kvPair struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
func export(path, output string) int {
|
||||
var (
|
||||
err error
|
||||
w io.WriteCloser
|
||||
)
|
||||
|
||||
db, err := bitcask.Open(path)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error opening database")
|
||||
return 1
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
if output == "-" {
|
||||
w = os.Stdout
|
||||
} else {
|
||||
w, err = os.OpenFile(output, os.O_WRONLY|os.O_CREATE|os.O_EXCL|os.O_TRUNC, 0755)
|
||||
if err != nil {
|
||||
log.WithError(err).
|
||||
WithField("output", output).
|
||||
Error("error opening output for writing")
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
err = db.Fold(func(key string) error {
|
||||
value, err := db.Get(key)
|
||||
if err != nil {
|
||||
log.WithError(err).
|
||||
WithField("key", key).
|
||||
Error("error reading key")
|
||||
return err
|
||||
}
|
||||
|
||||
kv := kvPair{
|
||||
Key: base64.StdEncoding.EncodeToString([]byte(key)),
|
||||
Value: base64.StdEncoding.EncodeToString(value),
|
||||
}
|
||||
|
||||
data, err := json.Marshal(&kv)
|
||||
if err != nil {
|
||||
log.WithError(err).
|
||||
WithField("key", key).
|
||||
Error("error serialzing key")
|
||||
return err
|
||||
}
|
||||
|
||||
if n, err := w.Write(data); err != nil || n != len(data) {
|
||||
if err == nil && n != len(data) {
|
||||
err = errNotAllDataWritten
|
||||
}
|
||||
log.WithError(err).
|
||||
WithField("key", key).
|
||||
WithField("n", n).
|
||||
Error("error writing key")
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := w.Write([]byte("\n")); err != nil {
|
||||
log.WithError(err).Error("error writing newline")
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.WithError(err).
|
||||
WithField("path", path).
|
||||
WithField("output", output).
|
||||
Error("error exporting keys")
|
||||
return 2
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
106
cmd/bitcask/import.go
Normal file
106
cmd/bitcask/import.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/prologic/bitcask"
|
||||
)
|
||||
|
||||
var importCmd = &cobra.Command{
|
||||
Use: "import",
|
||||
Aliases: []string{"restore", "read"},
|
||||
Short: "Import a database",
|
||||
Long: `This command allows you to import or restore a database from a
|
||||
previous export/dump using the export command either creating a new database
|
||||
or adding additional key/value pairs to an existing one.`,
|
||||
Args: cobra.RangeArgs(0, 1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var input string
|
||||
|
||||
path := viper.GetString("path")
|
||||
|
||||
if len(args) == 1 {
|
||||
input = args[0]
|
||||
} else {
|
||||
input = "-"
|
||||
}
|
||||
|
||||
os.Exit(_import(path, input))
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(importCmd)
|
||||
}
|
||||
|
||||
func _import(path, input string) int {
|
||||
var (
|
||||
err error
|
||||
r io.ReadCloser
|
||||
)
|
||||
|
||||
db, err := bitcask.Open(path)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error opening database")
|
||||
return 1
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
if input == "-" {
|
||||
r = os.Stdin
|
||||
} else {
|
||||
r, err = os.Open(input)
|
||||
if err != nil {
|
||||
log.WithError(err).
|
||||
WithField("input", input).
|
||||
Error("error opening input for reading")
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
var kv kvPair
|
||||
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
if err := json.Unmarshal(scanner.Bytes(), &kv); err != nil {
|
||||
log.WithError(err).
|
||||
WithField("input", input).
|
||||
Error("error reading input")
|
||||
return 2
|
||||
}
|
||||
|
||||
key, err := base64.StdEncoding.DecodeString(kv.Key)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error decoding key")
|
||||
return 2
|
||||
}
|
||||
|
||||
value, err := base64.StdEncoding.DecodeString(kv.Value)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error decoding value")
|
||||
return 2
|
||||
}
|
||||
|
||||
if err := db.Put(string(key), value); err != nil {
|
||||
log.WithError(err).Error("error writing key/value")
|
||||
return 2
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.WithError(err).
|
||||
WithField("input", input).
|
||||
Error("error reading input")
|
||||
return 2
|
||||
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
67
cmd/bitcask/initdb.go
Normal file
67
cmd/bitcask/initdb.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/prologic/bitcask"
|
||||
)
|
||||
|
||||
var initdbCmd = &cobra.Command{
|
||||
Use: "initdb",
|
||||
Aliases: []string{"create", "init"},
|
||||
Short: "Initialize a new database",
|
||||
Long: `This initializes a new database with persisted options`,
|
||||
Args: cobra.ExactArgs(0),
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
viper.BindPFlag("with-max-datafile-size", cmd.Flags().Lookup("with-max-datafile-size"))
|
||||
viper.SetDefault("with-max-datafile-size", bitcask.DefaultMaxDatafileSize)
|
||||
|
||||
viper.BindPFlag("with-max-key-size", cmd.Flags().Lookup("with-max-key-size"))
|
||||
viper.SetDefault("with-max-key-size", bitcask.DefaultMaxKeySize)
|
||||
|
||||
viper.BindPFlag("with-max-value-size", cmd.Flags().Lookup("with-max-value-size"))
|
||||
viper.SetDefault("with-max-value-size", bitcask.DefaultMaxValueSize)
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
path := viper.GetString("path")
|
||||
|
||||
maxDatafileSize := viper.GetInt("with-max-datafile-size")
|
||||
maxKeySize := viper.GetInt("with-max-key-size")
|
||||
maxValueSize := viper.GetInt("with-max-value-size")
|
||||
|
||||
db, err := bitcask.Open(
|
||||
path,
|
||||
bitcask.WithMaxDatafileSize(maxDatafileSize),
|
||||
bitcask.WithMaxKeySize(maxKeySize),
|
||||
bitcask.WithMaxValueSize(maxValueSize),
|
||||
)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error opening database")
|
||||
os.Exit(1)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
os.Exit(0)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(initdbCmd)
|
||||
|
||||
initdbCmd.PersistentFlags().IntP(
|
||||
"with-max-datafile-size", "", bitcask.DefaultMaxDatafileSize,
|
||||
"Maximum size of each datafile",
|
||||
)
|
||||
initdbCmd.PersistentFlags().IntP(
|
||||
"with-max-key-size", "", bitcask.DefaultMaxKeySize,
|
||||
"Maximum size of each key",
|
||||
)
|
||||
initdbCmd.PersistentFlags().IntP(
|
||||
"with-max-value-size", "", bitcask.DefaultMaxValueSize,
|
||||
"Maximum size of each value",
|
||||
)
|
||||
}
|
||||
@@ -13,11 +13,11 @@ import (
|
||||
"github.com/prologic/bitcask"
|
||||
)
|
||||
|
||||
var setCmd = &cobra.Command{
|
||||
Use: "set <key> [<value>]",
|
||||
Aliases: []string{"add"},
|
||||
Short: "Add/Set a new Key/Value pair",
|
||||
Long: `This adds or sets a new key/value pair.
|
||||
var putCmd = &cobra.Command{
|
||||
Use: "put <key> [<value>]",
|
||||
Aliases: []string{"add", "set", "store"},
|
||||
Short: "Adds a new Key/Value pair",
|
||||
Long: `This adds a new key/value pair or modifies an existing one.
|
||||
|
||||
If the value is not specified as an argument it is read from standard input.`,
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
@@ -33,15 +33,15 @@ If the value is not specified as an argument it is read from standard input.`,
|
||||
value = os.Stdin
|
||||
}
|
||||
|
||||
os.Exit(set(path, key, value))
|
||||
os.Exit(put(path, key, value))
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(setCmd)
|
||||
RootCmd.AddCommand(putCmd)
|
||||
}
|
||||
|
||||
func set(path, key string, value io.Reader) int {
|
||||
func put(path, key string, value io.Reader) int {
|
||||
db, err := bitcask.Open(path)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error opening database")
|
||||
2
go.mod
2
go.mod
@@ -1,6 +1,7 @@
|
||||
module github.com/prologic/bitcask
|
||||
|
||||
require (
|
||||
github.com/derekparker/trie v0.0.0-20190805173922-4e1a77fb815d
|
||||
github.com/gofrs/flock v0.7.1
|
||||
github.com/gogo/protobuf v1.2.1
|
||||
github.com/golang/protobuf v1.3.2
|
||||
@@ -9,7 +10,6 @@ require (
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c
|
||||
github.com/pelletier/go-toml v1.4.0 // indirect
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/prologic/trie v0.0.0-20190322091023-3972df81f9b5
|
||||
github.com/sirupsen/logrus v1.4.2
|
||||
github.com/spf13/afero v1.2.2 // indirect
|
||||
github.com/spf13/cobra v0.0.5
|
||||
|
||||
4
go.sum
4
go.sum
@@ -21,6 +21,8 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/derekparker/trie v0.0.0-20190805173922-4e1a77fb815d h1:TocZO8frNoxkwqFPePHFldSw8vLu+gBrlvFZYWqxiF4=
|
||||
github.com/derekparker/trie v0.0.0-20190805173922-4e1a77fb815d/go.mod h1:D6ICZm05D9VN1n/8iOtBxLpXtoGp6HDFUJ1RNVieOSE=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
@@ -88,8 +90,6 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prologic/trie v0.0.0-20190322091023-3972df81f9b5 h1:H8dTZzU3aWNQnuRyiT45J9szv7EFakAhFzsFq27t3Uo=
|
||||
github.com/prologic/trie v0.0.0-20190322091023-3972df81f9b5/go.mod h1:LFuDmpHJGmciXd8Rl5YMhVlLMps9gz2GtYLzwxrFhzs=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
|
||||
44
options.go
44
options.go
@@ -1,6 +1,11 @@
|
||||
package bitcask
|
||||
|
||||
import "errors"
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultMaxDatafileSize is the default maximum datafile size in bytes
|
||||
@@ -29,6 +34,43 @@ type config struct {
|
||||
maxConcurrency *int
|
||||
}
|
||||
|
||||
func (c *config) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
MaxDatafileSize int `json:"max_datafile_size"`
|
||||
MaxKeySize int `json:"max_key_size"`
|
||||
MaxValueSize int `json:"max_value_size"`
|
||||
}{
|
||||
MaxDatafileSize: c.maxDatafileSize,
|
||||
MaxKeySize: c.maxKeySize,
|
||||
MaxValueSize: c.maxValueSize,
|
||||
})
|
||||
}
|
||||
|
||||
func getConfig(path string) (*config, error) {
|
||||
type Config struct {
|
||||
MaxDatafileSize int `json:"max_datafile_size"`
|
||||
MaxKeySize int `json:"max_key_size"`
|
||||
MaxValueSize int `json:"max_value_size"`
|
||||
}
|
||||
|
||||
var cfg Config
|
||||
|
||||
data, err := ioutil.ReadFile(filepath.Join(path, "config.json"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &config{
|
||||
maxDatafileSize: cfg.MaxDatafileSize,
|
||||
maxKeySize: cfg.MaxKeySize,
|
||||
maxValueSize: cfg.MaxValueSize,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func newDefaultConfig() *config {
|
||||
return &config{
|
||||
maxDatafileSize: DefaultMaxDatafileSize,
|
||||
|
||||
Reference in New Issue
Block a user