Skip to content

Commit

Permalink
Sarthak | Adds InMemoryMap abstraction that will be used in the works…
Browse files Browse the repository at this point in the history
…hop in place of skiplist
  • Loading branch information
SarthakMakhija committed Apr 10, 2023
1 parent 0a77b9c commit 7399782
Show file tree
Hide file tree
Showing 2 changed files with 189 additions and 0 deletions.
69 changes: 69 additions & 0 deletions storage/memory/InMemoryMap.go
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
}
120 changes: 120 additions & 0 deletions storage/memory/InMemoryMap_test.go
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())
}
}

0 comments on commit 7399782

Please sign in to comment.