2017-02-09 15:29:17 +00:00
|
|
|
package mapstate
|
2016-12-02 18:33:39 +00:00
|
|
|
|
|
|
|
import (
|
2017-02-27 16:28:41 +00:00
|
|
|
"encoding/json"
|
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
2016-12-05 14:30:11 +00:00
|
|
|
"sync"
|
2016-12-02 18:33:39 +00:00
|
|
|
|
2017-02-13 15:46:53 +00:00
|
|
|
"github.com/ipfs/ipfs-cluster/api"
|
|
|
|
|
2016-12-16 11:40:28 +00:00
|
|
|
cid "github.com/ipfs/go-cid"
|
2016-12-02 18:33:39 +00:00
|
|
|
)
|
|
|
|
|
2017-02-15 14:16:16 +00:00
|
|
|
// Version is the map state Version. States with old versions should
|
|
|
|
// perform an upgrade before.
|
2017-02-27 16:28:41 +00:00
|
|
|
const Version = 2
|
2017-02-13 15:46:53 +00:00
|
|
|
|
2016-12-28 15:25:24 +00:00
|
|
|
// MapState is a very simple database to store the state of the system
|
|
|
|
// using a Go map. It is thread safe. It implements the State interface.
|
2016-12-02 18:33:39 +00:00
|
|
|
type MapState struct {
|
2017-02-13 15:46:53 +00:00
|
|
|
pinMux sync.RWMutex
|
2017-03-08 15:57:27 +00:00
|
|
|
PinMap map[string]api.PinSerial
|
2017-02-13 15:46:53 +00:00
|
|
|
Version int
|
2016-12-02 18:33:39 +00:00
|
|
|
}
|
|
|
|
|
2016-12-28 15:25:24 +00:00
|
|
|
// NewMapState initializes the internal map and returns a new MapState object.
|
2016-12-09 19:54:46 +00:00
|
|
|
func NewMapState() *MapState {
|
|
|
|
return &MapState{
|
2017-02-27 16:28:41 +00:00
|
|
|
PinMap: make(map[string]api.PinSerial),
|
|
|
|
Version: Version,
|
2016-12-05 14:30:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:57:27 +00:00
|
|
|
// Add adds a Pin to the internal map.
|
|
|
|
func (st *MapState) Add(c api.Pin) error {
|
2017-02-02 22:52:06 +00:00
|
|
|
st.pinMux.Lock()
|
|
|
|
defer st.pinMux.Unlock()
|
2017-02-13 15:46:53 +00:00
|
|
|
st.PinMap[c.Cid.String()] = c.ToSerial()
|
2016-12-02 18:33:39 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-02-13 15:46:53 +00:00
|
|
|
// Rm removes a Cid from the internal map.
|
|
|
|
func (st *MapState) Rm(c *cid.Cid) error {
|
2017-02-02 22:52:06 +00:00
|
|
|
st.pinMux.Lock()
|
|
|
|
defer st.pinMux.Unlock()
|
2016-12-02 18:33:39 +00:00
|
|
|
delete(st.PinMap, c.String())
|
|
|
|
return nil
|
|
|
|
}
|
2016-12-09 19:54:46 +00:00
|
|
|
|
2017-03-08 15:57:27 +00:00
|
|
|
// Get returns Pin information for a CID.
|
|
|
|
func (st *MapState) Get(c *cid.Cid) api.Pin {
|
2017-02-13 15:46:53 +00:00
|
|
|
st.pinMux.RLock()
|
|
|
|
defer st.pinMux.RUnlock()
|
2017-03-08 15:57:27 +00:00
|
|
|
pins, ok := st.PinMap[c.String()]
|
2017-02-13 15:46:53 +00:00
|
|
|
if !ok { // make sure no panics
|
2017-03-08 15:57:27 +00:00
|
|
|
return api.Pin{}
|
2017-02-13 15:46:53 +00:00
|
|
|
}
|
2017-03-08 15:57:27 +00:00
|
|
|
return pins.ToPin()
|
2017-02-13 15:46:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Has returns true if the Cid belongs to the State.
|
|
|
|
func (st *MapState) Has(c *cid.Cid) bool {
|
2017-02-02 22:52:06 +00:00
|
|
|
st.pinMux.RLock()
|
|
|
|
defer st.pinMux.RUnlock()
|
2016-12-16 16:22:37 +00:00
|
|
|
_, ok := st.PinMap[c.String()]
|
|
|
|
return ok
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:57:27 +00:00
|
|
|
// List provides the list of tracked Pins.
|
|
|
|
func (st *MapState) List() []api.Pin {
|
2017-02-02 22:52:06 +00:00
|
|
|
st.pinMux.RLock()
|
|
|
|
defer st.pinMux.RUnlock()
|
2017-03-08 15:57:27 +00:00
|
|
|
cids := make([]api.Pin, 0, len(st.PinMap))
|
2017-02-13 15:46:53 +00:00
|
|
|
for _, v := range st.PinMap {
|
2017-02-27 16:28:41 +00:00
|
|
|
if v.Cid == "" {
|
|
|
|
continue
|
|
|
|
}
|
2017-03-08 15:57:27 +00:00
|
|
|
cids = append(cids, v.ToPin())
|
2016-12-09 19:54:46 +00:00
|
|
|
}
|
|
|
|
return cids
|
|
|
|
}
|
2017-02-27 16:28:41 +00:00
|
|
|
|
|
|
|
// Snapshot dumps the MapState to the given writer, in pretty json
|
|
|
|
// format.
|
|
|
|
func (st *MapState) Snapshot(w io.Writer) error {
|
|
|
|
st.pinMux.RLock()
|
|
|
|
defer st.pinMux.RUnlock()
|
|
|
|
enc := json.NewEncoder(w)
|
|
|
|
enc.SetIndent("", " ")
|
|
|
|
return enc.Encode(st)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (st *MapState) Restore(r io.Reader) error {
|
|
|
|
snap, err := ioutil.ReadAll(r)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
var vonly struct{ Version int }
|
|
|
|
err = json.Unmarshal(snap, &vonly)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if vonly.Version == Version {
|
|
|
|
// we are good
|
|
|
|
err := json.Unmarshal(snap, st)
|
|
|
|
return err
|
|
|
|
} else {
|
|
|
|
return st.migrateFrom(vonly.Version, snap)
|
|
|
|
}
|
|
|
|
}
|