From d87e43cd3240c646ca71aceb90a5fbb953c78670 Mon Sep 17 00:00:00 2001 From: Kleissner Date: Wed, 11 Aug 2021 20:15:22 +0200 Subject: [PATCH] Simplify Store interface. Remove unused replication placeholder and untangle expiration option. MemoryStore is refactored into separate file. --- Kademlia.go | 4 +-- store/Memory.go | 73 ++++++++++++++++++++++++++++++++++++++++ store/Store.go | 89 +++++-------------------------------------------- 3 files changed, 84 insertions(+), 82 deletions(-) create mode 100644 store/Memory.go diff --git a/Kademlia.go b/Kademlia.go index 1513848..bf12912 100644 --- a/Kademlia.go +++ b/Kademlia.go @@ -153,14 +153,14 @@ func GetDataDHT(hash []byte) (data []byte, senderNodeID []byte, found bool) { // StoreDataLocal stores data into the local warehouse. func StoreDataLocal(data []byte) error { key := hashData(data) - return Warehouse.Store(key, data, time.Time{}, time.Time{}) + return Warehouse.Store(key, data) } // StoreDataDHT stores data locally and informs closestCount peers in the DHT about it. // Remote peers may choose to keep a record (in case another peers asks) or mirror the full data. func StoreDataDHT(data []byte, closestCount int) error { key := hashData(data) - if err := Warehouse.Store(key, data, time.Time{}, time.Time{}); err != nil { + if err := Warehouse.Store(key, data); err != nil { return err } return nodesDHT.Store(key, uint64(len(data)), closestCount) diff --git a/store/Memory.go b/store/Memory.go new file mode 100644 index 0000000..f354af5 --- /dev/null +++ b/store/Memory.go @@ -0,0 +1,73 @@ +/* +File Name: Memory.go +Copyright: 2021 Peernet s.r.o. +Author: Peter Kleissner +*/ + +package store + +import ( + "sync" + "time" +) + +// MemoryStore is a simple in-memory key/value store for testing purposes. +type MemoryStore struct { + mutex *sync.Mutex + data map[string][]byte + expireMap map[string]time.Time +} + +// NewMemoryStore create a properly initialized memory store. +func NewMemoryStore() *MemoryStore { + return &MemoryStore{ + data: make(map[string][]byte), + mutex: &sync.Mutex{}, + expireMap: make(map[string]time.Time), + } +} + +// ExpireKeys is called to delete all keys that are marked for expiration. +func (ms *MemoryStore) ExpireKeys() { + ms.mutex.Lock() + defer ms.mutex.Unlock() + for k, v := range ms.expireMap { + if time.Now().After(v) { + delete(ms.expireMap, k) + delete(ms.data, k) + } + } +} + +// Store stores the key/value pair. +func (ms *MemoryStore) Store(key []byte, data []byte) error { + ms.mutex.Lock() + ms.data[string(key)] = data + ms.mutex.Unlock() + return nil +} + +// StoreExpire stores the key/value pair and deletes it after the expiration time. +func (ms *MemoryStore) StoreExpire(key []byte, data []byte, expiration time.Time) error { + ms.mutex.Lock() + ms.expireMap[string(key)] = expiration + ms.data[string(key)] = data + ms.mutex.Unlock() + return nil +} + +// Retrieve returns the value for the key if present. +func (ms *MemoryStore) Retrieve(key []byte) (data []byte, found bool) { + ms.mutex.Lock() + data, found = ms.data[string(key)] + ms.mutex.Unlock() + return data, found +} + +// Delete deletes a key/value pair. +func (ms *MemoryStore) Delete(key []byte) { + ms.mutex.Lock() + delete(ms.expireMap, string(key)) + delete(ms.data, string(key)) + ms.mutex.Unlock() +} diff --git a/store/Store.go b/store/Store.go index 5c71fd1..f4110bd 100644 --- a/store/Store.go +++ b/store/Store.go @@ -9,95 +9,24 @@ Simple key-value store implementation. Currently in-memory only. package store import ( - "sync" "time" ) // Store is the interface for implementing the storage mechanism for the DHT. type Store interface { - // Store should store a key/value pair for the local node with the given replication and expiration times. - Store(key []byte, data []byte, replication time.Time, expiration time.Time) error + // Store stores the key/value pair. + Store(key []byte, data []byte) error - // Retrieve should return the local key/value if it exists. + // StoreExpire stores the key/value pair and deletes it after the expiration time. + // If key/value already exists, it will be overwritten and the new expiration time applies. + StoreExpire(key []byte, data []byte, expiration time.Time) error + + // Retrieve returns the value for the key if present. Retrieve(key []byte) (data []byte, found bool) - // Delete should delete a key/value pair from the Store + // Delete deletes a key/value pair. Delete(key []byte) - // GetAllKeysForReplication should return the keys of all data to be replicated across the network. Typically all data should be replicated every tReplicate seconds. - GetAllKeysForReplication() [][]byte - - // ExpireKeys should expire all key/values due for expiration. + // ExpireKeys is called to delete all keys that are marked for expiration. ExpireKeys() } - -// NewMemoryStore create a properly initialized memory store. -func NewMemoryStore() *MemoryStore { - return &MemoryStore{ - data: make(map[string][]byte), - mutex: &sync.Mutex{}, - replicateMap: make(map[string]time.Time), - expireMap: make(map[string]time.Time), - } -} - -// MemoryStore is a simple in-memory key/value store used for unit testing, and the CLI example -type MemoryStore struct { - mutex *sync.Mutex - data map[string][]byte - replicateMap map[string]time.Time - expireMap map[string]time.Time -} - -// GetAllKeysForReplication should return the keys of all data to be replicated across the network. Typically all data should be replicated every tReplicate seconds. -func (ms *MemoryStore) GetAllKeysForReplication() [][]byte { - ms.mutex.Lock() - defer ms.mutex.Unlock() - var keys [][]byte - for k := range ms.data { - if time.Now().After(ms.replicateMap[k]) { - keys = append(keys, []byte(k)) - } - } - return keys -} - -// ExpireKeys should expire all key/values due for expiration. -func (ms *MemoryStore) ExpireKeys() { - ms.mutex.Lock() - defer ms.mutex.Unlock() - for k, v := range ms.expireMap { - if time.Now().After(v) { - delete(ms.replicateMap, k) - delete(ms.expireMap, k) - delete(ms.data, k) - } - } -} - -// Store will store a key/value pair for the local node with the given replication and expiration times. -func (ms *MemoryStore) Store(key []byte, data []byte, replication time.Time, expiration time.Time) error { - ms.mutex.Lock() - defer ms.mutex.Unlock() - ms.replicateMap[string(key)] = replication - ms.expireMap[string(key)] = expiration - ms.data[string(key)] = data - return nil -} - -// Retrieve will return the local key/value if it exists -func (ms *MemoryStore) Retrieve(key []byte) (data []byte, found bool) { - ms.mutex.Lock() - defer ms.mutex.Unlock() - data, found = ms.data[string(key)] - return data, found -} - -// Delete deletes a key/value pair from the MemoryStore -func (ms *MemoryStore) Delete(key []byte) { - ms.mutex.Lock() - defer ms.mutex.Unlock() - delete(ms.replicateMap, string(key)) - delete(ms.expireMap, string(key)) - delete(ms.data, string(key)) -}