Updated RAFT layer to use new keyspace methods. Fixed API methods for HSET and SINTERCARD to match new key overwriting behaviour.

This commit is contained in:
Kelvin Clement Mwinuka
2024-05-26 15:49:51 +08:00
parent 98f4ca3a65
commit 93a616c5c1
7 changed files with 1356 additions and 355 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -616,13 +616,13 @@ func TestEchoVault_HSET(t *testing.T) {
wantErr: false, wantErr: false,
}, },
{ {
name: "HSET returns error when the target key is not a map", name: "HSET overwrites when the target key is not a map",
key: "key6", key: "key6",
presetValue: "Default preset value", presetValue: "Default preset value",
fieldValuePairs: map[string]string{"field1": "value1"}, fieldValuePairs: map[string]string{"field1": "value1"},
hsetFunc: server.HSet, hsetFunc: server.HSet,
want: 0, want: 1,
wantErr: true, wantErr: false,
}, },
} }
for _, tt := range tests { for _, tt := range tests {

View File

@@ -467,13 +467,12 @@ func TestEchoVault_SINTERCARD(t *testing.T) {
wantErr: false, wantErr: false,
}, },
{ {
name: "Return 0 if any of the keys does not exist", name: "Return error if any of the keys is non-existent",
presetValues: map[string]interface{}{ presetValues: map[string]interface{}{
"key11": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), "key11": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
"key12": "Default value",
"key13": set.NewSet([]string{"one"}), "key13": set.NewSet([]string{"one"}),
}, },
keys: []string{"key11", "key12", "key13", "non-existent"}, keys: []string{"key11", "key12", "key13"},
limit: 0, limit: 0,
want: 0, want: 0,
wantErr: false, wantErr: false,

View File

@@ -190,36 +190,39 @@ func NewEchoVault(options ...func(echovault *EchoVault)) (*EchoVault, error) {
} }
if echovault.isInCluster() { if echovault.isInCluster() {
// TODO: Uncomment this echovault.raft = raft.NewRaft(raft.Opts{
// echovault.raft = raft.NewRaft(raft.Opts{ Config: echovault.config,
// Config: echovault.config, GetCommand: echovault.getCommand,
// GetCommand: echovault.getCommand, SetValues: echovault.setValues,
// SetValue: echovault.SetValue, SetExpiry: echovault.setExpiry,
// SetExpiry: echovault.SetExpiry, StartSnapshot: echovault.startSnapshot,
// DeleteKey: echovault.DeleteKey, FinishSnapshot: echovault.finishSnapshot,
// StartSnapshot: echovault.startSnapshot, SetLatestSnapshotTime: echovault.setLatestSnapshot,
// FinishSnapshot: echovault.finishSnapshot, GetHandlerFuncParams: echovault.getHandlerFuncParams,
// SetLatestSnapshotTime: echovault.setLatestSnapshot, DeleteKey: func(key string) error {
// GetHandlerFuncParams: echovault.getHandlerFuncParams, echovault.storeLock.Lock()
// GetState: func() map[string]internal.KeyData { defer echovault.storeLock.Unlock()
// state := make(map[string]internal.KeyData) return echovault.deleteKey(key)
// for k, v := range echovault.getState() { },
// if data, ok := v.(internal.KeyData); ok { GetState: func() map[string]internal.KeyData {
// state[k] = data state := make(map[string]internal.KeyData)
// } for k, v := range echovault.getState() {
// } if data, ok := v.(internal.KeyData); ok {
// return state state[k] = data
// }, }
// }) }
// echovault.memberList = memberlist.NewMemberList(memberlist.Opts{ return state
// Config: echovault.config, },
// HasJoinedCluster: echovault.raft.HasJoinedCluster, })
// AddVoter: echovault.raft.AddVoter, echovault.memberList = memberlist.NewMemberList(memberlist.Opts{
// RemoveRaftServer: echovault.raft.RemoveServer, Config: echovault.config,
// IsRaftLeader: echovault.raft.IsRaftLeader, HasJoinedCluster: echovault.raft.HasJoinedCluster,
// ApplyMutate: echovault.raftApplyCommand, AddVoter: echovault.raft.AddVoter,
// ApplyDeleteKey: echovault.raftApplyDeleteKey, RemoveRaftServer: echovault.raft.RemoveServer,
// }) IsRaftLeader: echovault.raft.IsRaftLeader,
ApplyMutate: echovault.raftApplyCommand,
ApplyDeleteKey: echovault.raftApplyDeleteKey,
})
} else { } else {
// Set up standalone snapshot engine // Set up standalone snapshot engine
echovault.snapshotEngine = snapshot.NewSnapshotEngine( echovault.snapshotEngine = snapshot.NewSnapshotEngine(

View File

@@ -116,7 +116,7 @@ func Test_HandleHSET(t *testing.T) {
expectedError: nil, expectedError: nil,
}, },
{ {
name: "6. HSET returns error when the target key is not a map", name: "6. HSET overwrites when the target key is not a map",
key: "HsetKey6", key: "HsetKey6",
presetValue: "Default preset value", presetValue: "Default preset value",
command: []string{"HSET", "HsetKey6", "field1", "value1"}, command: []string{"HSET", "HsetKey6", "field1", "value1"},

View File

@@ -32,11 +32,9 @@ type FSMOpts struct {
Config config.Config Config config.Config
GetState func() map[string]internal.KeyData GetState func() map[string]internal.KeyData
GetCommand func(command string) (internal.Command, error) GetCommand func(command string) (internal.Command, error)
CreateKeyAndLock func(ctx context.Context, key string) (bool, error) SetValues func(ctx context.Context, entries map[string]interface{}) error
SetValue func(ctx context.Context, key string, value interface{}) error
SetExpiry func(ctx context.Context, key string, expire time.Time, touch bool) SetExpiry func(ctx context.Context, key string, expire time.Time, touch bool)
KeyUnlock func(ctx context.Context, key string) DeleteKey func(key string) error
DeleteKey func(ctx context.Context, key string) error
StartSnapshot func() StartSnapshot func()
FinishSnapshot func() FinishSnapshot func()
SetLatestSnapshotTime func(msec int64) SetLatestSnapshotTime func(msec int64)
@@ -79,7 +77,7 @@ func (fsm *FSM) Apply(log *raft.Log) interface{} {
} }
case "delete-key": case "delete-key":
if err := fsm.options.DeleteKey(ctx, request.Key); err != nil { if err := fsm.options.DeleteKey(request.Key); err != nil {
return internal.ApplyResponse{ return internal.ApplyResponse{
Error: err, Error: err,
Response: nil, Response: nil,
@@ -164,14 +162,10 @@ func (fsm *FSM) Restore(snapshot io.ReadCloser) error {
// Set state // Set state
ctx := context.Background() ctx := context.Background()
for k, v := range internal.FilterExpiredKeys(time.Now(), data.State) { for k, v := range internal.FilterExpiredKeys(time.Now(), data.State) {
if _, err = fsm.options.CreateKeyAndLock(ctx, k); err != nil { if err = fsm.options.SetValues(ctx, map[string]interface{}{k: v.Value}); err != nil {
log.Fatal(err)
}
if err = fsm.options.SetValue(ctx, k, v.Value); err != nil {
log.Fatal(err) log.Fatal(err)
} }
fsm.options.SetExpiry(ctx, k, v.ExpireAt, false) fsm.options.SetExpiry(ctx, k, v.ExpireAt, false)
fsm.options.KeyUnlock(ctx, k)
} }
// Set latest snapshot milliseconds // Set latest snapshot milliseconds
fsm.options.SetLatestSnapshotTime(data.LatestSnapshotMilliseconds) fsm.options.SetLatestSnapshotTime(data.LatestSnapshotMilliseconds)

View File

@@ -33,13 +33,11 @@ import (
type Opts struct { type Opts struct {
Config config.Config Config config.Config
CreateKeyAndLock func(ctx context.Context, key string) (bool, error) SetValues func(ctx context.Context, entries map[string]interface{}) error
SetValue func(ctx context.Context, key string, value interface{}) error
SetExpiry func(ctx context.Context, key string, expire time.Time, touch bool) SetExpiry func(ctx context.Context, key string, expire time.Time, touch bool)
KeyUnlock func(ctx context.Context, key string)
GetState func() map[string]internal.KeyData GetState func() map[string]internal.KeyData
GetCommand func(command string) (internal.Command, error) GetCommand func(command string) (internal.Command, error)
DeleteKey func(ctx context.Context, key string) error DeleteKey func(key string) error
StartSnapshot func() StartSnapshot func()
FinishSnapshot func() FinishSnapshot func()
SetLatestSnapshotTime func(msec int64) SetLatestSnapshotTime func(msec int64)
@@ -118,10 +116,8 @@ func (r *Raft) RaftInit(ctx context.Context) {
Config: r.options.Config, Config: r.options.Config,
GetState: r.options.GetState, GetState: r.options.GetState,
GetCommand: r.options.GetCommand, GetCommand: r.options.GetCommand,
CreateKeyAndLock: r.options.CreateKeyAndLock, SetValues: r.options.SetValues,
SetValue: r.options.SetValue,
SetExpiry: r.options.SetExpiry, SetExpiry: r.options.SetExpiry,
KeyUnlock: r.options.KeyUnlock,
DeleteKey: r.options.DeleteKey, DeleteKey: r.options.DeleteKey,
StartSnapshot: r.options.StartSnapshot, StartSnapshot: r.options.StartSnapshot,
FinishSnapshot: r.options.FinishSnapshot, FinishSnapshot: r.options.FinishSnapshot,