diff --git a/storage/edge/edge.go b/storage/edge/edge.go index 88cd4f5b87df3777c90e3499c3021c0ea0eae88e..d8ac0acbc083e3d48cb6250becfd7730c08e23e8 100644 --- a/storage/edge/edge.go +++ b/storage/edge/edge.go @@ -33,8 +33,9 @@ func NewStore(kv *versioned.KV, baseIdentity *id.ID) (*Store, error) { kv = kv.Prefix(edgeStorePrefix) s := &Store{ - kv: kv, - edge: make(map[id.ID]Preimages), + kv: kv, + edge: make(map[id.ID]Preimages), + callbacks: make(map[id.ID][]ListUpdateCallBack), } defaultPreimages := newPreimages(baseIdentity) @@ -49,6 +50,8 @@ func NewStore(kv *versioned.KV, baseIdentity *id.ID) (*Store, error) { return s, s.save() } +// Add adds the Preimage to the list of the given identity and calls any +// associated callbacks. func (s *Store) Add(preimage Preimage, identity *id.ID) { s.mux.Lock() defer s.mux.Unlock() @@ -60,7 +63,7 @@ func (s *Store) Add(preimage Preimage, identity *id.ID) { } // Add to the list - preimages = preimages.add(preimage) + preimages.add(preimage) // Store the updated list if err := preimages.save(s.kv, identity); err != nil { @@ -97,16 +100,16 @@ func (s *Store) Remove(preimage Preimage, identity *id.ID) error { "identity cannot be found", preimage.Data, identity) } - preimagesNew := preimages.remove(preimage.Data) + preimages.remove(preimage.Data) - if len(preimagesNew) == 0 { + if len(preimages) == 0 { delete(s.edge, *identity) if err := s.save(); err != nil { jww.FATAL.Panicf("Failed to store edge store after removing "+ "preimage %v to identity %s: %+v", preimage.Data, identity, err) } - if err := preimagesNew.delete(s.kv, identity); err != nil { + if err := preimages.delete(s.kv, identity); err != nil { jww.FATAL.Panicf("Failed to delete preimage list store after "+ "removing preimage %v to identity %s: %+v", preimage.Data, identity, err) @@ -121,12 +124,12 @@ func (s *Store) Remove(preimage Preimage, identity *id.ID) error { return nil } - if err := preimagesNew.save(s.kv, identity); err != nil { + if err := preimages.save(s.kv, identity); err != nil { jww.FATAL.Panicf("Failed to store preimage list store after removing "+ "preimage %v to identity %s: %+v", preimage.Data, identity, err) } - s.edge[*identity] = preimagesNew + s.edge[*identity] = preimages // Call any callbacks to notify for i := range s.callbacks[*identity] { @@ -137,7 +140,7 @@ func (s *Store) Remove(preimage Preimage, identity *id.ID) error { return nil } -func (s *Store) Get(identity *id.ID) ([]Preimage, bool) { +func (s *Store) Get(identity *id.ID) (Preimages, bool) { s.mux.RLock() defer s.mux.RUnlock() diff --git a/storage/edge/edge_test.go b/storage/edge/edge_test.go index 19ce3404c09c25d4d6e27fad7fde5fbaa89c1fa6..6385b6114aae20e6dbfe7061cbb63535939666b7 100644 --- a/storage/edge/edge_test.go +++ b/storage/edge/edge_test.go @@ -30,8 +30,9 @@ func TestNewStore(t *testing.T) { kv := versioned.NewKV(make(ekv.Memstore)) baseIdentity := id.NewIdFromString("baseIdentity", id.User, t) expected := &Store{ - kv: kv.Prefix(edgeStorePrefix), - edge: map[id.ID]Preimages{*baseIdentity: newPreimages(baseIdentity)}, + kv: kv.Prefix(edgeStorePrefix), + edge: map[id.ID]Preimages{*baseIdentity: newPreimages(baseIdentity)}, + callbacks: make(map[id.ID][]ListUpdateCallBack), } received, err := NewStore(kv, baseIdentity) @@ -50,6 +51,9 @@ func TestNewStore(t *testing.T) { } } +// Adds three Preimage to the store, two with the same identity. It checks that +// all three exist and that the length of the list is correct. Also checks that +// the appropriate callbacks are called. func TestStore_Add(t *testing.T) { s, _, _ := newTestStore(t) identities := []*id.ID{ @@ -62,10 +66,53 @@ func TestStore_Add(t *testing.T) { {[]byte("ID2"), "default2", []byte("ID2")}, } - // id0Chan := make(chan bool, 2) - // s.callbacks[*identities[0]] = []ListUpdateCallBack{func(identity *id.ID, deleted bool) { - // id0Chan - // }} + id0Chan := make(chan struct { + identity *id.ID + deleted bool + }, 2) + s.callbacks[*identities[0]] = []ListUpdateCallBack{func(identity *id.ID, deleted bool) { + id0Chan <- struct { + identity *id.ID + deleted bool + }{identity: identity, deleted: deleted} + }} + + go func() { + for i := 0; i < 2; i++ { + select { + case <-time.NewTimer(10 * time.Millisecond).C: + t.Errorf("Timed out waiting for callback (%d).", i) + case r := <-id0Chan: + if !identities[0].Cmp(r.identity) { + t.Errorf("Received wrong identity (%d).\nexpected: %s"+ + "\nreceived: %s", i, identities[0], r.identity) + } + } + } + }() + + id1Chan := make(chan struct { + identity *id.ID + deleted bool + }) + s.callbacks[*identities[1]] = []ListUpdateCallBack{func(identity *id.ID, deleted bool) { + id1Chan <- struct { + identity *id.ID + deleted bool + }{identity: identity, deleted: deleted} + }} + + go func() { + select { + case <-time.NewTimer(10 * time.Millisecond).C: + t.Errorf("Timed out waiting for callback.") + case r := <-id0Chan: + if !identities[0].Cmp(r.identity) { + t.Errorf("Received wrong identity.\nexpected: %s\nreceived: %s", + identities[0], r.identity) + } + } + }() s.Add(preimages[0], identities[0]) s.Add(preimages[1], identities[1]) @@ -84,19 +131,19 @@ func TestStore_Add(t *testing.T) { } expected := Preimage{identities[0].Bytes(), "default", identities[0].Bytes()} - if !reflect.DeepEqual(pis[0], expected) { + if !reflect.DeepEqual(pis[expected.key()], expected) { t.Errorf("First Preimage of first Preimages does not match expected."+ - "\nexpected: %+v\nreceived: %+v", expected, pis[0]) + "\nexpected: %+v\nreceived: %+v", expected, pis[expected.key()]) } - if !reflect.DeepEqual(pis[1], preimages[0]) { + if !reflect.DeepEqual(pis[preimages[0].key()], preimages[0]) { t.Errorf("Second Preimage of first Preimages does not match expected."+ - "\nexpected: %+v\nreceived: %+v", preimages[0], pis[1]) + "\nexpected: %+v\nreceived: %+v", preimages[0], pis[preimages[0].key()]) } - if !reflect.DeepEqual(pis[2], preimages[2]) { + if !reflect.DeepEqual(pis[preimages[2].key()], preimages[2]) { t.Errorf("Third Preimage of first Preimages does not match expected."+ - "\nexpected: %+v\nreceived: %+v", preimages[2], pis[2]) + "\nexpected: %+v\nreceived: %+v", preimages[2], pis[preimages[2].key()]) } pis = s.edge[*identities[1]] @@ -107,14 +154,14 @@ func TestStore_Add(t *testing.T) { } expected = Preimage{identities[1].Bytes(), "default", identities[1].Bytes()} - if !reflect.DeepEqual(pis[0], expected) { + if !reflect.DeepEqual(pis[expected.key()], expected) { t.Errorf("First Preimage of second Preimages does not match expected."+ - "\nexpected: %+v\nreceived: %+v", expected, pis[0]) + "\nexpected: %+v\nreceived: %+v", expected, pis[expected.key()]) } - if !reflect.DeepEqual(pis[1], preimages[1]) { + if !reflect.DeepEqual(pis[preimages[1].key()], preimages[1]) { t.Errorf("Second Preimage of second Preimages does not match expected."+ - "\nexpected: %+v\nreceived: %+v", preimages[1], pis[1]) + "\nexpected: %+v\nreceived: %+v", preimages[1], pis[preimages[1].key()]) } } diff --git a/storage/edge/preimage.go b/storage/edge/preimage.go index da5ff77d755202fb7e15d9d228e8a6b9049bf17b..0115bbee4b5036fc67a1ed92d4f24f75bdb15626 100644 --- a/storage/edge/preimage.go +++ b/storage/edge/preimage.go @@ -1,7 +1,7 @@ package edge import ( - "bytes" + "encoding/base64" "encoding/json" "github.com/pkg/errors" "gitlab.com/elixxir/client/storage/versioned" @@ -20,13 +20,18 @@ type Preimage struct { Source []byte } -type Preimages []Preimage +// key returns the key used to identify the Preimage in a map. +func (pi Preimage) key() string { + return base64.StdEncoding.EncodeToString(pi.Data) +} + +type Preimages map[string]Preimage // newPreimages makes a Preimages object for the given identity and populates // it with the default preimage for the identity. Does not store to disk. func newPreimages(identity *id.ID) Preimages { pis := Preimages{ - { + identity.String(): { Data: identity[:], Type: "default", Source: identity[:], @@ -37,19 +42,18 @@ func newPreimages(identity *id.ID) Preimages { } // add adds the preimage to the list. -func (pis Preimages) add(pimg Preimage) Preimages { - return append(pis, pimg) -} - -func (pis Preimages) remove(data []byte) Preimages { - for i, preimage := range pis { - if bytes.Equal(preimage.Data, data) { - pis[i] = pis[len(pis)-1] - return pis[:len(pis)-1] - } +func (pis Preimages) add(preimage Preimage) { + if _, exists := pis[preimage.key()]; exists { + return } - return pis + pis[preimage.key()] = preimage +} + +// remove deletes the Preimage with the matching data from the list. +func (pis Preimages) remove(data []byte) { + key := base64.StdEncoding.EncodeToString(data) + delete(pis, key) } //////////////////////////////////////////////////////////////////////////////// diff --git a/storage/edge/preimage_test.go b/storage/edge/preimage_test.go index 173873d7755f8ba48926b0ca99bca6653c9f6a94..208fbd7966aae20da15f0dd2a5a231282e0fa1e6 100644 --- a/storage/edge/preimage_test.go +++ b/storage/edge/preimage_test.go @@ -20,11 +20,13 @@ import ( // Tests that newPreimages returns the expected new Preimages. func Test_newPreimages(t *testing.T) { identity := id.NewIdFromString("identity", id.User, t) - expected := Preimages{{ - Data: identity.Bytes(), - Type: "default", - Source: identity.Bytes(), - }} + expected := Preimages{ + identity.String(): { + Data: identity.Bytes(), + Type: "default", + Source: identity.Bytes(), + }, + } received := newPreimages(identity) @@ -38,15 +40,16 @@ func Test_newPreimages(t *testing.T) { func TestPreimages_add(t *testing.T) { identity0 := id.NewIdFromString("identity0", id.User, t) identity1 := id.NewIdFromString("identity1", id.User, t) + identity2 := id.NewIdFromString("identity3", id.User, t) expected := Preimages{ - {identity0.Bytes(), "default", identity0.Bytes()}, - {identity0.Bytes(), "group", identity0.Bytes()}, - {identity1.Bytes(), "default", identity1.Bytes()}, + identity0.String(): {identity0.Bytes(), "default", identity0.Bytes()}, + identity1.String(): {identity1.Bytes(), "group", identity1.Bytes()}, + identity2.String(): {identity2.Bytes(), "default", identity2.Bytes()}, } pis := newPreimages(identity0) - pis = pis.add(Preimage{identity0.Bytes(), "group", identity0.Bytes()}) - pis = pis.add(Preimage{identity1.Bytes(), "default", identity1.Bytes()}) + pis.add(Preimage{identity1.Bytes(), "group", identity1.Bytes()}) + pis.add(Preimage{identity2.Bytes(), "default", identity2.Bytes()}) if !reflect.DeepEqual(expected, pis) { t.Errorf("Failed to add expected Preimages."+ @@ -56,7 +59,7 @@ func TestPreimages_add(t *testing.T) { // Tests that Preimages.remove removes all the correct Preimage from the list. func TestPreimages_remove(t *testing.T) { - var pis Preimages + pis := make(Preimages) var identities [][]byte // Add 10 Preimage to the list @@ -67,14 +70,14 @@ func TestPreimages_remove(t *testing.T) { pisType = "group" } - pis = pis.add(Preimage{identity.Bytes(), pisType, identity.Bytes()}) + pis.add(Preimage{identity.Bytes(), pisType, identity.Bytes()}) identities = append(identities, identity.Bytes()) } // Remove each Preimage, check if the length of the list has changed, and // check that the correct Preimage was removed for i, identity := range identities { - pis = pis.remove(identity) + pis.remove(identity) if len(pis) != len(identities)-(i+1) { t.Errorf("Length of Preimages incorrect after removing %d Premiages."+ @@ -101,9 +104,9 @@ func Test_loadPreimages(t *testing.T) { kv := versioned.NewKV(make(ekv.Memstore)) identity := id.NewIdFromString("identity", id.User, t) pis := Preimages{ - {[]byte("identity0"), "default", []byte("identity0")}, - {[]byte("identity0"), "group", []byte("identity0")}, - {[]byte("identity1"), "default", []byte("identity1")}, + "a": {[]byte("identity0"), "default", []byte("identity0")}, + "b": {[]byte("identity0"), "group", []byte("identity0")}, + "c": {[]byte("identity1"), "default", []byte("identity1")}, } err := pis.save(kv, identity) @@ -128,9 +131,9 @@ func TestPreimages_save(t *testing.T) { kv := versioned.NewKV(make(ekv.Memstore)) identity := id.NewIdFromString("identity", id.User, t) pis := Preimages{ - {[]byte("identity0"), "default", []byte("identity0")}, - {[]byte("identity0"), "group", []byte("identity0")}, - {[]byte("identity1"), "default", []byte("identity1")}, + "a": {[]byte("identity0"), "default", []byte("identity0")}, + "b": {[]byte("identity0"), "group", []byte("identity0")}, + "c": {[]byte("identity1"), "default", []byte("identity1")}, } err := pis.save(kv, identity) @@ -161,9 +164,9 @@ func TestPreimages_delete(t *testing.T) { kv := versioned.NewKV(make(ekv.Memstore)) identity := id.NewIdFromString("identity", id.User, t) pis := Preimages{ - {[]byte("identity0"), "default", []byte("identity0")}, - {[]byte("identity0"), "group", []byte("identity0")}, - {[]byte("identity1"), "default", []byte("identity1")}, + "a": {[]byte("identity0"), "default", []byte("identity0")}, + "b": {[]byte("identity0"), "group", []byte("identity0")}, + "c": {[]byte("identity1"), "default", []byte("identity1")}, } err := pis.save(kv, identity)