-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Sarthak | Adds InMemoryMap abstraction that will be used in the works…
…hop in place of skiplist
- Loading branch information
1 parent
0a77b9c
commit 7399782
Showing
2 changed files
with
189 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package memory | ||
|
||
import ( | ||
"sort" | ||
"storage-engine-workshop/db/model" | ||
"storage-engine-workshop/storage/comparator" | ||
) | ||
|
||
type InMemoryMap struct { | ||
keyValues map[string]model.Slice | ||
} | ||
|
||
func NewInMemoryMap() *InMemoryMap { | ||
return &InMemoryMap{ | ||
keyValues: make(map[string]model.Slice), | ||
} | ||
} | ||
|
||
func (inMemoryMap *InMemoryMap) Put(key model.Slice, value model.Slice) bool { | ||
keyAsString := key.AsString() | ||
if _, ok := inMemoryMap.keyValues[keyAsString]; ok { | ||
return false | ||
} | ||
inMemoryMap.keyValues[keyAsString] = value | ||
return true | ||
} | ||
|
||
func (inMemoryMap *InMemoryMap) Get(key model.Slice) model.GetResult { | ||
keyAsString := key.AsString() | ||
if value, ok := inMemoryMap.keyValues[keyAsString]; ok { | ||
return model.GetResult{ | ||
Key: key, | ||
Value: value, | ||
Exists: true, | ||
} | ||
} | ||
return model.GetResult{ | ||
Key: key, | ||
Value: model.NilSlice(), | ||
Exists: false, | ||
} | ||
} | ||
|
||
func (inMemoryMap *InMemoryMap) MultiGet(keys []model.Slice) (model.MultiGetResult, []model.Slice) { | ||
response := model.MultiGetResult{} | ||
var missingKeys []model.Slice | ||
|
||
for _, key := range keys { | ||
getResult := inMemoryMap.Get(key) | ||
if getResult.Exists { | ||
response.Add(getResult) | ||
} else { | ||
missingKeys = append(missingKeys, key) | ||
} | ||
} | ||
return response, missingKeys | ||
} | ||
|
||
func (inMemoryMap *InMemoryMap) AllKeyValues(keyComparator comparator.KeyComparator) []model.KeyValuePair { | ||
var pairs []model.KeyValuePair | ||
for key, value := range inMemoryMap.keyValues { | ||
pairs = append(pairs, model.KeyValuePair{Key: model.NewSlice([]byte(key)), Value: value}) | ||
} | ||
|
||
sort.SliceStable(pairs, func(i, j int) bool { | ||
return keyComparator.Compare(pairs[i].Key, pairs[j].Key) < 0 | ||
}) | ||
return pairs | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package memory | ||
|
||
import ( | ||
"reflect" | ||
"storage-engine-workshop/db/model" | ||
"storage-engine-workshop/storage/comparator" | ||
"testing" | ||
) | ||
|
||
func TestPutsAKeyValueAndGetByKeyInMemoryMap(t *testing.T) { | ||
sentinelNode := NewInMemoryMap() | ||
|
||
key := model.NewSlice([]byte("HDD")) | ||
value := model.NewSlice([]byte("Hard disk")) | ||
|
||
sentinelNode.Put(key, value) | ||
|
||
getResult := sentinelNode.Get(key) | ||
if getResult.Value.AsString() != "Hard disk" { | ||
t.Fatalf("Expected %v, received %v", "Hard disk", getResult.Value.AsString()) | ||
} | ||
} | ||
|
||
func TestPutAKeyValueAndAssertsItsExistenceInMemoryMap(t *testing.T) { | ||
sentinelNode := NewInMemoryMap() | ||
|
||
key := model.NewSlice([]byte("HDD")) | ||
value := model.NewSlice([]byte("Hard disk")) | ||
|
||
sentinelNode.Put(key, value) | ||
|
||
getResult := sentinelNode.Get(key) | ||
if getResult.Exists != true { | ||
t.Fatalf("Expected key to exist, but it did not. Key was %v", "HDD") | ||
} | ||
} | ||
|
||
func TestPutsKeyValuesAndDoesMultiGetByKeysInMemoryMap(t *testing.T) { | ||
sentinelNode := NewInMemoryMap() | ||
|
||
sentinelNode.Put(model.NewSlice([]byte("HDD")), model.NewSlice([]byte("Hard disk"))) | ||
sentinelNode.Put(model.NewSlice([]byte("SDD")), model.NewSlice([]byte("Solid state"))) | ||
|
||
keys := []model.Slice{ | ||
model.NewSlice([]byte("HDD")), | ||
model.NewSlice([]byte("SDD")), | ||
} | ||
multiGetResult, _ := sentinelNode.MultiGet(keys) | ||
allGetResults := multiGetResult.Values | ||
|
||
expected := []model.GetResult{ | ||
{Value: model.NewSlice([]byte("Hard disk")), Exists: true}, | ||
{Value: model.NewSlice([]byte("Solid state")), Exists: true}, | ||
} | ||
|
||
for index, e := range expected { | ||
if e.Value.AsString() != allGetResults[index].Value.AsString() { | ||
t.Fatalf("Expected %v, received %v", e.Value.AsString(), allGetResults[index].Value.AsString()) | ||
} | ||
} | ||
} | ||
|
||
func TestPutsKeyValuesAndDoesMultiGetByKeysWithMissingKeysInMemoryMap(t *testing.T) { | ||
sentinelNode := NewInMemoryMap() | ||
|
||
sentinelNode.Put(model.NewSlice([]byte("HDD")), model.NewSlice([]byte("Hard disk"))) | ||
sentinelNode.Put(model.NewSlice([]byte("SDD")), model.NewSlice([]byte("Solid state"))) | ||
|
||
keys := []model.Slice{ | ||
model.NewSlice([]byte("HDD")), | ||
model.NewSlice([]byte("SDD")), | ||
model.NewSlice([]byte("PMEM")), | ||
} | ||
multiGetResult, missingKeys := sentinelNode.MultiGet(keys) | ||
allGetResults := multiGetResult.Values | ||
|
||
expected := []model.GetResult{ | ||
{Value: model.NewSlice([]byte("Hard disk")), Exists: true}, | ||
{Value: model.NewSlice([]byte("Solid state")), Exists: true}, | ||
} | ||
expectedMissing := []model.Slice{ | ||
model.NewSlice([]byte("PMEM")), | ||
} | ||
|
||
for index, e := range expected { | ||
if e.Value.AsString() != allGetResults[index].Value.AsString() { | ||
t.Fatalf("Expected %v, received %v", e.Value.AsString(), allGetResults[index].Value.AsString()) | ||
} | ||
} | ||
if !reflect.DeepEqual(missingKeys, expectedMissing) { | ||
t.Fatalf("Expected missing keys to be %v, received %v", missingKeys, expectedMissing) | ||
} | ||
} | ||
|
||
func TestGetsAllKeyValuesInMemoryMap(t *testing.T) { | ||
keyComparator := comparator.StringKeyComparator{} | ||
|
||
sentinelNode := NewInMemoryMap() | ||
key := model.NewSlice([]byte("HDD")) | ||
value := model.NewSlice([]byte("Hard disk")) | ||
|
||
sentinelNode.Put(key, value) | ||
sentinelNode.Put(model.NewSlice([]byte("Disk")), model.NewSlice([]byte("SSD"))) | ||
|
||
keyValuePairs := sentinelNode.AllKeyValues(keyComparator) | ||
|
||
if keyValuePairs[0].Key.AsString() != model.NewSlice([]byte("Disk")).AsString() { | ||
t.Fatalf("Expected persistent key to be %v received %v", model.NewSlice([]byte("Disk")).AsString(), keyValuePairs[0].Key.AsString()) | ||
} | ||
if keyValuePairs[1].Key.AsString() != key.AsString() { | ||
t.Fatalf("Expected persistent key to be %v received %v", key.AsString(), keyValuePairs[0].Key.AsString()) | ||
} | ||
|
||
if keyValuePairs[0].Value.AsString() != model.NewSlice([]byte("SSD")).AsString() { | ||
t.Fatalf("Expected persistent value to be %v received %v", model.NewSlice([]byte("SSD")).AsString(), keyValuePairs[0].Value.AsString()) | ||
} | ||
if keyValuePairs[1].Value.AsString() != value.AsString() { | ||
t.Fatalf("Expected persistent value to be %v received %v", value.AsString(), keyValuePairs[0].Value.AsString()) | ||
} | ||
} |