diff options
| -rw-r--r-- | handlers.go | 75 | ||||
| -rw-r--r-- | main.go | 19 | ||||
| -rw-r--r-- | redisDB.go | 10 | ||||
| -rw-r--r-- | shards.go | 18 |
4 files changed, 77 insertions, 45 deletions
diff --git a/handlers.go b/handlers.go index 305d526..aefea85 100644 --- a/handlers.go +++ b/handlers.go @@ -3,50 +3,42 @@ package main import ( "errors" "net" - "path/filepath" - "sort" - "strconv" "time" ) func handleGet(conn net.Conn, args []string) { - db.mu.Lock() - defer db.mu.Unlock() - if len(args) != 2 { err := errors.New("wrong number of arguments for 'GET'") conn.Write(serializeRESP(err)) return } + + key := args[1] - key := args[1] + result := db.Execute(key, func(s *Shard) interface{}{ + item, exists := s.data[key] + if !exists { + return nil + } - item, exists := db.data[key] - if !exists { - conn.Write(serializeRESP(nil)) - return - } + if item.ExpiresAt != nil && time.Now().After(*item.ExpiresAt) { + delete(s.data, key) + return nil + } - if item.ExpiresAt != nil && time.Now().After(*item.ExpiresAt) { - delete(db.data, key) - conn.Write(serializeRESP(nil)) - return - } + strValue, ok := item.Value.(string) + if !ok { + err := errors.New("WRONGTYPE Operation against a key holding the wrong kind of value") + return err + } + return strValue + }) - strValue, ok := item.Value.(string) - if !ok { - err := errors.New("WRONGTYPE Operation against a key holding the wrong kind of value") - conn.Write(serializeRESP(err)) - return - } - conn.Write(serializeRESP(strValue)) + conn.Write(serializeRESP(result)) } func handleExists(conn net.Conn, args []string) { - db.mu.Lock() - defer db.mu.Unlock() - if len(args) != 2 { err := errors.New("wrong number of arguments for 'EXISTS'") conn.Write(serializeRESP(err)) @@ -54,13 +46,16 @@ func handleExists(conn net.Conn, args []string) { } key := args[1] + result := db.Execute(key, func(s *Shard) interface{}{ + _, exists := s.data[key] + if exists { + return 1 + } else { + return 0 + } + }) - _, exists := db.data[key] - if exists { - conn.Write(serializeRESP(1)) - } else { - conn.Write(serializeRESP(0)) - } + conn.Write(serializeRESP(result)) } func handleSet(conn net.Conn, args []string) { @@ -74,12 +69,15 @@ func handleSet(conn net.Conn, args []string) { } key := args[1] - item := Item{Value: args[2]} + result := db.Execute(key, func(s *Shard) interface{}{ + item := Item{Value: args[2]} + s.data[key] = item + return SimpleString("OK") + }) - db.data[key] = item - conn.Write(serializeRESP(SimpleString("OK"))) + conn.Write(serializeRESP(result)) } - +/* func handleDel(conn net.Conn, args []string) { db.mu.Lock() defer db.mu.Unlock() @@ -730,4 +728,5 @@ func handleLrem(conn net.Conn, args []string){ item.Value = list db.data[key] = item conn.Write(serializeRESP(counter)) -}
\ No newline at end of file +} +*/
\ No newline at end of file @@ -7,7 +7,6 @@ import ( "net" "os" "strings" - "time" ) @@ -18,9 +17,9 @@ type handlerFunc func(net.Conn, []string) var commandRegistry = map[string]handlerFunc{ "GET": handleGet, "SET": handleSet, - "DEL": handleDel, +// "DEL": handleDel, "EXISTS": handleExists, - "INCR": handleIncr, +/* "INCR": handleIncr, "DECR": handleDecr, "PING": handlePing, "FLUSHALL": handleFlushall, @@ -38,12 +37,20 @@ var commandRegistry = map[string]handlerFunc{ "TYPE": handleType, "DBSIZE": handleDbsize, "KEYS": handleKeys, - "LREM": handleLrem, + "LREM": handleLrem,*/ } func main() { - db = RedisDB{data: make(map[string]Item)} + numShards := 16 + shards := make([]*Shard, numShards) + for i := 0; i < numShards; i++ { + shards[i] = &Shard{ + data: make(map[string]Item), + } +} + db = RedisDB{shards: shards} +/* go func() { ticker := time.NewTicker(1 * time.Second) for range ticker.C { @@ -56,7 +63,7 @@ func main() { db.mu.Unlock() } }() - +*/ listener, err := net.Listen("tcp", ":6379") if err != nil { fmt.Println("error starting server: ", err) @@ -9,13 +9,21 @@ type Item struct { Value any ExpiresAt *time.Time } + type RedisDB struct { mu sync.Mutex - data map[string]Item + shards []*Shard } type SimpleString string +func (db *RedisDB) Execute(key string, fn func(*Shard) interface{}) interface{} { + shard := db.getShard(key) + shard.mu.Lock() + defer shard.mu.Unlock() + return fn(shard) +} + func serializeRESP(v any) []byte { switch val := v.(type) { case string: diff --git a/shards.go b/shards.go new file mode 100644 index 0000000..55ab976 --- /dev/null +++ b/shards.go @@ -0,0 +1,18 @@ +package main + +import ( + "hash/fnv" + "sync" +) +type Shard struct{ + mu sync.Mutex + data map[string]Item +} + +func (db *RedisDB) getShard(key string)*Shard{ + hash := fnv.New64a() + hash.Write([]byte(key)) + val := hash.Sum64() + + return db.shards[val%16] +}
\ No newline at end of file |
