Added DEL command for deleting keys from the store

This commit is contained in:
Kelvin Mwinuka
2024-03-08 22:49:03 +08:00
parent e34ed74e3f
commit 0b90c9343e
6 changed files with 280 additions and 226 deletions

View File

@@ -22,7 +22,7 @@ services:
- MTLS=false
- BOOTSTRAP_CLUSTER=false
- ACL_CONFIG=/etc/config/echovault/acl.yml
- REQUIRE_PASS=true
- REQUIRE_PASS=false
- PASSWORD=default_password
- FORWARD_COMMAND=false
- SNAPSHOT_THRESHOLD=1000
@@ -47,206 +47,216 @@ services:
networks:
- testnet
# cluster_node_1:
# container_name: cluster_node_1
# build:
# context: .
# dockerfile: Dockerfile.dev
# environment:
# - PORT=7480
# - RAFT_PORT=8000
# - ML_PORT=7946
# - KEY=/generic/ssl/certs/echovault/server1.key
# - CERT=/generic/ssl/certs/echovault/server1.crt
# - SERVER_ID=1
# - DATA_DIR=/var/lib/echovault
# - IN_MEMORY=false
# - TLS=true
# - MTLS=true
# - BOOTSTRAP_CLUSTER=true
# - ACL_CONFIG=/generic/config/echovault/acl.yml
# - REQUIRE_PASS=false
# - FORWARD_COMMAND=true
# - SNAPSHOT_THRESHOLD=1000
# - SNAPSHOT_INTERVAL=5m30s
# - RESTORE_SNAPSHOT=false
# - RESTORE_AOF=false
# - AOF_SYNC_STRATEGY=everysec
# # List of server cert/key pairs
# - CERT_KEY_PAIR_1=/generic/ssl/certs/echovault/server/server1.crt,/generic/ssl/certs/echovault/server/server1.key
# - CERT_KEY_PAIR_2=/generic/ssl/certs/echovault/server/server2.crt,/generic/ssl/certs/echovault/server/server2.key
# # List of client certificate authorities
# - CLIENT_CA_1=/generic/ssl/certs/echovault/client/rootCA.crt
# ports:
# - "7481:7480"
# - "7945:7946"
# - "8000:8000"
# volumes:
# - ./config/acl.yml:/generic/config/echovault/acl.yml
# - ./volumes/cluster_node_1:/var/lib/echovault
# networks:
# - testnet
#
# cluster_node_2:
# container_name: cluster_node_2
# build:
# context: .
# dockerfile: Dockerfile.dev
# environment:
# - PORT=7480
# - RAFT_PORT=8000
# - ML_PORT=7946
# - KEY=/generic/ssl/certs/echovault/server1.key
# - CERT=/generic/ssl/certs/echovault/server1.crt
# - SERVER_ID=2
# - JOIN_ADDR=cluster_node_1:7946
# - DATA_DIR=/var/lib/echovault
# - IN_MEMORY=false
# - TLS=true
# - MTLS=true
# - BOOTSTRAP_CLUSTER=false
# - ACL_CONFIG=/generic/config/echovault/acl.yml
# - REQUIRE_PASS=false
# - FORWARD_COMMAND=true
# - SNAPSHOT_THRESHOLD=1000
# - SNAPSHOT_INTERVAL=5m30s
# - RESTORE_SNAPSHOT=false
# - RESTORE_AOF=false
# - AOF_SYNC_STRATEGY=everysec
# # List of server cert/key pairs
# - CERT_KEY_PAIR_1=/generic/ssl/certs/echovault/server/server1.crt,/generic/ssl/certs/echovault/server/server1.key
# - CERT_KEY_PAIR_2=/generic/ssl/certs/echovault/server/server2.crt,/generic/ssl/certs/echovault/server/server2.key
# # List of client certificate authorities
# - CLIENT_CA_1=/generic/ssl/certs/echovault/client/rootCA.crt
# ports:
# - "7482:7480"
# - "7947:7946"
# - "8001:8000"
# volumes:
# - ./config/acl.yml:/generic/config/echovault/acl.yml
# - ./volumes/cluster_node_2:/var/lib/echovault
# networks:
# - testnet
#
# cluster_node_3:
# container_name: cluster_node_3
# build:
# context: .
# dockerfile: Dockerfile.dev
# environment:
# - PORT=7480
# - RAFT_PORT=8000
# - ML_PORT=7946
# - KEY=/generic/ssl/certs/echovault/server1.key
# - CERT=/generic/ssl/certs/echovault/server1.crt
# - SERVER_ID=3
# - JOIN_ADDR=cluster_node_1:7946
# - DATA_DIR=/var/lib/echovault
# - IN_MEMORY=false
# - TLS=true
# - MTLS=true
# - BOOTSTRAP_CLUSTER=false
# - ACL_CONFIG=/generic/config/echovault/acl.yml
# - REQUIRE_PASS=false
# - FORWARD_COMMAND=true
# - SNAPSHOT_THRESHOLD=1000
# - SNAPSHOT_INTERVAL=5m30s
# - RESTORE_SNAPSHOT=false
# - RESTORE_AOF=false
# - AOF_SYNC_STRATEGY=everysec
# # List of server cert/key pairs
# - CERT_KEY_PAIR_1=/generic/ssl/certs/echovault/server/server1.crt,/generic/ssl/certs/echovault/server/server1.key
# - CERT_KEY_PAIR_2=/generic/ssl/certs/echovault/server/server2.crt,/generic/ssl/certs/echovault/server/server2.key
# # List of client certificate authorities
# - CLIENT_CA_1=/generic/ssl/certs/echovault/client/rootCA.crt
# ports:
# - "7483:7480"
# - "7948:7946"
# - "8002:8000"
# volumes:
# - ./config/acl.yml:/generic/config/echovault/acl.yml
# - ./volumes/cluster_node_3:/var/lib/echovault
# networks:
# - testnet
#
# cluster_node_4:
# container_name: cluster_node_4
# build:
# context: .
# dockerfile: Dockerfile.dev
# environment:
# - PORT=7480
# - RAFT_PORT=8000
# - ML_PORT=7946
# - KEY=/generic/ssl/certs/echovault/server1.key
# - CERT=/generic/ssl/certs/echovault/server1.crt
# - SERVER_ID=4
# - JOIN_ADDR=cluster_node_1:7946
# - DATA_DIR=/var/lib/echovault
# - IN_MEMORY=false
# - TLS=true
# - MTLS=true
# - BOOTSTRAP_CLUSTER=false
# - ACL_CONFIG=/generic/config/echovault/acl.yml
# - REQUIRE_PASS=false
# - FORWARD_COMMAND=true
# - SNAPSHOT_THRESHOLD=1000
# - SNAPSHOT_INTERVAL=5m30s
# - RESTORE_SNAPSHOT=false
# - RESTORE_AOF=false
# - AOF_SYNC_STRATEGY=everysec
# # List of server cert/key pairs
# - CERT_KEY_PAIR_1=/generic/ssl/certs/echovault/server/server1.crt,/generic/ssl/certs/echovault/server/server1.key
# - CERT_KEY_PAIR_2=/generic/ssl/certs/echovault/server/server2.crt,/generic/ssl/certs/echovault/server/server2.key
# # List of client certificate authorities
# - CLIENT_CA_1=/generic/ssl/certs/echovault/client/rootCA.crt
# ports:
# - "7484:7480"
# - "7949:7946"
# - "8003:8000"
# volumes:
# - ./config/acl.yml:/generic/config/echovault/acl.yml
# - ./volumes/cluster_node_4:/var/lib/echovault
# networks:
# - testnet
#
# cluster_node_5:
# container_name: cluster_node_5
# build:
# context: .
# dockerfile: Dockerfile.dev
# environment:
# - PORT=7480
# - RAFT_PORT=8000
# - ML_PORT=7946
# - KEY=/generic/ssl/certs/echovault/server1.key
# - CERT=/generic/ssl/certs/echovault/server1.crt
# - SERVER_ID=5
# - JOIN_ADDR=cluster_node_1:7946
# - DATA_DIR=/var/lib/echovault
# - IN_MEMORY=false
# - TLS=true
# - MTLS=true
# - BOOTSTRAP_CLUSTER=false
# - ACL_CONFIG=/generic/config/echovault/acl.yml
# - REQUIRE_PASS=false
# - FORWARD_COMMAND=true
# - SNAPSHOT_THRESHOLD=1000
# - SNAPSHOT_INTERVAL=5m30s
# - RESTORE_SNAPSHOT=false
# - RESTORE_AOF=false
# - AOF_SYNC_STRATEGY=everysec
# # List of server cert/key pairs
# - CERT_KEY_PAIR_1=/generic/ssl/certs/echovault/server/server1.crt,/generic/ssl/certs/echovault/server/server1.key
# - CERT_KEY_PAIR_2=/generic/ssl/certs/echovault/server/server2.crt,/generic/ssl/certs/echovault/server/server2.key
# # List of client certificate authorities
# - CLIENT_CA_1=/generic/ssl/certs/echovault/client/rootCA.crt
# ports:
# - "7485:7480"
# - "7950:7946"
# - "8004:8000"
# volumes:
# - ./config/acl.yml:/generic/config/echovault/acl.yml
# - ./volumes/cluster_node_5:/var/lib/echovault
# networks:
# - testnet
cluster_node_1:
container_name: cluster_node_1
build:
context: .
dockerfile: Dockerfile.dev
environment:
- PORT=7480
- RAFT_PORT=8000
- ML_PORT=7946
- KEY=/generic/ssl/certs/echovault/server1.key
- CERT=/generic/ssl/certs/echovault/server1.crt
- SERVER_ID=1
- DATA_DIR=/var/lib/echovault
- IN_MEMORY=false
- TLS=false
- MTLS=false
- BOOTSTRAP_CLUSTER=true
- ACL_CONFIG=/generic/config/echovault/acl.yml
- REQUIRE_PASS=false
- FORWARD_COMMAND=true
- SNAPSHOT_THRESHOLD=1000
- SNAPSHOT_INTERVAL=5m30s
- RESTORE_SNAPSHOT=false
- RESTORE_AOF=false
- AOF_SYNC_STRATEGY=everysec
- MAX_MEMORY=2000kb
- EVICTION_POLICY=allkeys-lfu
# List of server cert/key pairs
- CERT_KEY_PAIR_1=/generic/ssl/certs/echovault/server/server1.crt,/generic/ssl/certs/echovault/server/server1.key
- CERT_KEY_PAIR_2=/generic/ssl/certs/echovault/server/server2.crt,/generic/ssl/certs/echovault/server/server2.key
# List of client certificate authorities
- CLIENT_CA_1=/generic/ssl/certs/echovault/client/rootCA.crt
ports:
- "7481:7480"
- "7945:7946"
- "8000:8000"
volumes:
- ./config/acl.yml:/generic/config/echovault/acl.yml
- ./volumes/cluster_node_1:/var/lib/echovault
networks:
- testnet
cluster_node_2:
container_name: cluster_node_2
build:
context: .
dockerfile: Dockerfile.dev
environment:
- PORT=7480
- RAFT_PORT=8000
- ML_PORT=7946
- KEY=/generic/ssl/certs/echovault/server1.key
- CERT=/generic/ssl/certs/echovault/server1.crt
- SERVER_ID=2
- JOIN_ADDR=cluster_node_1:7946
- DATA_DIR=/var/lib/echovault
- IN_MEMORY=false
- TLS=false
- MTLS=false
- BOOTSTRAP_CLUSTER=false
- ACL_CONFIG=/generic/config/echovault/acl.yml
- REQUIRE_PASS=false
- FORWARD_COMMAND=true
- SNAPSHOT_THRESHOLD=1000
- SNAPSHOT_INTERVAL=5m30s
- RESTORE_SNAPSHOT=false
- RESTORE_AOF=false
- AOF_SYNC_STRATEGY=everysec
- MAX_MEMORY=2000kb
- EVICTION_POLICY=allkeys-lfu
# List of server cert/key pairs
- CERT_KEY_PAIR_1=/generic/ssl/certs/echovault/server/server1.crt,/generic/ssl/certs/echovault/server/server1.key
- CERT_KEY_PAIR_2=/generic/ssl/certs/echovault/server/server2.crt,/generic/ssl/certs/echovault/server/server2.key
# List of client certificate authorities
- CLIENT_CA_1=/generic/ssl/certs/echovault/client/rootCA.crt
ports:
- "7482:7480"
- "7947:7946"
- "8001:8000"
volumes:
- ./config/acl.yml:/generic/config/echovault/acl.yml
- ./volumes/cluster_node_2:/var/lib/echovault
networks:
- testnet
cluster_node_3:
container_name: cluster_node_3
build:
context: .
dockerfile: Dockerfile.dev
environment:
- PORT=7480
- RAFT_PORT=8000
- ML_PORT=7946
- KEY=/generic/ssl/certs/echovault/server1.key
- CERT=/generic/ssl/certs/echovault/server1.crt
- SERVER_ID=3
- JOIN_ADDR=cluster_node_1:7946
- DATA_DIR=/var/lib/echovault
- IN_MEMORY=false
- TLS=false
- MTLS=false
- BOOTSTRAP_CLUSTER=false
- ACL_CONFIG=/generic/config/echovault/acl.yml
- REQUIRE_PASS=false
- FORWARD_COMMAND=true
- SNAPSHOT_THRESHOLD=1000
- SNAPSHOT_INTERVAL=5m30s
- RESTORE_SNAPSHOT=false
- RESTORE_AOF=false
- AOF_SYNC_STRATEGY=everysec
- MAX_MEMORY=2000kb
- EVICTION_POLICY=allkeys-lfu
# List of server cert/key pairs
- CERT_KEY_PAIR_1=/generic/ssl/certs/echovault/server/server1.crt,/generic/ssl/certs/echovault/server/server1.key
- CERT_KEY_PAIR_2=/generic/ssl/certs/echovault/server/server2.crt,/generic/ssl/certs/echovault/server/server2.key
# List of client certificate authorities
- CLIENT_CA_1=/generic/ssl/certs/echovault/client/rootCA.crt
ports:
- "7483:7480"
- "7948:7946"
- "8002:8000"
volumes:
- ./config/acl.yml:/generic/config/echovault/acl.yml
- ./volumes/cluster_node_3:/var/lib/echovault
networks:
- testnet
cluster_node_4:
container_name: cluster_node_4
build:
context: .
dockerfile: Dockerfile.dev
environment:
- PORT=7480
- RAFT_PORT=8000
- ML_PORT=7946
- KEY=/generic/ssl/certs/echovault/server1.key
- CERT=/generic/ssl/certs/echovault/server1.crt
- SERVER_ID=4
- JOIN_ADDR=cluster_node_1:7946
- DATA_DIR=/var/lib/echovault
- IN_MEMORY=false
- TLS=false
- MTLS=false
- BOOTSTRAP_CLUSTER=false
- ACL_CONFIG=/generic/config/echovault/acl.yml
- REQUIRE_PASS=false
- FORWARD_COMMAND=true
- SNAPSHOT_THRESHOLD=1000
- SNAPSHOT_INTERVAL=5m30s
- RESTORE_SNAPSHOT=false
- RESTORE_AOF=false
- AOF_SYNC_STRATEGY=everysec
- MAX_MEMORY=2000kb
- EVICTION_POLICY=allkeys-lfu
# List of server cert/key pairs
- CERT_KEY_PAIR_1=/generic/ssl/certs/echovault/server/server1.crt,/generic/ssl/certs/echovault/server/server1.key
- CERT_KEY_PAIR_2=/generic/ssl/certs/echovault/server/server2.crt,/generic/ssl/certs/echovault/server/server2.key
# List of client certificate authorities
- CLIENT_CA_1=/generic/ssl/certs/echovault/client/rootCA.crt
ports:
- "7484:7480"
- "7949:7946"
- "8003:8000"
volumes:
- ./config/acl.yml:/generic/config/echovault/acl.yml
- ./volumes/cluster_node_4:/var/lib/echovault
networks:
- testnet
cluster_node_5:
container_name: cluster_node_5
build:
context: .
dockerfile: Dockerfile.dev
environment:
- PORT=7480
- RAFT_PORT=8000
- ML_PORT=7946
- KEY=/generic/ssl/certs/echovault/server1.key
- CERT=/generic/ssl/certs/echovault/server1.crt
- SERVER_ID=5
- JOIN_ADDR=cluster_node_1:7946
- DATA_DIR=/var/lib/echovault
- IN_MEMORY=false
- TLS=false
- MTLS=false
- BOOTSTRAP_CLUSTER=false
- ACL_CONFIG=/generic/config/echovault/acl.yml
- REQUIRE_PASS=false
- FORWARD_COMMAND=true
- SNAPSHOT_THRESHOLD=1000
- SNAPSHOT_INTERVAL=5m30s
- RESTORE_SNAPSHOT=false
- RESTORE_AOF=false
- AOF_SYNC_STRATEGY=everysec
- MAX_MEMORY=2000kb
- EVICTION_POLICY=allkeys-lfu
# List of server cert/key pairs
- CERT_KEY_PAIR_1=/generic/ssl/certs/echovault/server/server1.crt,/generic/ssl/certs/echovault/server/server1.key
- CERT_KEY_PAIR_2=/generic/ssl/certs/echovault/server/server2.crt,/generic/ssl/certs/echovault/server/server2.key
# List of client certificate authorities
- CLIENT_CA_1=/generic/ssl/certs/echovault/client/rootCA.crt
ports:
- "7485:7480"
- "7950:7946"
- "8004:8000"
volumes:
- ./config/acl.yml:/generic/config/echovault/acl.yml
- ./volumes/cluster_node_5:/var/lib/echovault
networks:
- testnet

View File

@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"github.com/echovault/echovault/src/utils"
"log"
"net"
"strings"
"time"
@@ -206,6 +207,23 @@ func handleMGet(ctx context.Context, cmd []string, server utils.Server, _ *net.C
return bytes, nil
}
func handleDel(ctx context.Context, cmd []string, server utils.Server, _ *net.Conn) ([]byte, error) {
keys, err := delKeyFunc(cmd)
if err != nil {
return nil, err
}
count := 0
for _, key := range keys {
err = server.DeleteKey(ctx, key)
if err != nil {
log.Printf("could not delete key %s due to error: %+v\n", key, err)
continue
}
count += 1
}
return []byte(fmt.Sprintf(":%d\r\n", count)), nil
}
func Commands() []utils.Command {
return []utils.Command{
{
@@ -249,5 +267,13 @@ PXAT - Expire at the exat time in unix milliseconds (positive integer).`,
KeyExtractionFunc: mgetKeyFunc,
HandlerFunc: handleMGet,
},
{
Command: "del",
Categories: []string{utils.KeyspaceCategory, utils.WriteCategory, utils.SlowCategory},
Description: "(DEL) Removes one or more keys from the store.",
Sync: true,
KeyExtractionFunc: delKeyFunc,
HandlerFunc: handleDel,
},
}
}

View File

@@ -38,3 +38,10 @@ func mgetKeyFunc(cmd []string) ([]string, error) {
}
return cmd[1:], nil
}
func delKeyFunc(cmd []string) ([]string, error) {
if len(cmd) < 2 {
return nil, errors.New(utils.WrongArgsResponse)
}
return cmd[1:], nil
}

View File

@@ -185,6 +185,10 @@ func (server *Server) DeleteKey(ctx context.Context, key string) error {
// updateKeyInCache updates either the key access count or the most recent access time in the cache
// depending on whether an LFU or LRU strategy was used.
func (server *Server) updateKeyInCache(ctx context.Context, key string) error {
// Only update cache when in standalone mode or when raft leader
if server.IsInCluster() || (server.IsInCluster() && !server.raft.IsRaftLeader()) {
return nil
}
// If max memory is 0, there's no max so no need to update caches
if server.Config.MaxMemory == 0 {
return nil

View File

@@ -57,7 +57,7 @@ func (server *Server) handleCommand(ctx context.Context, message []byte, conn *n
}
}
// If we're not in cluster mode and command/subcommand is a write command, wait for state copy to finish.
// If the command is a write command, wait for state copy to finish.
if utils.IsWriteCommand(command, subCommand) {
for {
if !server.StateCopyInProgress.Load() {

View File

@@ -138,26 +138,6 @@ func NewServer(opts Opts) *Server {
)
}
// Set up LFU cache
server.lfuCache = struct {
mutex sync.Mutex
cache eviction.CacheLFU
}{
mutex: sync.Mutex{},
cache: eviction.NewCacheLFU(),
}
// set up LRU cache
server.lruCache = struct {
mutex sync.Mutex
cache eviction.CacheLRU
}{
mutex: sync.Mutex{},
cache: eviction.NewCacheLRU(),
}
// TODO: If eviction policy is volatile-ttl, start goroutine that continuously reads the mem stats
// TODO: before triggering purge once max-memory is reached
return server
}
@@ -319,7 +299,13 @@ func (server *Server) Start(ctx context.Context) {
// Initialise raft and memberlist
server.raft.RaftInit(ctx)
server.memberList.MemberListInit(ctx)
} else {
if server.raft.IsRaftLeader() {
server.InitialiseCaches()
}
}
if !server.IsInCluster() {
server.InitialiseCaches()
// Restore from AOF by default if it's enabled
if conf.RestoreAOF {
err := server.AOFEngine.Restore()
@@ -406,3 +392,24 @@ func (server *Server) ShutDown(ctx context.Context) {
server.memberList.MemberListShutdown(ctx)
}
}
func (server *Server) InitialiseCaches() {
// Set up LFU cache
server.lfuCache = struct {
mutex sync.Mutex
cache eviction.CacheLFU
}{
mutex: sync.Mutex{},
cache: eviction.NewCacheLFU(),
}
// set up LRU cache
server.lruCache = struct {
mutex sync.Mutex
cache eviction.CacheLRU
}{
mutex: sync.Mutex{},
cache: eviction.NewCacheLRU(),
}
// TODO: If eviction policy is volatile-ttl, start goroutine that continuously reads the mem stats
// TODO: before triggering purge once max-memory is reached
}