Re-enabled cluster nodes in docker-compose.yml.

Created flow to forward key deletion command from non-leader node to leader node.
Created flow for propagating key deletion accross the entire cluster to maintain consistency of the deleted keys.
This commit is contained in:
Kelvin Mwinuka
2024-03-11 20:39:57 +08:00
parent c611dd60ee
commit 52b39d5b0f
7 changed files with 294 additions and 225 deletions

View File

@@ -47,216 +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=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
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

@@ -21,6 +21,7 @@ type DelegateOpts struct {
addVoter func(id raft.ServerID, address raft.ServerAddress, prevIndex uint64, timeout time.Duration) error
isRaftLeader func() bool
applyMutate func(ctx context.Context, cmd []string) ([]byte, error)
applyDeleteKey func(ctx context.Context, key string) error
}
func NewDelegate(opts DelegateOpts) *Delegate {
@@ -67,6 +68,24 @@ func (delegate *Delegate) NotifyMsg(msgBytes []byte) {
if err != nil {
fmt.Println(err)
}
case "DeleteKey":
// If the current node is not a cluster leader, re-broadcast the message
if !delegate.options.isRaftLeader() {
delegate.options.broadcastQueue.QueueBroadcast(&msg)
return
}
// Current node is the cluster leader, handle the key deletion
ctx := context.WithValue(
context.WithValue(context.Background(), utils.ContextServerID("ServerID"), string(msg.ServerID)),
utils.ContextConnID("ConnectionID"), msg.ConnId)
key := string(msg.Content)
if err := delegate.options.applyDeleteKey(ctx, key); err != nil {
log.Println(err)
}
case "MutateData":
// If the current node is not a cluster leader, re-broadcast the message
if !delegate.options.isRaftLeader() {

View File

@@ -19,23 +19,24 @@ type NodeMeta struct {
RaftAddr raft.ServerAddress `json:"RaftAddr"`
}
type MemberlistOpts struct {
type Opts struct {
Config utils.Config
HasJoinedCluster func() bool
AddVoter func(id raft.ServerID, address raft.ServerAddress, prevIndex uint64, timeout time.Duration) error
RemoveRaftServer func(meta NodeMeta) error
IsRaftLeader func() bool
ApplyMutate func(ctx context.Context, cmd []string) ([]byte, error)
ApplyDeleteKey func(ctx context.Context, key string) error
}
type MemberList struct {
options MemberlistOpts
options Opts
broadcastQueue *memberlist.TransmitLimitedQueue
numOfNodes int
memberList *memberlist.Memberlist
}
func NewMemberList(opts MemberlistOpts) *MemberList {
func NewMemberList(opts Opts) *MemberList {
return &MemberList{
options: opts,
broadcastQueue: new(memberlist.TransmitLimitedQueue),
@@ -53,6 +54,7 @@ func (m *MemberList) MemberListInit(ctx context.Context) {
addVoter: m.options.AddVoter,
isRaftLeader: m.options.IsRaftLeader,
applyMutate: m.options.ApplyMutate,
applyDeleteKey: m.options.ApplyDeleteKey,
})
cfg.Events = NewEventDelegate(EventDelegateOpts{
incrementNodes: func() { m.numOfNodes += 1 },
@@ -75,8 +77,8 @@ func (m *MemberList) MemberListInit(ctx context.Context) {
if m.options.Config.JoinAddr != "" {
backoffPolicy := utils.RetryBackoff(retry.NewFibonacci(1*time.Second), 5, 200*time.Millisecond, 0, 0)
err := retry.Do(ctx, backoffPolicy, func(ctx context.Context) error {
_, err := list.Join([]string{m.options.Config.JoinAddr})
err = retry.Do(ctx, backoffPolicy, func(ctx context.Context) error {
_, err = list.Join([]string{m.options.Config.JoinAddr})
if err != nil {
return retry.RetryableError(err)
}
@@ -103,9 +105,26 @@ func (m *MemberList) broadcastRaftAddress(ctx context.Context) {
m.broadcastQueue.QueueBroadcast(&msg)
}
// The ForwardDeleteKey function is only called by non-leaders.
// It uses the broadcast queue to forward a key eviction command within the cluster.
func (m *MemberList) ForwardDeleteKey(ctx context.Context, key string) {
connId, _ := ctx.Value(utils.ContextConnID("ConnectionID")).(string)
m.broadcastQueue.QueueBroadcast(&BroadcastMessage{
Action: "DeleteKey",
Content: []byte(key),
ContentHash: md5.Sum([]byte(key)),
ConnId: connId,
NodeMeta: NodeMeta{
ServerID: raft.ServerID(m.options.Config.ServerID),
RaftAddr: raft.ServerAddress(fmt.Sprintf("%s:%d",
m.options.Config.BindAddr, m.options.Config.RaftBindPort)),
},
})
}
// The ForwardDataMutation function is only called by non-leaders.
// It uses the broadcast queue to forward a data mutation within the cluster.
func (m *MemberList) ForwardDataMutation(ctx context.Context, cmd []byte) {
// This function is only called by non-leaders
// It uses the broadcast queue to forward a data mutation within the cluster
connId, _ := ctx.Value(utils.ContextConnID("ConnectionID")).(string)
m.broadcastQueue.QueueBroadcast(&BroadcastMessage{
Action: "MutateData",

View File

@@ -15,6 +15,7 @@ type FSMOpts struct {
Config utils.Config
Server utils.Server
GetCommand func(command string) (utils.Command, error)
DeleteKey func(ctx context.Context, key string) error
}
type FSM struct {
@@ -53,7 +54,16 @@ func (fsm *FSM) Apply(log *raft.Log) interface{} {
}
case "delete-key":
// TODO: Handle key deletion
if err := fsm.options.DeleteKey(ctx, request.Key); err != nil {
return utils.ApplyResponse{
Error: err,
Response: nil,
}
}
return utils.ApplyResponse{
Error: nil,
Response: []byte("OK"),
}
case "command":
// Handle command

View File

@@ -20,6 +20,7 @@ type Opts struct {
Config utils.Config
Server utils.Server
GetCommand func(command string) (utils.Command, error)
DeleteKey func(ctx context.Context, key string) error
}
type Raft struct {
@@ -94,6 +95,7 @@ func (r *Raft) RaftInit(ctx context.Context) {
Config: r.options.Config,
Server: r.options.Server,
GetCommand: r.options.GetCommand,
DeleteKey: r.options.DeleteKey,
}),
logStore,
stableStore,

View File

@@ -85,10 +85,25 @@ func (server *Server) KeyExists(ctx context.Context, key string) bool {
}
if entry.ExpireAt != (time.Time{}) && entry.ExpireAt.Before(time.Now()) {
if !server.IsInCluster() {
// If in standalone mode, delete the key directly.
err := server.DeleteKey(ctx, key)
if err != nil {
log.Printf("keyExists: %+v\n", err)
}
} else if server.IsInCluster() && server.raft.IsRaftLeader() {
// If we're in a raft cluster, and we're the leader, send command to delete the key in the cluster.
err := server.raftApplyDeleteKey(ctx, key)
if err != nil {
log.Printf("keyExists: %+v\n", err)
}
} else if server.IsInCluster() && !server.raft.IsRaftLeader() {
// Forward message to leader to initiate key deletion.
// This is always called regardless of ForwardCommand config value
// because we always want to remove expired keys.
server.memberList.ForwardDeleteKey(ctx, key)
}
return false
}
@@ -251,6 +266,8 @@ func (server *Server) DeleteKey(ctx context.Context, key string) error {
server.lruCache.cache.Delete(key)
}
log.Printf("deleted key %s\n", key)
return nil
}

View File

@@ -94,14 +94,16 @@ func NewServer(opts Opts) *Server {
Config: opts.Config,
Server: server,
GetCommand: server.getCommand,
DeleteKey: server.DeleteKey,
})
server.memberList = memberlist.NewMemberList(memberlist.MemberlistOpts{
server.memberList = memberlist.NewMemberList(memberlist.Opts{
Config: opts.Config,
HasJoinedCluster: server.raft.HasJoinedCluster,
AddVoter: server.raft.AddVoter,
RemoveRaftServer: server.raft.RemoveServer,
IsRaftLeader: server.raft.IsRaftLeader,
ApplyMutate: server.raftApplyCommand,
ApplyDeleteKey: server.raftApplyDeleteKey,
})
} else {
// Set up standalone snapshot engine