diff --git a/Dockerfile b/Dockerfile index 160f514..c4055e3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,9 +10,14 @@ ARG BUILD_TIME WORKDIR /build +# 挂载本地缓存加速 +VOLUME ["/go/pkg/mod", "/go/cache"] + COPY . . -RUN go build -ldflags="-s -w -X main.buildTime=${BUILD_TIME}" -o rotom . +RUN --mount=type=cache,target=/go/pkg/mod \ + --mount=type=cache,target=/root/.cache/go-build \ + go build -ldflags="-s -w -X main.buildTime=${BUILD_TIME}" -o rotom . FROM alpine:latest diff --git a/command.go b/command.go index 5979e8b..473eafb 100644 --- a/command.go +++ b/command.go @@ -3,7 +3,6 @@ package main import ( "fmt" "github.com/xgzlucario/rotom/internal/resp" - "github.com/xgzlucario/rotom/internal/timer" "strconv" "strings" "time" @@ -64,6 +63,7 @@ var cmdTable = []*Command{ {"zrange", zrangeCommand, 3, false}, {"eval", evalCommand, 2, true}, {"ping", pingCommand, 0, false}, + {"hello", helloCommand, 0, false}, {"flushdb", flushdbCommand, 0, true}, {"load", loadCommand, 0, false}, {"save", saveCommand, 0, false}, @@ -110,7 +110,7 @@ func setCommand(writer *resp.Writer, args []resp.RESP) { writer.WriteError(errParseInteger) return } - ttl = timer.GetNanoTime() + int64(n*time.Second) + ttl = time.Now().Add(n * time.Second).UnixNano() extra = extra[2:] // PX @@ -120,7 +120,7 @@ func setCommand(writer *resp.Writer, args []resp.RESP) { writer.WriteError(errParseInteger) return } - ttl = timer.GetNanoTime() + int64(n*time.Millisecond) + ttl = time.Now().Add(n * time.Millisecond).UnixNano() extra = extra[2:] // KEEPTTL @@ -551,6 +551,39 @@ func flushdbCommand(writer *resp.Writer, _ []resp.RESP) { writer.WriteSString("OK") } +func helloCommand(writer *resp.Writer, args []resp.RESP) { + var protoVersion int + var err error + + if len(args) > 0 { + protoVersion, err = args[0].ToInt() + if err != nil { + writer.WriteError(err) + return + } + } + + result := map[string]any{ + "server": "rotom", + "version": "1.0.0", + "proto": protoVersion, + } + if protoVersion == 3 { + writer.WriteMapHead(len(result)) + } else { + writer.WriteMapHead(len(result)) + } + for k, v := range result { + writer.WriteBulkString(k) + switch val := v.(type) { + case string: + writer.WriteBulkString(val) + case int: + writer.WriteInteger(val) + } + } +} + func loadCommand(writer *resp.Writer, _ []resp.RESP) { db.dict = New() if err := db.rdb.LoadDB(); err != nil { diff --git a/dict.go b/dict.go index 337dab4..2cffed5 100644 --- a/dict.go +++ b/dict.go @@ -2,7 +2,6 @@ package main import ( "github.com/cockroachdb/swiss" - "github.com/xgzlucario/rotom/internal/timer" "time" ) @@ -12,10 +11,6 @@ type Dict struct { expire *swiss.Map[string, int64] } -func init() { - timer.Init() -} - func New() *Dict { return &Dict{ data: swiss.New[string, any](64), @@ -36,7 +31,7 @@ func (dict *Dict) Get(key string) (any, int) { } // key expired - now := timer.GetNanoTime() + now := time.Now().UnixNano() if ts < now { dict.delete(key) return nil, KEY_NOT_EXIST @@ -82,7 +77,7 @@ func (dict *Dict) SetTTL(key string, ttl int64) int { // check key if already expired ts, ok := dict.expire.Get(key) - if ok && ts < timer.GetNanoTime() { + if ok && ts < time.Now().UnixNano() { dict.delete(key) return 0 } @@ -94,8 +89,9 @@ func (dict *Dict) SetTTL(key string, ttl int64) int { func (dict *Dict) EvictExpired() { var count int + now := time.Now().UnixNano() dict.expire.All(func(key string, ts int64) bool { - if timer.GetNanoTime() > ts { + if now > ts { dict.Delete(key) } count++ diff --git a/internal/resp/resp.go b/internal/resp/resp.go index 9a33279..e0040c3 100644 --- a/internal/resp/resp.go +++ b/internal/resp/resp.go @@ -16,7 +16,7 @@ const ( INTEGER = ':' BULK = '$' ARRAY = '*' - MAP = '%' // TODO: https://redis.io/docs/latest/develop/reference/protocol-spec/#maps + MAP = '%' ) var ( @@ -161,6 +161,12 @@ func (w *Writer) WriteArrayHead(n int) { w.b = append(w.b, CRLF...) } +func (w *Writer) WriteMapHead(n int) { + w.b = append(w.b, MAP) + w.b = strconv.AppendUint(w.b, uint64(n), 10) + w.b = append(w.b, CRLF...) +} + // WriteBulk writes a RESP bulk string from a byte slice. func (w *Writer) WriteBulk(bulk []byte) { w.WriteBulkString(b2s(bulk)) diff --git a/internal/timer/timer.go b/internal/timer/timer.go deleted file mode 100644 index 91fad75..0000000 --- a/internal/timer/timer.go +++ /dev/null @@ -1,23 +0,0 @@ -package timer - -import ( - "sync/atomic" - "time" -) - -var ( - nanotime atomic.Int64 -) - -func Init() { - go func() { - tk := time.NewTicker(time.Millisecond / 10) - for t := range tk.C { - nanotime.Store(t.UnixNano()) - } - }() -} - -func GetNanoTime() int64 { - return nanotime.Load() -}