Skip to content

Commit

Permalink
feat: add time event check oom
Browse files Browse the repository at this point in the history
  • Loading branch information
xgzlucario committed Jul 16, 2024
1 parent fec9d2f commit d40f39b
Show file tree
Hide file tree
Showing 18 changed files with 180 additions and 111 deletions.
33 changes: 10 additions & 23 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ type Command struct {
// cmdTable is the list of all available commands.
var cmdTable []*Command = []*Command{
{"set", setCommand, 2, true},
{"mset", msetCommand, 2, true},
{"get", getCommand, 1, false},
{"incr", incrCommand, 1, true},
{"hset", hsetCommand, 3, true},
Expand All @@ -43,6 +42,9 @@ var cmdTable []*Command = []*Command{
{"ping", pingCommand, 0, false},
{"hgetall", hgetallCommand, 1, false},
{"lrange", lrangeCommand, 3, false},

// TODO
{"mset", todoCommand, 0, false},
{"zpopmin", todoCommand, 0, false},
{"xadd", todoCommand, 0, false},
}
Expand Down Expand Up @@ -72,7 +74,7 @@ func equalCommand(str, lowerText string) bool {

func (cmd *Command) processCommand(writer *RESPWriter, args []RESP) {
if len(args) < cmd.arity {
writer.WriteError(ErrWrongNumberArgs(cmd.name))
writer.WriteError(errInvalidArguments)
return
}
cmd.handler(writer, args)
Expand All @@ -89,20 +91,6 @@ func setCommand(writer *RESPWriter, args []RESP) {
writer.WriteString("OK")
}

func msetCommand(writer *RESPWriter, args []RESP) {
// check arguments number
if len(args)%2 == 1 {
writer.WriteError(ErrWrongNumberArgs("mset"))
return
}
for i := 0; i < len(args); i += 2 {
key := args[i].ToString()
value := args[i+1].Clone()
db.dict.Set(key, value)
}
writer.WriteString("OK")
}

func incrCommand(writer *RESPWriter, args []RESP) {
key := args[0].ToString()

Expand All @@ -115,13 +103,13 @@ func incrCommand(writer *RESPWriter, args []RESP) {

valBytes, ok := val.([]byte)
if !ok {
writer.WriteError(ErrWrongType)
writer.WriteError(errWrongType)
return
}

num, err := RESP(valBytes).ToInt()
if err != nil {
writer.WriteError(ErrParseInteger)
writer.WriteError(errParseInteger)
return
}
num++
Expand All @@ -143,17 +131,16 @@ func getCommand(writer *RESPWriter, args []RESP) {
if ok {
writer.WriteBulk(valBytes)
} else {
writer.WriteError(ErrWrongType)
writer.WriteError(errWrongType)
}
}

func hsetCommand(writer *RESPWriter, args []RESP) {
hash := args[0].ToString()
args = args[1:]

// check arguments number
if len(args)%2 == 1 {
writer.WriteError(ErrWrongNumberArgs("hset"))
writer.WriteError(errInvalidArguments)
return
}

Expand All @@ -180,7 +167,7 @@ func hgetCommand(writer *RESPWriter, args []RESP) {

hmap, err := fetchMap(hash)
if err != nil {
writer.WriteError(ErrWrongType)
writer.WriteError(errWrongType)
return
}

Expand Down Expand Up @@ -432,7 +419,7 @@ func fetch[T any](key string, new func() T, setnx ...bool) (v T, err error) {
if ok {
return v, nil
}
return v, ErrWrongType
return v, errWrongType
}
v = new()
if len(setnx) > 0 && setnx[0] {
Expand Down
6 changes: 3 additions & 3 deletions command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func TestCommand(t *testing.T) {

rdb.Set(ctx, "notNum", "bar", 0)
_, err := rdb.Incr(ctx, "notNum").Result()
assert.Equal(err.Error(), ErrParseInteger.Error())
assert.Equal(err.Error(), errParseInteger.Error())
})

t.Run("hash", func(t *testing.T) {
Expand Down Expand Up @@ -102,10 +102,10 @@ func TestCommand(t *testing.T) {

// error
_, err := rdb.HSet(ctx, "map").Result()
assert.Equal(err.Error(), ErrWrongNumberArgs("hset").Error())
assert.Equal(err.Error(), errInvalidArguments.Error())

_, err = rdb.HSet(ctx, "map", "k1", "v1", "k2").Result()
assert.Equal(err.Error(), ErrWrongNumberArgs("hset").Error())
assert.Equal(err.Error(), errInvalidArguments.Error())
})

t.Run("list", func(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type Config struct {
Port int `json:"port"`
AppendOnly bool `json:"appendonly"`
AppendFileName string `json:"appendfilename"`
MaxMemory int `json:"maxMemory"`
}

func LoadConfig(path string) (config *Config, err error) {
Expand Down
16 changes: 5 additions & 11 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,13 @@ import (
)

var (
ErrWrongType = errors.New("WRONGTYPE Operation against a key holding the wrong kind of value")

ErrUnknownType = errors.New("ERR unknown value type")

ErrParseInteger = errors.New("ERR value is not an integer or out of range")

ErrCRLFNotFound = errors.New("ERR CRLF not found in line")
errWrongType = errors.New("WRONGTYPE Operation against a key holding the wrong kind of value")
errParseInteger = errors.New("ERR value is not an integer or out of range")
errCRLFNotFound = errors.New("ERR CRLF not found in line")
errInvalidArguments = errors.New("ERR invalid number of arguments")
errOOM = errors.New("ERR command not allowed when out of memory")
)

func ErrWrongNumberArgs(cmd string) error {
return fmt.Errorf("ERR wrong number of arguments for '%s' command", cmd)
}

func ErrUnknownCommand(cmd string) error {
return fmt.Errorf("ERR unknown command '%s'", cmd)
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 // indirect
golang.org/x/exp v0.0.0-20240716160929-1d5bc16f04a8 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tidwall/mmap v0.3.0 h1:XXt1YsiXCF5/UAu3pLbu6g7iulJ9jsbs6vt7UpiV0sY=
github.com/tidwall/mmap v0.3.0/go.mod h1:2/dNzF5zA+te/JVHfrqNLcRkb8LjdH3c80vYHFQEZRk=
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w=
golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/exp v0.0.0-20240716160929-1d5bc16f04a8 h1:Z+vTUQyBb738QmIhbJx3z4htsxDeI+rd0EHvNm8jHkg=
golang.org/x/exp v0.0.0-20240716160929-1d5bc16f04a8/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
56 changes: 50 additions & 6 deletions internal/hash/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ import (
"testing"
)

const N = 512

func BenchmarkMap(b *testing.B) {
benchMapI("map", func() MapI { return NewMap() }, b)
benchMapI("zipmap", func() MapI { return NewZipMap() }, b)
}

func BenchmarkSet(b *testing.B) {
benchSetI("set", func() SetI { return NewSet() }, b)
benchSetI("zipset", func() SetI { return NewZipSet() }, b)
}

func genKey(i int) string {
return fmt.Sprintf("%08x", i)
}
Expand All @@ -17,19 +29,19 @@ func genMap(m MapI, n int) MapI {
return m
}

func BenchmarkMap(b *testing.B) {
benchMapI("map", func() MapI { return NewMap() }, b)
benchMapI("zipmap", func() MapI { return NewZipMap() }, b)
func genSet(s SetI, n int) SetI {
for i := 0; i < n; i++ {
s.Add(genKey(i))
}
return s
}

func benchMapI(name string, newf func() MapI, b *testing.B) {
const N = 512
b.Run(name+"/get", func(b *testing.B) {
m := genMap(newf(), N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
k := genKey(i % N)
m.Get(k)
m.Get(genKey(i % N))
}
})
b.Run(name+"/set", func(b *testing.B) {
Expand All @@ -55,3 +67,35 @@ func benchMapI(name string, newf func() MapI, b *testing.B) {
}
})
}

func benchSetI(name string, newf func() SetI, b *testing.B) {
b.Run(name+"/add", func(b *testing.B) {
m := newf()
for i := 0; i < b.N; i++ {
m.Add(genKey(i % N))
}
})
b.Run(name+"/exist", func(b *testing.B) {
m := genSet(newf(), N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
k := genKey(i % N)
m.Exist(k)
}
})
b.Run(name+"/remove", func(b *testing.B) {
m := genSet(newf(), b.N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
k := genKey(i)
m.Remove(k)
}
})
b.Run(name+"/scan", func(b *testing.B) {
m := genSet(newf(), N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
m.Scan(func(string) {})
}
})
}
2 changes: 1 addition & 1 deletion internal/hash/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type Map struct {
}

func NewMap() *Map {
return &Map{m: swiss.New[string, []byte](64)}
return &Map{m: swiss.New[string, []byte](256)}
}

func (m *Map) Get(key string) ([]byte, bool) {
Expand Down
5 changes: 5 additions & 0 deletions internal/hash/map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ func testMapI(m MapI, t *testing.T) {
assert.True(m.Remove("key3"))
assert.False(m.Remove("notexist"))

// scan
m.Scan(func(string, []byte) {
panic("should not call")
})

// len
assert.Equal(m.Len(), 0)
}
Expand Down
21 changes: 12 additions & 9 deletions internal/hash/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import (
)

type SetI interface {
Add(key string) (ok bool)
Remove(key string) (ok bool)
Add(key string) bool
Exist(key string) bool
Remove(key string) bool
Pop() (key string, ok bool)
Scan(fn func(string))
Scan(fn func(key string))
Len() int
}

Expand All @@ -19,24 +20,26 @@ type Set struct {
}

func NewSet() *Set {
return &Set{mapset.NewThreadUnsafeSetWithSize[string](64)}
return &Set{mapset.NewThreadUnsafeSetWithSize[string](512)}
}

func (s Set) Remove(key string) bool {
if !s.ContainsOne(key) {
if !s.Exist(key) {
return false
}
s.Set.Remove(key)
return true
}

func (s Set) Len() int {
return s.Cardinality()
}

func (s Set) Scan(fn func(string)) {
s.Set.Each(func(s string) bool {
fn(s)
return false
})
}

func (s Set) Exist(key string) bool {
return s.Set.ContainsOne(key)
}

func (s Set) Len() int { return s.Cardinality() }
5 changes: 5 additions & 0 deletions internal/hash/set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ func testSetI(m SetI, t *testing.T) {
assert.Equal(key, "")
assert.False(ok)

// scan
m.Scan(func(string) {
panic("should not call")
})

// len
assert.Equal(m.Len(), 0)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/hash/zipmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func (zm *ZipMap) Remove(key string) bool {

kb, _ := decodeEntry(entry)
if key == kb {
it.RemoveNext()
it.RemoveNexts(1, nil)
return true
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/hash/zipset.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func (zs *ZipSet) Remove(key string) bool {
it := zs.m.Iterator().SeekLast()
for !it.IsFirst() {
if key == b2s(it.Prev()) {
it.RemoveNext()
it.RemoveNexts(1, nil)
return true
}
}
Expand Down
Loading

0 comments on commit d40f39b

Please sign in to comment.