internal/store: rename compat interface
All checks were successful
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 2m17s
Test / Hakurei (push) Successful in 3m9s
Test / Sandbox (race detector) (push) Successful in 4m3s
Test / Hpkg (push) Successful in 4m4s
Test / Flake checks (push) Successful in 1m25s
Test / Hakurei (race detector) (push) Successful in 4m54s

The new store implementation will be exported as Store.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
Ophestra 2025-10-30 18:53:59 +09:00
parent ebdcff1049
commit b25ade5f3d
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
4 changed files with 60 additions and 68 deletions

View File

@ -168,7 +168,7 @@ func printShowInstance(
} }
// printPs writes a representation of active instances to output. // printPs writes a representation of active instances to output.
func printPs(output io.Writer, now time.Time, s store.Store, short, flagJSON bool) { func printPs(output io.Writer, now time.Time, s store.Compat, short, flagJSON bool) {
var entries map[hst.ID]*hst.State var entries map[hst.ID]*hst.State
if e, err := store.Join(s); err != nil { if e, err := store.Join(s); err != nil {
log.Fatalf("cannot join store: %v", err) log.Fatalf("cannot join store: %v", err)

View File

@ -34,7 +34,7 @@ type mainState struct {
// Time is nil if no process was ever created. // Time is nil if no process was ever created.
Time *time.Time Time *time.Time
store store.Store store store.Compat
cancel context.CancelFunc cancel context.CancelFunc
cmd *exec.Cmd cmd *exec.Cmd
cmdWait chan error cmdWait chan error

View File

@ -1,6 +1,8 @@
package store package store
import ( import (
"errors"
"maps"
"strconv" "strconv"
"hakurei.app/container/check" "hakurei.app/container/check"
@ -10,7 +12,7 @@ import (
/* this provides an implementation of Store on top of the improved state tracking to ease in the changes */ /* this provides an implementation of Store on top of the improved state tracking to ease in the changes */
type Store interface { type Compat interface {
// Do calls f exactly once and ensures store exclusivity until f returns. // Do calls f exactly once and ensures store exclusivity until f returns.
// Returns whether f is called and any errors during the locking process. // Returns whether f is called and any errors during the locking process.
// Cursor provided to f becomes invalid as soon as f returns. // Cursor provided to f becomes invalid as soon as f returns.
@ -58,7 +60,7 @@ func (s storeAdapter) List() ([]int, error) {
} }
// NewMulti returns an instance of the multi-file store. // NewMulti returns an instance of the multi-file store.
func NewMulti(msg message.Msg, prefix *check.Absolute) Store { func NewMulti(msg message.Msg, prefix *check.Absolute) Compat {
return storeAdapter{msg, newStore(prefix.Append("state"))} return storeAdapter{msg, newStore(prefix.Append("state"))}
} }
@ -128,3 +130,57 @@ func (h *storeHandle) Len() (int, error) {
} }
return n, err return n, err
} }
var (
ErrDuplicate = errors.New("store contains duplicates")
)
// Joiner is the interface that wraps the Join method.
//
// The Join function uses Joiner if available.
type Joiner interface {
Join() (map[hst.ID]*hst.State, error)
}
// Join returns joined state entries of all active identities.
func Join(s Compat) (map[hst.ID]*hst.State, error) {
if j, ok := s.(Joiner); ok {
return j.Join()
}
var (
aids []int
entries = make(map[hst.ID]*hst.State)
el int
res map[hst.ID]*hst.State
loadErr error
)
if ln, err := s.List(); err != nil {
return nil, err
} else {
aids = ln
}
for _, aid := range aids {
if _, err := s.Do(aid, func(c Cursor) {
res, loadErr = c.Load()
}); err != nil {
return nil, err
}
if loadErr != nil {
return nil, loadErr
}
// save expected length
el = len(entries) + len(res)
maps.Copy(entries, res)
if len(entries) != el {
return nil, ErrDuplicate
}
}
return entries, nil
}

View File

@ -1,64 +0,0 @@
package store
import (
"errors"
"maps"
"hakurei.app/hst"
)
var (
ErrDuplicate = errors.New("store contains duplicates")
)
/*
Joiner is the interface that wraps the Join method.
The Join function uses Joiner if available.
*/
type Joiner interface {
Join() (map[hst.ID]*hst.State, error)
}
// Join returns joined state entries of all active identities.
func Join(s Store) (map[hst.ID]*hst.State, error) {
if j, ok := s.(Joiner); ok {
return j.Join()
}
var (
aids []int
entries = make(map[hst.ID]*hst.State)
el int
res map[hst.ID]*hst.State
loadErr error
)
if ln, err := s.List(); err != nil {
return nil, err
} else {
aids = ln
}
for _, aid := range aids {
if _, err := s.Do(aid, func(c Cursor) {
res, loadErr = c.Load()
}); err != nil {
return nil, err
}
if loadErr != nil {
return nil, loadErr
}
// save expected length
el = len(entries) + len(res)
maps.Copy(entries, res)
if len(entries) != el {
return nil, ErrDuplicate
}
}
return entries, nil
}