Skip to content

Commit

Permalink
Implement DBSIZE command (#159)
Browse files Browse the repository at this point in the history
Implement DBSIZE Command - @NicoleStrel
  • Loading branch information
NicoleStrel authored Jan 6, 2025
1 parent 108bf97 commit 8f1330e
Show file tree
Hide file tree
Showing 11 changed files with 4,316 additions and 6,061 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ Benchmark script options:
<a name="commands-generic"></a>
## GENERIC
* [COPY](https://sugardb.io/docs/commands/generic/copy)
* [DBSIZE](https://sugardb.io/docs/commands/generic/dbsize)
* [DECR](https://sugardb.io/docs/commands/generic/decr)
* [DECRBY](https://sugardb.io/docs/commands/generic/decrby)
* [DEL](https://sugardb.io/docs/commands/generic/del)
Expand Down
10,205 changes: 4,147 additions & 6,058 deletions coverage/coverage.out

Large diffs are not rendered by default.

47 changes: 47 additions & 0 deletions docs/docs/commands/generic/dbsize.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# DBSIZE

### Syntax
```
DBSIZE
```

### Module
<span className="acl-category">generic</span>

### Categories
<span className="acl-category">fast</span>
<span className="acl-category">read</span>
<span className="acl-category">keyspace</span>

### Description
Return the number of keys in the currently-selected database.

### Examples

<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Get the number of keys in the database:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
key, err := db.DBSize()
```
</TabItem>
<TabItem value="cli">
Get the number of keys in the database:
```
> DBSIZE
```
</TabItem>
</Tabs>
15 changes: 15 additions & 0 deletions internal/modules/generic/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,11 @@ func handleRandomKey(params internal.HandlerFuncParams) ([]byte, error) {
return []byte(fmt.Sprintf("+%v\r\n", key)), nil
}

func handleDBSize(params internal.HandlerFuncParams) ([]byte, error) {
count := params.DBSize(params.Context)
return []byte(fmt.Sprintf(":%d\r\n", count)), nil
}

func handleGetdel(params internal.HandlerFuncParams) ([]byte, error) {
keys, err := getDelKeyFunc(params.Command)
if err != nil {
Expand Down Expand Up @@ -1285,6 +1290,16 @@ Delete all the keys in the currently selected database. This command is always s
KeyExtractionFunc: randomKeyFunc,
HandlerFunc: handleRandomKey,
},
{
Command: "dbsize",
Module: constants.GenericModule,
Categories: []string{constants.KeyspaceCategory, constants.ReadCategory, constants.FastCategory},
Description: "(DBSIZE) Return the number of keys in the currently selected database.",
Sync: false,
Type: "BUILT_IN",
KeyExtractionFunc: dbSizeKeyFunc,
HandlerFunc: handleDBSize,
},
{
Command: "getdel",
Module: constants.GenericModule,
Expand Down
39 changes: 39 additions & 0 deletions internal/modules/generic/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2909,6 +2909,45 @@ func Test_Generic(t *testing.T) {
}
})

t.Run("Test_HandleDBSIZE", func(t *testing.T) {
conn, err := internal.GetConnection("localhost", port)
if err != nil {
t.Error(err)
return
}
defer func() {
_ = conn.Close()
}()
client := resp.NewConn(conn)

// Populate the store with a few keys
expectedSize := 5
for i := 0; i < expectedSize; i++ {
_, _, err := mockServer.Set(
fmt.Sprintf("DBSizeKey%d", i),
fmt.Sprintf("Value%d", i),
sugardb.SETOptions{},
)
if err != nil {
t.Error(err)
return
}
}

if err = client.WriteArray([]resp.Value{resp.StringValue("DBSIZE")}); err != nil {
t.Error(err)
}

res, _, err := client.ReadValue()
if err != nil {
t.Error(err)
}

if res.Integer() != int(expectedSize) {
t.Errorf("expected dbsize %d, got %d", expectedSize, res.Integer())
}
})

t.Run("Test_HandleGETDEL", func(t *testing.T) {
t.Parallel()
conn, err := internal.GetConnection("localhost", port)
Expand Down
11 changes: 11 additions & 0 deletions internal/modules/generic/key_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,17 @@ func randomKeyFunc(cmd []string) (internal.KeyExtractionFuncResult, error) {
}, nil
}

func dbSizeKeyFunc(cmd []string) (internal.KeyExtractionFuncResult, error) {
if len(cmd) != 1 {
return internal.KeyExtractionFuncResult{}, errors.New(constants.WrongArgsResponse)
}
return internal.KeyExtractionFuncResult{
Channels: make([]string, 0),
ReadKeys: make([]string, 0),
WriteKeys: make([]string, 0),
}, nil
}

func getDelKeyFunc(cmd []string) (internal.KeyExtractionFuncResult, error) {
if len(cmd) != 2 {
return internal.KeyExtractionFuncResult{}, errors.New(constants.WrongArgsResponse)
Expand Down
2 changes: 2 additions & 0 deletions internal/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ type HandlerFuncParams struct {
Flush func(database int)
// RandomKey returns a random key
RandomKey func(ctx context.Context) string
// DBSize returns the number of keys in the currently selected database.
DBSize func(ctx context.Context) int
// (TOUCH key [key ...]) Alters the last access time or access count of the key(s)
// depending on whether LFU or LRU strategy was used.
// A key is ignored if it does not exist.
Expand Down
10 changes: 10 additions & 0 deletions sugardb/api_generic.go
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,16 @@ func (server *SugarDB) RandomKey() (string, error) {
return internal.ParseStringResponse(b)
}

// DBSize returns the number of keys in the currently-selected database.
// Returns: An integer number of keys
func (server *SugarDB) DBSize() (int, error) {
b, err := server.handleCommand(server.context, internal.EncodeCommand([]string{"DBSIZE"}), nil, false, true)
if err != nil {
return 0, err
}
return internal.ParseIntegerResponse(b)
}

// GetDel retrieves the value at the provided key and deletes that key.
//
// Parameters:
Expand Down
31 changes: 31 additions & 0 deletions sugardb/api_generic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1410,6 +1410,37 @@ func TestSugarDB_RANDOMKEY(t *testing.T) {

}

func TestSugarDB_DBSize(t *testing.T) {
server := createSugarDB()
got, err := server.DBSize()
if err != nil {
t.Error(err)
return
}
if got != 0 {
t.Errorf("DBSIZE error, expected 0, got %d", got)
}

// test with keys
testkeys := []string{"1", "2", "3"}
for _, k := range testkeys {
err := presetValue(server, context.Background(), k, "")
if err != nil {
t.Error(err)
return
}
}

got, err = server.DBSize()
if err != nil {
t.Error(err)
return
}
if got != len(testkeys) {
t.Errorf("DBSIZE error, expected %d, got %d", len(testkeys), got)
}
}

func TestSugarDB_GETDEL(t *testing.T) {
server := createSugarDB()

Expand Down
8 changes: 8 additions & 0 deletions sugardb/keyspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,14 @@ func (server *SugarDB) randomKey(ctx context.Context) string {
return randkey
}

func (server *SugarDB) dbSize(ctx context.Context) int {
server.storeLock.RLock()
defer server.storeLock.RUnlock()

database := ctx.Value("Database").(int)
return len(server.store[database])
}

func (server *SugarDB) getObjectFreq(ctx context.Context, key string) (int, error) {
database := ctx.Value("Database").(int)

Expand Down
8 changes: 5 additions & 3 deletions sugardb/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ import (
"context"
"errors"
"fmt"
"github.com/echovault/sugardb/internal"
"github.com/echovault/sugardb/internal/clock"
"github.com/echovault/sugardb/internal/constants"
"io"
"net"
"strings"

"github.com/echovault/sugardb/internal"
"github.com/echovault/sugardb/internal/clock"
"github.com/echovault/sugardb/internal/constants"
)

func (server *SugarDB) getCommand(cmd string) (internal.Command, error) {
Expand Down Expand Up @@ -61,6 +62,7 @@ func (server *SugarDB) getHandlerFuncParams(ctx context.Context, cmd []string, c
GetClock: server.getClock,
Flush: server.Flush,
RandomKey: server.randomKey,
DBSize: server.dbSize,
TouchKey: server.updateKeysInCache,
GetObjectFrequency: server.getObjectFreq,
GetObjectIdleTime: server.getObjectIdleTime,
Expand Down

0 comments on commit 8f1330e

Please sign in to comment.