internal/store: expose save via handle
All checks were successful
Test / Create distribution (push) Successful in 26s
Test / Sandbox (push) Successful in 42s
Test / Sandbox (race detector) (push) Successful in 42s
Test / Hakurei (push) Successful in 46s
Test / Hakurei (race detector) (push) Successful in 46s
Test / Hpkg (push) Successful in 42s
Test / Flake checks (push) Successful in 1m30s
All checks were successful
Test / Create distribution (push) Successful in 26s
Test / Sandbox (push) Successful in 42s
Test / Sandbox (race detector) (push) Successful in 42s
Test / Hakurei (push) Successful in 46s
Test / Hakurei (race detector) (push) Successful in 46s
Test / Hpkg (push) Successful in 42s
Test / Flake checks (push) Successful in 1m30s
The handle is otherwise inaccessible without the compat interface. This change also moves compatibility methods to separate adapter structs to avoid inadvertently using them. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -22,20 +22,20 @@ type Compat interface {
|
|||||||
List() (identities []int, err error)
|
List() (identities []int, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) Do(identity int, f func(c Cursor)) (bool, error) {
|
|
||||||
if h, err := s.Handle(identity); err != nil {
|
|
||||||
return false, err
|
|
||||||
} else {
|
|
||||||
return h.do(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// storeAdapter satisfies [Compat] via [Store].
|
// storeAdapter satisfies [Compat] via [Store].
|
||||||
type storeAdapter struct {
|
type storeAdapter struct {
|
||||||
msg message.Msg
|
msg message.Msg
|
||||||
*Store
|
*Store
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s storeAdapter) Do(identity int, f func(c Cursor)) (bool, error) {
|
||||||
|
if h, err := s.Handle(identity); err != nil {
|
||||||
|
return false, err
|
||||||
|
} else {
|
||||||
|
return handleAdapter{h}.do(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s storeAdapter) List() ([]int, error) {
|
func (s storeAdapter) List() ([]int, error) {
|
||||||
segments, n, err := s.Segments()
|
segments, n, err := s.Segments()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -71,8 +71,11 @@ type Cursor interface {
|
|||||||
Len() (int, error)
|
Len() (int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleAdapter satisfies [Cursor] via [Handle].
|
||||||
|
type handleAdapter struct{ *Handle }
|
||||||
|
|
||||||
// do implements [Compat.Do] on [Handle].
|
// do implements [Compat.Do] on [Handle].
|
||||||
func (h *Handle) do(f func(c Cursor)) (bool, error) {
|
func (h handleAdapter) do(f func(c Cursor)) (bool, error) {
|
||||||
if unlock, err := h.Lock(); err != nil {
|
if unlock, err := h.Lock(); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
} else {
|
} else {
|
||||||
@@ -85,15 +88,13 @@ func (h *Handle) do(f func(c Cursor)) (bool, error) {
|
|||||||
|
|
||||||
/* these compatibility methods must only be called while fileMu is held */
|
/* these compatibility methods must only be called while fileMu is held */
|
||||||
|
|
||||||
func (h *Handle) Save(state *hst.State) error {
|
func (h handleAdapter) Save(state *hst.State) error { _, err := h.Handle.Save(state); return err }
|
||||||
return (&EntryHandle{nil, h.Path.Append(state.ID.String()), state.ID}).Save(state)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handle) Destroy(id hst.ID) error {
|
func (h handleAdapter) Destroy(id hst.ID) error {
|
||||||
return (&EntryHandle{nil, h.Path.Append(id.String()), id}).Destroy()
|
return (&EntryHandle{nil, h.Path.Append(id.String()), id}).Destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handle) Load() (map[hst.ID]*hst.State, error) {
|
func (h handleAdapter) Load() (map[hst.ID]*hst.State, error) {
|
||||||
entries, n, err := h.Entries()
|
entries, n, err := h.Entries()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -114,7 +115,7 @@ func (h *Handle) Load() (map[hst.ID]*hst.State, error) {
|
|||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handle) Len() (int, error) {
|
func (h handleAdapter) Len() (int, error) {
|
||||||
entries, _, err := h.Entries()
|
entries, _, err := h.Entries()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
|
|||||||
@@ -54,11 +54,11 @@ func (eh *EntryHandle) Destroy() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save encodes [hst.State] and writes it to the underlying file.
|
// save encodes [hst.State] and writes it to the underlying file.
|
||||||
// An error is returned if a file already exists with the same identifier.
|
// An error is returned if a file already exists with the same identifier.
|
||||||
// Save does not validate the embedded [hst.Config].
|
// save does not validate the embedded [hst.Config].
|
||||||
// A non-nil error returned by Save is of type [hst.AppError].
|
// A non-nil error returned by save is of type [hst.AppError].
|
||||||
func (eh *EntryHandle) Save(state *hst.State) error {
|
func (eh *EntryHandle) save(state *hst.State) error {
|
||||||
f, err := eh.open(os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
|
f, err := eh.open(os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -123,6 +123,16 @@ func (h *Handle) Lock() (unlock func(), err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save attempts to save [hst.State] as a segment entry, and returns its [EntryHandle].
|
||||||
|
// Must be called while holding [Handle.Lock].
|
||||||
|
// An error is returned if an entry already exists with the same identifier.
|
||||||
|
// Save does not validate the embedded [hst.Config].
|
||||||
|
// A non-nil error returned by Save is of type [hst.AppError].
|
||||||
|
func (h *Handle) Save(state *hst.State) (*EntryHandle, error) {
|
||||||
|
eh := EntryHandle{nil, h.Path.Append(state.ID.String()), state.ID}
|
||||||
|
return &eh, eh.save(state)
|
||||||
|
}
|
||||||
|
|
||||||
// Entries returns an iterator over all [EntryHandle] held in this segment.
|
// Entries returns an iterator over all [EntryHandle] held in this segment.
|
||||||
// Must be called while holding [Handle.Lock].
|
// Must be called while holding [Handle.Lock].
|
||||||
// A non-nil error attached to a [EntryHandle] indicates a malformed identifier and is of type [hst.AppError].
|
// A non-nil error attached to a [EntryHandle] indicates a malformed identifier and is of type [hst.AppError].
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ func newHandle(base *check.Absolute, identity int) *store.Handle
|
|||||||
//go:linkname open hakurei.app/internal/store.(*EntryHandle).open
|
//go:linkname open hakurei.app/internal/store.(*EntryHandle).open
|
||||||
func open(eh *store.EntryHandle, flag int, perm os.FileMode) (*os.File, error)
|
func open(eh *store.EntryHandle, flag int, perm os.FileMode) (*os.File, error)
|
||||||
|
|
||||||
|
//go:linkname save hakurei.app/internal/store.(*EntryHandle).save
|
||||||
|
func save(eh *store.EntryHandle, state *hst.State) error
|
||||||
|
|
||||||
func TestStateEntryHandle(t *testing.T) {
|
func TestStateEntryHandle(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -44,7 +47,7 @@ func TestStateEntryHandle(t *testing.T) {
|
|||||||
if err := eh.Destroy(); !reflect.DeepEqual(err, wantErr()) {
|
if err := eh.Destroy(); !reflect.DeepEqual(err, wantErr()) {
|
||||||
t.Errorf("destroy: error = %v, want %v", err, wantErr())
|
t.Errorf("destroy: error = %v, want %v", err, wantErr())
|
||||||
}
|
}
|
||||||
if err := eh.Save(nil); !reflect.DeepEqual(err, wantErr()) {
|
if err := save(&eh, nil); !reflect.DeepEqual(err, wantErr()) {
|
||||||
t.Errorf("save: error = %v, want %v", err, wantErr())
|
t.Errorf("save: error = %v, want %v", err, wantErr())
|
||||||
}
|
}
|
||||||
if _, err := eh.Load(nil); !reflect.DeepEqual(err, wantErr()) {
|
if _, err := eh.Load(nil); !reflect.DeepEqual(err, wantErr()) {
|
||||||
@@ -90,7 +93,7 @@ func TestStateEntryHandle(t *testing.T) {
|
|||||||
eh := store.EntryHandle{Pathname: check.MustAbs(t.TempDir()).Append("entry"),
|
eh := store.EntryHandle{Pathname: check.MustAbs(t.TempDir()).Append("entry"),
|
||||||
ID: newTemplateState().ID}
|
ID: newTemplateState().ID}
|
||||||
|
|
||||||
if err := eh.Save(newTemplateState()); err != nil {
|
if err := save(&eh, newTemplateState()); err != nil {
|
||||||
t.Fatalf("save: error = %v", err)
|
t.Fatalf("save: error = %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user