Skip to content
Snippets Groups Projects
Commit 0a1e1fa3 authored by Josh Brooks's avatar Josh Brooks
Browse files

Finalize uncheckedRoundStore design

parent 1773cc6d
Branches
Tags
1 merge request!23Release
///////////////////////////////////////////////////////////////////////////////
// Copyright © 2020 xx network SEZC //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file //
///////////////////////////////////////////////////////////////////////////////
package rounds package rounds
import ( import (
...@@ -14,16 +21,23 @@ import ( ...@@ -14,16 +21,23 @@ import (
) )
const ( const (
uncheckRoundVersion = 0 uncheckedRoundVersion = 0
uncheckRoundPrefix = "uncheckedRoundPrefix" uncheckedRoundPrefix = "uncheckedRoundPrefix"
// Key to store round list // Key to store round list
uncheckedRoundListKey = "uncheckRounds" uncheckedRoundListKey = "uncheckRounds"
// Key to store individual round // Key to store individual round
uncheckedRoundKey = "uncheckedRound-" uncheckedRoundKey = "uncheckedRound-"
// Housekeeping constant (used for storage of uint64 ie id.Round) // Housekeeping constant (used for serializing uint64 ie id.Round)
uint64Size = 8 uint64Size = 8
) )
// Round identity information used in message retrieval
// Derived from reception.Identity
type Identity struct {
EpdId ephemeral.Id
Source *id.ID
}
// Unchecked round structure is rounds which failed on message retrieval // Unchecked round structure is rounds which failed on message retrieval
// These rounds are stored for retry of message retrieval // These rounds are stored for retry of message retrieval
type UncheckedRound struct { type UncheckedRound struct {
...@@ -36,13 +50,6 @@ type UncheckedRound struct { ...@@ -36,13 +50,6 @@ type UncheckedRound struct {
NumTries uint NumTries uint
} }
// Round identity information used in message retrieval
// Derived from reception.Identity
type Identity struct {
EpdId ephemeral.Id
Source *id.ID
}
// Storage object saving rounds to retry for message retrieval // Storage object saving rounds to retry for message retrieval
type UncheckedRoundStore struct { type UncheckedRoundStore struct {
list map[id.Round]UncheckedRound list map[id.Round]UncheckedRound
...@@ -52,7 +59,7 @@ type UncheckedRoundStore struct { ...@@ -52,7 +59,7 @@ type UncheckedRoundStore struct {
// Constructor for a UncheckedRoundStore // Constructor for a UncheckedRoundStore
func NewUncheckedStore(kv *versioned.KV) (*UncheckedRoundStore, error) { func NewUncheckedStore(kv *versioned.KV) (*UncheckedRoundStore, error) {
kv = kv.Prefix(uncheckRoundPrefix) kv = kv.Prefix(uncheckedRoundPrefix)
urs := &UncheckedRoundStore{ urs := &UncheckedRoundStore{
list: make(map[id.Round]UncheckedRound, 0), list: make(map[id.Round]UncheckedRound, 0),
...@@ -66,8 +73,8 @@ func NewUncheckedStore(kv *versioned.KV) (*UncheckedRoundStore, error) { ...@@ -66,8 +73,8 @@ func NewUncheckedStore(kv *versioned.KV) (*UncheckedRoundStore, error) {
// Loads an deserializes a UncheckedRoundStore from memory // Loads an deserializes a UncheckedRoundStore from memory
func LoadUncheckedStore(kv *versioned.KV) (*UncheckedRoundStore, error) { func LoadUncheckedStore(kv *versioned.KV) (*UncheckedRoundStore, error) {
kv = kv.Prefix(uncheckRoundPrefix) kv = kv.Prefix(uncheckedRoundPrefix)
vo, err := kv.Get(uncheckedRoundListKey, uncheckRoundVersion) vo, err := kv.Get(uncheckedRoundListKey, uncheckedRoundVersion)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -102,6 +109,8 @@ func LoadUncheckedStore(kv *versioned.KV) (*UncheckedRoundStore, error) { ...@@ -102,6 +109,8 @@ func LoadUncheckedStore(kv *versioned.KV) (*UncheckedRoundStore, error) {
func (s *UncheckedRoundStore) AddRound(rid id.Round, ephID ephemeral.Id, source *id.ID) error { func (s *UncheckedRoundStore) AddRound(rid id.Round, ephID ephemeral.Id, source *id.ID) error {
s.mux.Lock() s.mux.Lock()
defer s.mux.Unlock() defer s.mux.Unlock()
if _, exists := s.list[rid]; !exists {
newUncheckedRound := UncheckedRound{ newUncheckedRound := UncheckedRound{
Rid: rid, Rid: rid,
Identity: Identity{ Identity: Identity{
...@@ -117,6 +126,9 @@ func (s *UncheckedRoundStore) AddRound(rid id.Round, ephID ephemeral.Id, source ...@@ -117,6 +126,9 @@ func (s *UncheckedRoundStore) AddRound(rid id.Round, ephID ephemeral.Id, source
return s.save() return s.save()
} }
return nil
}
// Retrieves an UncheckedRound from the map, if it exists // Retrieves an UncheckedRound from the map, if it exists
func (s *UncheckedRoundStore) GetRound(rid id.Round) (UncheckedRound, bool) { func (s *UncheckedRoundStore) GetRound(rid id.Round) (UncheckedRound, bool) {
s.mux.RLock() s.mux.RLock()
...@@ -133,15 +145,18 @@ func (s *UncheckedRoundStore) GetList() map[id.Round]UncheckedRound { ...@@ -133,15 +145,18 @@ func (s *UncheckedRoundStore) GetList() map[id.Round]UncheckedRound {
} }
// Increments the amount of checks performed on this stored round // Increments the amount of checks performed on this stored round
func (s *UncheckedRoundStore) IncrementCheck(rid id.Round) { func (s *UncheckedRoundStore) IncrementCheck(rid id.Round) error {
s.mux.Lock() s.mux.Lock()
defer s.mux.Unlock() defer s.mux.Unlock()
rnd, exists := s.list[rid] rnd, exists := s.list[rid]
if !exists { if !exists {
return return errors.Errorf("round %d could not be found in RAM", rid)
} }
rnd.NumTries++ rnd.NumTries++
return rnd.store(s.kv)
} }
// Remove deletes a round from UncheckedRoundStore's list and from storage // Remove deletes a round from UncheckedRoundStore's list and from storage
...@@ -150,7 +165,7 @@ func (s *UncheckedRoundStore) Remove(rid id.Round) error { ...@@ -150,7 +165,7 @@ func (s *UncheckedRoundStore) Remove(rid id.Round) error {
defer s.mux.Unlock() defer s.mux.Unlock()
delete(s.list, rid) delete(s.list, rid)
return s.kv.Delete(roundStoreKey(rid), uncheckRoundVersion) return s.kv.Delete(roundStoreKey(rid), uncheckedRoundVersion)
} }
...@@ -177,13 +192,13 @@ func (s *UncheckedRoundStore) saveRoundList() error { ...@@ -177,13 +192,13 @@ func (s *UncheckedRoundStore) saveRoundList() error {
// Create the versioned object // Create the versioned object
obj := &versioned.Object{ obj := &versioned.Object{
Version: uncheckRoundVersion, Version: uncheckedRoundVersion,
Timestamp: netTime.Now(), Timestamp: netTime.Now(),
Data: serializeRoundList(s.list), Data: serializeRoundList(s.list),
} }
// Save to storage // Save to storage
err := s.kv.Set(uncheckedRoundListKey, uncheckRoundVersion, obj) err := s.kv.Set(uncheckedRoundListKey, uncheckedRoundVersion, obj)
if err != nil { if err != nil {
return errors.WithMessage(err, "Failed to store round ID list") return errors.WithMessage(err, "Failed to store round ID list")
} }
...@@ -211,12 +226,12 @@ func (r UncheckedRound) store(kv *versioned.KV) error { ...@@ -211,12 +226,12 @@ func (r UncheckedRound) store(kv *versioned.KV) error {
} }
obj := &versioned.Object{ obj := &versioned.Object{
Version: uncheckRoundVersion, Version: uncheckedRoundVersion,
Timestamp: netTime.Now(), Timestamp: netTime.Now(),
Data: data, Data: data,
} }
return kv.Set(roundStoreKey(r.Rid), uncheckRoundVersion, obj) return kv.Set(roundStoreKey(r.Rid), uncheckedRoundVersion, obj)
} }
...@@ -256,7 +271,7 @@ func (r UncheckedRound) Serialize() ([]byte, error) { ...@@ -256,7 +271,7 @@ func (r UncheckedRound) Serialize() ([]byte, error) {
// loadRound pulls an UncheckedRound corresponding to roundId from storage // loadRound pulls an UncheckedRound corresponding to roundId from storage
func loadRound(roundId id.Round, kv *versioned.KV) (UncheckedRound, error) { func loadRound(roundId id.Round, kv *versioned.KV) (UncheckedRound, error) {
vo, err := kv.Get(roundStoreKey(roundId), uncheckRoundVersion) vo, err := kv.Get(roundStoreKey(roundId), uncheckedRoundVersion)
if err != nil { if err != nil {
return UncheckedRound{}, errors.WithMessagef(err, "Could not find %d in storage", roundId) return UncheckedRound{}, errors.WithMessagef(err, "Could not find %d in storage", roundId)
} }
......
///////////////////////////////////////////////////////////////////////////////
// Copyright © 2020 xx network SEZC //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file //
///////////////////////////////////////////////////////////////////////////////
package rounds
import (
"gitlab.com/elixxir/client/storage/versioned"
"gitlab.com/elixxir/ekv"
"gitlab.com/xx_network/primitives/id"
"reflect"
"sync"
"testing"
)
func TestNewUncheckedStore(t *testing.T) {
kv := versioned.NewKV(make(ekv.Memstore))
testStore := &UncheckedRoundStore{
list: make(map[id.Round]UncheckedRound),
kv: kv.Prefix(uncheckedRoundPrefix),
}
store, err := NewUncheckedStore(kv)
if err != nil {
t.Fatalf("NewUncheckedStore error: " +
"Could not create unchecked stor: %v", err)
}
// Compare manually created object with NewUnknownRoundsStore
if !reflect.DeepEqual(testStore, store) {
t.Fatalf("NewUncheckedStore error: " +
"Returned incorrect Store."+
"\n\texpected: %+v\n\treceived: %+v", testStore, store)
}
UnknownRounds{
rounds: nil,
params: UnknownRoundsParams{},
kv: nil,
mux: sync.Mutex{},
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment