aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--handlers.go75
-rw-r--r--main.go19
-rw-r--r--redisDB.go10
-rw-r--r--shards.go18
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
diff --git a/main.go b/main.go
index 8edf10f..5e56280 100644
--- a/main.go
+++ b/main.go
@@ -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)
diff --git a/redisDB.go b/redisDB.go
index 74a7de6..939fbbe 100644
--- a/redisDB.go
+++ b/redisDB.go
@@ -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