diff options
Diffstat (limited to 'internal/app/state/state.go')
| -rw-r--r-- | internal/app/state/state.go | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/internal/app/state/state.go b/internal/app/state/state.go index a64568f6..169af507 100644 --- a/internal/app/state/state.go +++ b/internal/app/state/state.go @@ -2,9 +2,16 @@ package state import ( + "strconv" + + "hakurei.app/container/check" "hakurei.app/hst" + "hakurei.app/internal/lockedfile" + "hakurei.app/message" ) +/* this provides an implementation of Store on top of the improved state tracking to ease in the changes */ + type Store interface { // Do calls f exactly once and ensures store exclusivity until f returns. // Returns whether f is called and any errors during the locking process. @@ -16,6 +23,13 @@ type Store interface { List() (identities []int, err error) } +// NewMulti returns an instance of the multi-file store. +func NewMulti(msg message.Msg, prefix *check.Absolute) Store { + store := &stateStore{msg: msg, base: prefix.Append("state")} + store.fileMu = lockedfile.MutexAt(store.base.Append(storeMutexName).String()) + return store +} + // Cursor provides access to the store of an identity. type Cursor interface { Save(state *hst.State) error @@ -23,3 +37,62 @@ type Cursor interface { Load() (map[hst.ID]*hst.State, error) Len() (int, error) } + +// do implements stateStore.Do on storeHandle. +func (h *storeHandle) do(f func(c Cursor)) (bool, error) { + if unlock, err := h.fileMu.Lock(); err != nil { + return false, &hst.AppError{Step: "acquire lock on store segment " + strconv.Itoa(h.identity), Err: err} + } else { + defer unlock() + } + + f(h) + return true, nil +} + +/* these compatibility methods must only be called while fileMu is held */ + +func (h *storeHandle) Save(state *hst.State) error { + return (&stateEntryHandle{nil, h.path.Append(state.ID.String()), state.ID}).save(state) +} + +func (h *storeHandle) Destroy(id hst.ID) error { + return (&stateEntryHandle{nil, h.path.Append(id.String()), id}).destroy() +} + +func (h *storeHandle) Load() (map[hst.ID]*hst.State, error) { + entries, n, err := h.entries() + if err != nil { + return nil, err + } + + r := make(map[hst.ID]*hst.State, n) + for eh := range entries { + if eh.decodeErr != nil { + err = eh.decodeErr + break + } + var s hst.State + if _, err = eh.load(&s); err != nil { + break + } + r[eh.ID] = &s + } + return r, err +} + +func (h *storeHandle) Len() (int, error) { + entries, _, err := h.entries() + if err != nil { + return -1, err + } + + var n int + for eh := range entries { + if eh.decodeErr != nil { + err = eh.decodeErr + } + n++ + } + return n, err +} |
