diff --git a/storage/e2e/session.go b/storage/e2e/session.go index 2be837e613369b878a112912252919ce7e021de3..6172f56addb98baff180d5f0cd881c25b8577c79 100644 --- a/storage/e2e/session.go +++ b/storage/e2e/session.go @@ -154,6 +154,9 @@ func loadSession(ship *relationship, kv *versioned.KV, return nil, errors.WithMessagef(err, "Failed to load %s", kv.GetFullKey(sessionKey)) } + obj, err := sessionUpgradeTable.Upgrade(obj) + + err = session.unmarshal(obj.Data) if err != nil { return nil, err diff --git a/storage/versioned/kv.go b/storage/versioned/kv.go index 09a109a3aac30b5297d8ee2975d2e5e754e91e7a..d2c0f50615dbc2bfd772094e5e61810cc902a0ae 100644 --- a/storage/versioned/kv.go +++ b/storage/versioned/kv.go @@ -9,6 +9,7 @@ package versioned import ( "fmt" + "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/ekv" "gitlab.com/xx_network/primitives/id" @@ -57,8 +58,8 @@ func NewKV(data ekv.KeyValue) *KV { // Get gets and upgrades data stored in the key/value store // Make sure to inspect the version returned in the versioned object -func (v *KV) Get(key string) (*Object, error) { - key = v.makeKey(key) +func (v *KV) Get(key string, version uint64) (*Object, error) { + key = v.makeKey(key, version) jww.TRACE.Printf("Get %p with key %v", v.r.data, key) // Get raw data result := Object{} @@ -69,22 +70,47 @@ func (v *KV) Get(key string) (*Object, error) { return &result, nil } +type UpgradeTable struct{ + CurrentVersion uint64 + Table []Upgrade +} + // Get gets and upgrades data stored in the key/value store // Make sure to inspect the version returned in the versioned object -func (v *KV) GetUpgrade(key string, table []Upgrade) (*Object, error) { - key = v.makeKey(key) - jww.TRACE.Printf("Get %p with key %v", v.r.data, key) - // Get raw data - result := &Object{} - err := v.r.data.Get(key, result) - if err != nil { - return nil, err +func (v *KV) GetUpgrade(key string, ut UpgradeTable) (*Object, error) { + version := ut.CurrentVersion + key = v.makeKey(key, version) + + if uint64(len(ut.Table))!=version{ + jww.FATAL.Panicf("Cannot get upgrade for %s: table lengh (%d) " + + "does not match current version (%d)", key, len(ut.Table), + version) + } + var result *Object + for ;version>=0;version--{ + + key = v.makeKey(key, version) + jww.TRACE.Printf("Get %p with key %v", v.r.data, key) + + // Get raw data + result = &Object{} + err := v.r.data.Get(key, result) + if err != nil { + jww.WARN.Printf("Failed to get keyvalue %s: %s", key, err) + }else{ + break + } + } + + if version < 0{ + return nil, errors.Errorf("Failed to get key and upgrade it for %s", v.makeKey(key, ut.CurrentVersion)) } + var err error initialVersion := result.Version - for result.Version<uint64(len(table)){ + for result.Version<uint64(len(ut.Table)){ oldVersion := result.Version - result, err = table[oldVersion](result) + result, err = ut.Table[oldVersion](result) if err!=nil{ jww.FATAL.Panicf("failed to upgrade key %s from " + "version %v, initla version %v", key, oldVersion, @@ -97,8 +123,8 @@ func (v *KV) GetUpgrade(key string, table []Upgrade) (*Object, error) { // delete removes a given key from the data store -func (v *KV) Delete(key string) error { - key = v.makeKey(key) +func (v *KV) Delete(key string, version uint64) error { + key = v.makeKey(key, version) jww.TRACE.Printf("delete %p with key %v", v.r.data, key) return v.r.data.Delete(key) } @@ -106,8 +132,8 @@ func (v *KV) Delete(key string) error { // Set upserts new data into the storage // When calling this, you are responsible for prefixing the key with the correct // type optionally unique id! Call MakeKeyWithPrefix() to do so. -func (v *KV) Set(key string, object *Object) error { - key = v.makeKey(key) +func (v *KV) Set(key string, version uint64, object *Object) error { + key = v.makeKey(key, version) jww.TRACE.Printf("Set %p with key %v", v.r.data, key) return v.r.data.Set(key, object) } @@ -122,10 +148,10 @@ func (v *KV) Prefix(prefix string) *KV { } //Returns the key with all prefixes appended -func (v *KV) GetFullKey(key string) string { - return v.prefix + key +func (v *KV) GetFullKey(key string, version uint64) string { + return v.makeKey(key, version) } -func (v *KV)makeKey(key string)string{ - return v.prefix + key +func (v *KV)makeKey(key string, version uint64)string{ + return fmt.Sprintf("%s%s_%d", v.prefix, key, version) } \ No newline at end of file