aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/state/segment.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-10-30 18:43:55 +0900
committerOphestra <cat@gensokyo.uk>2025-10-30 18:43:55 +0900
commitebdcff1049fb979405677a823a47410df7ee7c4f (patch)
treea5a14d409e4bc9f3b4b2e2c15f6c23de5ad0755f /internal/state/segment.go
parent46c5ce493638ea2d034bbbdb9449e93b66d0330f (diff)
internal/store: rename from state
This reduces collision with local variable names, and generally makes sense for the new store package, since it no longer specifies the state struct. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/state/segment.go')
-rw-r--r--internal/state/segment.go161
1 files changed, 0 insertions, 161 deletions
diff --git a/internal/state/segment.go b/internal/state/segment.go
deleted file mode 100644
index c8ab8c13..00000000
--- a/internal/state/segment.go
+++ /dev/null
@@ -1,161 +0,0 @@
-package state
-
-import (
- "errors"
- "fmt"
- "iter"
- "os"
- "strconv"
- "sync"
-
- "hakurei.app/container/check"
- "hakurei.app/hst"
- "hakurei.app/internal/lockedfile"
-)
-
-// stateEntryHandle is a handle on a state entry retrieved from a storeHandle.
-// Must only be used while its parent storeHandle.fileMu is held.
-type stateEntryHandle struct {
- // Error returned while decoding pathname.
- // A non-nil value disables stateEntryHandle.
- decodeErr error
-
- // Checked path to entry file.
- pathname *check.Absolute
-
- hst.ID
-}
-
-// open opens the underlying state entry file, returning [hst.AppError] for a non-nil error.
-func (eh *stateEntryHandle) open(flag int, perm os.FileMode) (*os.File, error) {
- if eh.decodeErr != nil {
- return nil, eh.decodeErr
- }
-
- if f, err := os.OpenFile(eh.pathname.String(), flag, perm); err != nil {
- return nil, &hst.AppError{Step: "open state entry", Err: err}
- } else {
- return f, nil
- }
-}
-
-// destroy removes the underlying state entry file, returning [hst.AppError] for a non-nil error.
-func (eh *stateEntryHandle) destroy() error {
- // destroy does not go through open
- if eh.decodeErr != nil {
- return eh.decodeErr
- }
-
- if err := os.Remove(eh.pathname.String()); err != nil {
- return &hst.AppError{Step: "destroy state entry", Err: err}
- }
- return nil
-}
-
-// save encodes [hst.State] and writes it to the underlying file.
-// An error is returned if a file already exists with the same identifier.
-// save does not validate the embedded [hst.Config].
-func (eh *stateEntryHandle) save(state *hst.State) error {
- f, err := eh.open(os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
- if err != nil {
- return err
- }
-
- err = entryEncode(f, state)
- if closeErr := f.Close(); closeErr != nil && err == nil {
- err = &hst.AppError{Step: "close state file", Err: closeErr}
- }
- return err
-}
-
-// load loads and validates the state entry header, and returns the [hst.Enablement] byte.
-// for a non-nil v, the full state payload is decoded and stored in the value pointed to by v.
-// load validates the embedded hst.Config value.
-func (eh *stateEntryHandle) load(v *hst.State) (hst.Enablement, error) {
- f, err := eh.open(os.O_RDONLY, 0)
- if err != nil {
- return 0, err
- }
-
- var et hst.Enablement
- if v != nil {
- et, err = entryDecode(f, v)
- if err == nil && v.ID != eh.ID {
- err = &hst.AppError{Step: "validate state identifier", Err: os.ErrInvalid,
- Msg: fmt.Sprintf("state entry %s has unexpected id %s", eh.ID.String(), v.ID.String())}
- }
- } else {
- et, err = entryDecodeHeader(f)
- }
-
- if closeErr := f.Close(); closeErr != nil && err == nil {
- err = &hst.AppError{Step: "close state file", Err: closeErr}
- }
- return et, err
-}
-
-// storeHandle is a handle on a stateStore segment.
-// Initialised by stateStore.identityHandle.
-type storeHandle struct {
- // Identity of instances tracked by this segment.
- identity int
- // Pathname of directory that the segment referred to by storeHandle is rooted in.
- path *check.Absolute
- // Inter-process mutex to synchronise operations against resources in this segment.
- fileMu *lockedfile.Mutex
-
- // Must be held alongside fileMu.
- mu sync.Mutex
-}
-
-// entries returns an iterator over all stateEntryHandle held in this segment.
-// Must be called while holding a lock on mu and fileMu.
-// A non-nil error attached to a stateEntryHandle indicates a malformed identifier and is of type [hst.AppError].
-// A non-nil error returned by entries is of type [hst.AppError].
-func (h *storeHandle) entries() (iter.Seq[*stateEntryHandle], int, error) {
- // for error reporting
- const step = "read store segment entries"
-
- // read directory contents, should only contain storeMutexName and identifier
- var entries []os.DirEntry
- if pl, err := os.ReadDir(h.path.String()); err != nil {
- return nil, -1, &hst.AppError{Step: step, Err: err}
- } else {
- entries = pl
- }
-
- // expects lock file
- l := len(entries)
- if l > 0 {
- l--
- }
-
- return func(yield func(*stateEntryHandle) bool) {
- for _, ent := range entries {
- var eh = stateEntryHandle{pathname: h.path.Append(ent.Name())}
-
- // this should never happen
- if ent.IsDir() {
- eh.decodeErr = &hst.AppError{Step: step,
- Err: errors.New("unexpected directory " + strconv.Quote(ent.Name()) + " in store")}
- goto out
- }
-
- // silently skip lock file
- if ent.Name() == storeMutexName {
- continue
- }
-
- // this either indicates a serious bug or external interference
- if err := eh.ID.UnmarshalText([]byte(ent.Name())); err != nil {
- eh.decodeErr = &hst.AppError{Step: "decode store segment entry", Err: err}
- goto out
- }
-
- out:
- if !yield(&eh) {
- break
- }
- }
- }, l, nil
-}