From 9bd2b82caf865b8aa4364f72ab6c8ec79ecf9a12 Mon Sep 17 00:00:00 2001 From: Karan Sharma Date: Wed, 7 Dec 2022 09:36:30 +0530 Subject: [PATCH] feat: add more handlers --- cmd/server/config.toml | 3 +++ cmd/server/handlers.go | 45 ++++++++++++++++++++++++++++++++++++++++++ cmd/server/main.go | 4 +++- go.mod | 1 + go.sum | 6 ++++++ pkg/barrel/barrel.go | 33 ++++++++++++++++++++++++------- pkg/barrel/gc.go | 2 +- pkg/barrel/merge.go | 3 +-- 8 files changed, 86 insertions(+), 11 deletions(-) diff --git a/cmd/server/config.toml b/cmd/server/config.toml index 76efb65..2b9abc4 100644 --- a/cmd/server/config.toml +++ b/cmd/server/config.toml @@ -1,2 +1,5 @@ [server] address = ":6379" + +[app] +debug = true \ No newline at end of file diff --git a/cmd/server/handlers.go b/cmd/server/handlers.go index 1b7ea42..9bf67f5 100644 --- a/cmd/server/handlers.go +++ b/cmd/server/handlers.go @@ -48,3 +48,48 @@ func (app *App) get(conn redcon.Conn, cmd redcon.Command) { conn.WriteBulk(val) } + +func (app *App) delete(conn redcon.Conn, cmd redcon.Command) { + if len(cmd.Args) != 2 { + conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command") + return + } + var ( + key = string(cmd.Args[1]) + ) + err := app.barrel.Delete(key) + if err != nil { + conn.WriteString(fmt.Sprintf("ERR: %s", err)) + return + } + + conn.WriteNull() +} + +func (app *App) keys(conn redcon.Conn, cmd redcon.Command) { + if len(cmd.Args) != 2 { + conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command") + return + } + var ( + key = string(cmd.Args[1]) + ) + + // Only supports listing all keys for now. + if key != "*" { + conn.WriteError("ERR: Only * is supported as a pattern for now'") + return + } + + keys := app.barrel.List() + + if len(keys) == 0 { + conn.WriteArray(0) + return + } + + for _, k := range keys { + conn.WriteBulkString(k) + } + +} diff --git a/cmd/server/main.go b/cmd/server/main.go index ae022bf..02d90e7 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -25,6 +25,7 @@ func main() { ReadOnly: false, EnableFSync: true, MaxFileSize: 1 << 4, + Debug: true, }) if err != nil { lo.Fatal("error opening barrel db: %w", err) @@ -39,7 +40,8 @@ func main() { mux.HandleFunc("quit", app.quit) mux.HandleFunc("set", app.set) mux.HandleFunc("get", app.get) - // mux.HandleFunc("del", app.delete) + mux.HandleFunc("del", app.delete) + mux.HandleFunc("keys", app.keys) err = redcon.ListenAndServe(addr, mux.ServeRESP, diff --git a/go.mod b/go.mod index caa4938..a63cb1e 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.19 require ( github.com/tidwall/redcon v1.6.0 + github.com/zerodha/logf v0.5.5 golang.org/x/sys v0.2.0 ) diff --git a/go.sum b/go.sum index 38b54e6..ea44b61 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,14 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/tidwall/btree v1.1.0 h1:5P+9WU8ui5uhmcg3SoPyTwoI0mVyZ1nps7YQzTZFkYM= github.com/tidwall/btree v1.1.0/go.mod h1:TzIRzen6yHbibdSfK6t8QimqbUnoxUSrZfeW7Uob0q4= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/redcon v1.6.0 h1:ekkYf2xwk1+VmyTVrefZElJC71EK/1JOLwlGSllmPIk= github.com/tidwall/redcon v1.6.0/go.mod h1:p5Wbsgeyi2VSTBWOcA5vRXrOb9arFTcU2+ZzFjqV75Y= +github.com/zerodha/logf v0.5.5 h1:AhxHlixHNYwhFjvlgTv6uO4VBKYKxx2I6SbHoHtWLBk= +github.com/zerodha/logf v0.5.5/go.mod h1:HWpfKsie+WFFpnUnUxelT6Z0FC6xu9+qt+oXNMPg6y8= golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/pkg/barrel/barrel.go b/pkg/barrel/barrel.go index 7d2c528..ba7c2ab 100644 --- a/pkg/barrel/barrel.go +++ b/pkg/barrel/barrel.go @@ -2,12 +2,12 @@ package barrel import ( "fmt" - "log" "os" "sync" "time" "github.com/mr-karan/barreldb/internal/datafile" + "github.com/zerodha/logf" ) const ( @@ -17,7 +17,7 @@ const ( type Barrel struct { sync.Mutex - lo *log.Logger + lo logf.Logger opts Opts // Options for managing datafile. keydir KeyDir // In-memory hashmap of all active keys. @@ -29,6 +29,7 @@ type Barrel struct { // Opts represents configuration options for managing a datastore. type Opts struct { + Debug bool // Enable debug logging. Dir string // Path for storing data files. ReadOnly bool // Whether this datastore should be opened in a read-only mode. Only one process at a time can open it in R-W mode. MergeInterval time.Duration // Interval to compact old files. @@ -36,12 +37,21 @@ type Opts struct { EnableFSync bool // Should flush filesystem buffer after every right. } +// initLogger initializes logger instance. +func initLogger(debug bool) logf.Logger { + opts := logf.Opts{EnableCaller: true} + if debug { + opts.Level = logf.DebugLevel + } + return logf.New(opts) +} + // Init initialises a datastore for storing data. func Init(opts Opts) (*Barrel, error) { // TODO: Check for stale files and create an index automatically. var ( - lo = log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile) + lo = initLogger(opts.Debug) index = 0 ) @@ -76,10 +86,10 @@ func Init(opts Opts) (*Barrel, error) { } // Spawn a goroutine which runs in background and compacts all datafiles in a new single datafile. - if opts.MergeInterval == time.Second*0 { - // TODO: Add a sane default later. - opts.MergeInterval = time.Second * 5 - } + // if opts.MergeInterval == time.Second*0 { + // // TODO: Add a sane default later. + // opts.MergeInterval = time.Second * 5 + // } // go barrel.MergeFiles(opts.MergeInterval) // // Spawn a goroutine which checks for the file size of the active file at periodic interval. // go barrel.ExamineFileSize(time.Minute * 1) @@ -111,6 +121,8 @@ func (b *Barrel) Put(k string, val []byte) error { return fmt.Errorf("put operation now allowed in read-only mode") } + b.lo.Debug("adding key", "key", k, "val", val) + return b.put(k, val, nil) } @@ -156,10 +168,17 @@ func (b *Barrel) List() []string { b.Lock() defer b.Unlock() + b.lo.Debug("fetching list of all keys") + keys := make([]string, len(b.keydir)) + + b.lo.Debug("reached 1") + for k := range b.keydir { keys = append(keys, k) } + b.lo.Debug("reached 2") + return keys } diff --git a/pkg/barrel/gc.go b/pkg/barrel/gc.go index 00d5331..c10044a 100644 --- a/pkg/barrel/gc.go +++ b/pkg/barrel/gc.go @@ -17,7 +17,7 @@ func (b *Barrel) ExamineFileSize(evalInterval time.Duration) { ) for range evalTicker { if err := b.rotateDF(); err != nil { - b.lo.Printf("error rotating db file: %s\n", err) + b.lo.Error("error rotating db file", "error", err) } } } diff --git a/pkg/barrel/merge.go b/pkg/barrel/merge.go index 2078449..aa9899a 100644 --- a/pkg/barrel/merge.go +++ b/pkg/barrel/merge.go @@ -20,7 +20,7 @@ func (b *Barrel) MergeFiles(evalInterval time.Duration) { ) for range evalTicker { if err := b.Merge(); err != nil { - b.lo.Printf("error merging files: %s\n", err) + b.lo.Error("error merging files", "error", err) } } } @@ -59,7 +59,6 @@ func (b *Barrel) Merge() error { // Since the keydir has updated values of all keys, all the old keys which are expired/deleted/overwritten // will be cleaned up in the merged database. for k := range b.keydir { - fmt.Println("putting keys", k) val, err := b.get(k) if err != nil { return err