2017-02-27 16:28:41 +00:00
|
|
|
package mapstate
|
|
|
|
|
2018-01-05 04:07:52 +00:00
|
|
|
// To add a new state format
|
|
|
|
// - implement the previous format's "next" function to the new format
|
|
|
|
// - implement the new format's unmarshal function
|
|
|
|
// - add a case to the switch statement for the previous format version
|
|
|
|
// - update the code copying the from mapStateVx to mapState
|
2017-02-27 16:28:41 +00:00
|
|
|
import (
|
2017-11-28 22:45:10 +00:00
|
|
|
"bytes"
|
2017-02-27 16:28:41 +00:00
|
|
|
"errors"
|
|
|
|
|
2017-11-28 22:45:10 +00:00
|
|
|
msgpack "github.com/multiformats/go-multicodec/msgpack"
|
|
|
|
|
2017-02-27 16:28:41 +00:00
|
|
|
"github.com/ipfs/ipfs-cluster/api"
|
|
|
|
)
|
|
|
|
|
2018-01-05 04:07:52 +00:00
|
|
|
// Instances of migrateable can be read from a serialized format and migrated
|
|
|
|
// to other state formats
|
|
|
|
type migrateable interface {
|
|
|
|
next() migrateable
|
|
|
|
unmarshal([]byte) error
|
|
|
|
}
|
|
|
|
|
2018-03-09 20:17:48 +00:00
|
|
|
/* V1 */
|
|
|
|
|
2017-02-27 16:28:41 +00:00
|
|
|
type mapStateV1 struct {
|
|
|
|
Version int
|
|
|
|
PinMap map[string]struct{}
|
|
|
|
}
|
|
|
|
|
2018-01-05 04:07:52 +00:00
|
|
|
// Unmarshal the serialization of a v1 state
|
|
|
|
func (st *mapStateV1) unmarshal(bs []byte) error {
|
|
|
|
buf := bytes.NewBuffer(bs)
|
|
|
|
dec := msgpack.Multicodec(msgpack.DefaultMsgpackHandle()).Decoder(buf)
|
|
|
|
return dec.Decode(st)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Migrate from v1 to v2
|
|
|
|
func (st *mapStateV1) next() migrateable {
|
|
|
|
var mst2 mapStateV2
|
2018-01-12 17:04:46 +00:00
|
|
|
mst2.PinMap = make(map[string]pinSerialV2)
|
2018-01-05 04:07:52 +00:00
|
|
|
for k := range st.PinMap {
|
2018-01-12 17:04:46 +00:00
|
|
|
mst2.PinMap[k] = pinSerialV2{
|
2018-01-05 04:07:52 +00:00
|
|
|
Cid: k,
|
|
|
|
Allocations: []string{},
|
|
|
|
ReplicationFactor: -1,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return &mst2
|
|
|
|
}
|
|
|
|
|
2018-03-09 20:17:48 +00:00
|
|
|
/* V2 */
|
|
|
|
|
2018-01-12 17:04:46 +00:00
|
|
|
type pinSerialV2 struct {
|
|
|
|
Cid string `json:"cid"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
Allocations []string `json:"allocations"`
|
|
|
|
ReplicationFactor int `json:"replication_factor"`
|
|
|
|
}
|
|
|
|
|
2018-01-05 04:07:52 +00:00
|
|
|
type mapStateV2 struct {
|
2018-01-12 17:04:46 +00:00
|
|
|
PinMap map[string]pinSerialV2
|
2018-01-05 04:07:52 +00:00
|
|
|
Version int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (st *mapStateV2) unmarshal(bs []byte) error {
|
|
|
|
buf := bytes.NewBuffer(bs)
|
|
|
|
dec := msgpack.Multicodec(msgpack.DefaultMsgpackHandle()).Decoder(buf)
|
|
|
|
return dec.Decode(st)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (st *mapStateV2) next() migrateable {
|
2018-01-12 17:04:46 +00:00
|
|
|
var mst3 mapStateV3
|
2018-03-09 20:17:48 +00:00
|
|
|
mst3.PinMap = make(map[string]pinSerialV3)
|
2018-01-12 17:04:46 +00:00
|
|
|
for k, v := range st.PinMap {
|
2018-03-09 20:17:48 +00:00
|
|
|
mst3.PinMap[k] = pinSerialV3{
|
2018-01-12 17:04:46 +00:00
|
|
|
Cid: v.Cid,
|
|
|
|
Name: v.Name,
|
|
|
|
Allocations: v.Allocations,
|
|
|
|
ReplicationFactorMin: v.ReplicationFactor,
|
|
|
|
ReplicationFactorMax: v.ReplicationFactor,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return &mst3
|
|
|
|
}
|
|
|
|
|
2018-03-09 20:17:48 +00:00
|
|
|
/* V3 */
|
|
|
|
|
|
|
|
type pinSerialV3 struct {
|
|
|
|
Cid string `json:"cid"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
Allocations []string `json:"allocations"`
|
|
|
|
ReplicationFactorMin int `json:"replication_factor_min"`
|
|
|
|
ReplicationFactorMax int `json:"replication_factor_max"`
|
|
|
|
}
|
|
|
|
|
2018-01-12 17:04:46 +00:00
|
|
|
type mapStateV3 struct {
|
2018-03-09 20:17:48 +00:00
|
|
|
PinMap map[string]pinSerialV3
|
2018-01-12 17:04:46 +00:00
|
|
|
Version int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (st *mapStateV3) unmarshal(bs []byte) error {
|
|
|
|
buf := bytes.NewBuffer(bs)
|
|
|
|
dec := msgpack.Multicodec(msgpack.DefaultMsgpackHandle()).Decoder(buf)
|
|
|
|
return dec.Decode(st)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (st *mapStateV3) next() migrateable {
|
2018-03-09 20:17:48 +00:00
|
|
|
var mst4 mapStateV4
|
|
|
|
mst4.PinMap = make(map[string]api.PinSerial)
|
|
|
|
for k, v := range st.PinMap {
|
|
|
|
mst4.PinMap[k] = api.PinSerial{
|
|
|
|
Cid: v.Cid,
|
|
|
|
Name: v.Name,
|
|
|
|
Allocations: v.Allocations,
|
|
|
|
ReplicationFactorMin: v.ReplicationFactorMin,
|
|
|
|
ReplicationFactorMax: v.ReplicationFactorMax,
|
|
|
|
Recursive: true,
|
2018-06-28 15:01:39 +00:00
|
|
|
Type: int(api.DataType),
|
2018-03-18 19:29:02 +00:00
|
|
|
Parents: nil,
|
|
|
|
Clusterdag: "",
|
2018-03-09 20:17:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return &mst4
|
|
|
|
}
|
|
|
|
|
|
|
|
/* V4 */
|
|
|
|
|
|
|
|
type mapStateV4 struct {
|
|
|
|
PinMap map[string]api.PinSerial
|
|
|
|
Version int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (st *mapStateV4) unmarshal(bs []byte) error {
|
|
|
|
buf := bytes.NewBuffer(bs)
|
|
|
|
dec := msgpack.Multicodec(msgpack.DefaultMsgpackHandle()).Decoder(buf)
|
|
|
|
return dec.Decode(st)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (st *mapStateV4) next() migrateable {
|
2018-01-05 04:07:52 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-03-09 20:17:48 +00:00
|
|
|
func finalCopy(st *MapState, internal *mapStateV4) {
|
2018-01-12 17:04:46 +00:00
|
|
|
for k, v := range internal.PinMap {
|
|
|
|
st.PinMap[k] = v
|
2018-01-05 04:07:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-27 16:28:41 +00:00
|
|
|
func (st *MapState) migrateFrom(version int, snap []byte) error {
|
2018-01-05 04:07:52 +00:00
|
|
|
var m, next migrateable
|
2017-02-27 16:28:41 +00:00
|
|
|
switch version {
|
|
|
|
case 1:
|
2018-01-05 04:07:52 +00:00
|
|
|
var mst1 mapStateV1
|
|
|
|
m = &mst1
|
2018-01-12 17:04:46 +00:00
|
|
|
case 2:
|
|
|
|
var mst2 mapStateV2
|
|
|
|
m = &mst2
|
2018-03-09 20:17:48 +00:00
|
|
|
case 3:
|
|
|
|
var mst3 mapStateV3
|
|
|
|
m = &mst3
|
2017-02-27 16:28:41 +00:00
|
|
|
default:
|
|
|
|
return errors.New("version migration not supported")
|
|
|
|
}
|
2018-01-05 04:07:52 +00:00
|
|
|
|
|
|
|
err := m.unmarshal(snap)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
next = m.next()
|
|
|
|
if next == nil {
|
2018-03-09 20:17:48 +00:00
|
|
|
mst4, ok := m.(*mapStateV4)
|
2018-01-05 04:07:52 +00:00
|
|
|
if !ok {
|
|
|
|
return errors.New("migration ended prematurely")
|
|
|
|
}
|
2018-03-09 20:17:48 +00:00
|
|
|
finalCopy(st, mst4)
|
2018-01-05 04:07:52 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
m = next
|
|
|
|
}
|
2017-02-27 16:28:41 +00:00
|
|
|
}
|