internal/store: remove compat adapter
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Test / Create distribution (push) Successful in 34s
				
			
		
			
				
	
				Test / Sandbox (push) Successful in 2m16s
				
			
		
			
				
	
				Test / Hakurei (push) Successful in 3m17s
				
			
		
			
				
	
				Test / Sandbox (race detector) (push) Successful in 4m12s
				
			
		
			
				
	
				Test / Hpkg (push) Successful in 4m18s
				
			
		
			
				
	
				Test / Hakurei (race detector) (push) Successful in 5m3s
				
			
		
			
				
	
				Test / Flake checks (push) Successful in 1m30s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Test / Create distribution (push) Successful in 34s
				
			Test / Sandbox (push) Successful in 2m16s
				
			Test / Hakurei (push) Successful in 3m17s
				
			Test / Sandbox (race detector) (push) Successful in 4m12s
				
			Test / Hpkg (push) Successful in 4m18s
				
			Test / Hakurei (race detector) (push) Successful in 5m3s
				
			Test / Flake checks (push) Successful in 1m30s
				
			This is no longer used as everything has been migrated. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
		
							parent
							
								
									24435694a5
								
							
						
					
					
						commit
						149bc3671a
					
				@ -1,186 +0,0 @@
 | 
				
			|||||||
package store
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"errors"
 | 
					 | 
				
			||||||
	"maps"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"hakurei.app/container/check"
 | 
					 | 
				
			||||||
	"hakurei.app/hst"
 | 
					 | 
				
			||||||
	"hakurei.app/message"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* this provides an implementation of Store on top of the improved state tracking to ease in the changes */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Compat 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.
 | 
					 | 
				
			||||||
	// Cursor provided to f becomes invalid as soon as f returns.
 | 
					 | 
				
			||||||
	Do(identity int, f func(c Cursor)) (ok bool, err error)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// List queries the store and returns a list of identities known to the store.
 | 
					 | 
				
			||||||
	// Note that some or all returned identities might not have any active apps.
 | 
					 | 
				
			||||||
	List() (identities []int, err error)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// storeAdapter satisfies [Compat] via [Store].
 | 
					 | 
				
			||||||
type storeAdapter struct {
 | 
					 | 
				
			||||||
	msg message.Msg
 | 
					 | 
				
			||||||
	*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) {
 | 
					 | 
				
			||||||
	segments, n, err := s.Segments()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	identities := make([]int, 0, n)
 | 
					 | 
				
			||||||
	for si := range segments {
 | 
					 | 
				
			||||||
		if si.Err != nil {
 | 
					 | 
				
			||||||
			if m, ok := message.GetMessage(err); ok {
 | 
					 | 
				
			||||||
				s.msg.Verbose(m)
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				// unreachable
 | 
					 | 
				
			||||||
				return nil, err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		identities = append(identities, si.Identity)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return identities, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// NewMulti returns an instance of the multi-file store.
 | 
					 | 
				
			||||||
func NewMulti(msg message.Msg, prefix *check.Absolute) Compat {
 | 
					 | 
				
			||||||
	return storeAdapter{msg, New(prefix.Append("state"))}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Cursor provides access to the store of an identity.
 | 
					 | 
				
			||||||
type Cursor interface {
 | 
					 | 
				
			||||||
	Save(state *hst.State) error
 | 
					 | 
				
			||||||
	Destroy(id hst.ID) error
 | 
					 | 
				
			||||||
	Load() (map[hst.ID]*hst.State, error)
 | 
					 | 
				
			||||||
	Len() (int, error)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// handleAdapter satisfies [Cursor] via [Handle].
 | 
					 | 
				
			||||||
type handleAdapter struct{ *Handle }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// do implements [Compat.Do] on [Handle].
 | 
					 | 
				
			||||||
func (h handleAdapter) do(f func(c Cursor)) (bool, error) {
 | 
					 | 
				
			||||||
	if unlock, err := h.Lock(); err != nil {
 | 
					 | 
				
			||||||
		return false, err
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		defer unlock()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	f(h)
 | 
					 | 
				
			||||||
	return true, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* these compatibility methods must only be called while fileMu is held */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (h handleAdapter) Save(state *hst.State) error { _, err := h.Handle.Save(state); return err }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (h handleAdapter) Destroy(id hst.ID) error {
 | 
					 | 
				
			||||||
	return (&EntryHandle{nil, h.Path.Append(id.String()), id}).Destroy()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (h handleAdapter) 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 handleAdapter) 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
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,120 +0,0 @@
 | 
				
			|||||||
package store_test
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"log"
 | 
					 | 
				
			||||||
	"math/rand"
 | 
					 | 
				
			||||||
	"reflect"
 | 
					 | 
				
			||||||
	"slices"
 | 
					 | 
				
			||||||
	"testing"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"hakurei.app/container/check"
 | 
					 | 
				
			||||||
	"hakurei.app/hst"
 | 
					 | 
				
			||||||
	"hakurei.app/internal/store"
 | 
					 | 
				
			||||||
	"hakurei.app/message"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestMulti(t *testing.T) {
 | 
					 | 
				
			||||||
	s := store.NewMulti(message.NewMsg(log.New(log.Writer(), "multi: ", 0)), check.MustAbs(t.TempDir()))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	t.Run("list empty store", func(t *testing.T) {
 | 
					 | 
				
			||||||
		if identities, err := s.List(); err != nil {
 | 
					 | 
				
			||||||
			t.Fatalf("List: error = %v", err)
 | 
					 | 
				
			||||||
		} else if len(identities) != 0 {
 | 
					 | 
				
			||||||
			t.Fatalf("List: identities = %#v", identities)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const (
 | 
					 | 
				
			||||||
		insertEntryChecked = iota
 | 
					 | 
				
			||||||
		insertEntryNoCheck
 | 
					 | 
				
			||||||
		insertEntryOtherApp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		tl
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var tc [tl]hst.State
 | 
					 | 
				
			||||||
	for i := 0; i < tl; i++ {
 | 
					 | 
				
			||||||
		if err := hst.NewInstanceID(&tc[i].ID); err != nil {
 | 
					 | 
				
			||||||
			t.Fatalf("cannot create dummy state: %v", err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		tc[i].PID = rand.Int()
 | 
					 | 
				
			||||||
		tc[i].Config = hst.Template()
 | 
					 | 
				
			||||||
		tc[i].Time = time.Now()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	do := func(identity int, f func(c store.Cursor)) {
 | 
					 | 
				
			||||||
		if ok, err := s.Do(identity, f); err != nil {
 | 
					 | 
				
			||||||
			t.Fatalf("Do: ok = %v, error = %v", ok, err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	insert := func(i, identity int) {
 | 
					 | 
				
			||||||
		do(identity, func(c store.Cursor) {
 | 
					 | 
				
			||||||
			if err := c.Save(&tc[i]); err != nil {
 | 
					 | 
				
			||||||
				t.Fatalf("Save: error = %v", err)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	check := func(i, identity int) {
 | 
					 | 
				
			||||||
		do(identity, func(c store.Cursor) {
 | 
					 | 
				
			||||||
			if entries, err := c.Load(); err != nil {
 | 
					 | 
				
			||||||
				t.Fatalf("Load: error = %v", err)
 | 
					 | 
				
			||||||
			} else if got, ok := entries[tc[i].ID]; !ok {
 | 
					 | 
				
			||||||
				t.Fatalf("Load: entry %s missing", &tc[i].ID)
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				got.Time = tc[i].Time
 | 
					 | 
				
			||||||
				if !reflect.DeepEqual(got, &tc[i]) {
 | 
					 | 
				
			||||||
					t.Fatalf("Load: entry %s got %#v, want %#v", &tc[i].ID, got, &tc[i])
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// insert entry checked
 | 
					 | 
				
			||||||
	insert(insertEntryChecked, 0)
 | 
					 | 
				
			||||||
	check(insertEntryChecked, 0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// insert entry unchecked
 | 
					 | 
				
			||||||
	insert(insertEntryNoCheck, 0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// insert entry different identity
 | 
					 | 
				
			||||||
	insert(insertEntryOtherApp, 1)
 | 
					 | 
				
			||||||
	check(insertEntryOtherApp, 1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// check previous insertion
 | 
					 | 
				
			||||||
	check(insertEntryNoCheck, 0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// list identities
 | 
					 | 
				
			||||||
	if identities, err := s.List(); err != nil {
 | 
					 | 
				
			||||||
		t.Fatalf("List: error = %v", err)
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		slices.Sort(identities)
 | 
					 | 
				
			||||||
		want := []int{0, 1}
 | 
					 | 
				
			||||||
		if !slices.Equal(identities, want) {
 | 
					 | 
				
			||||||
			t.Fatalf("List() = %#v, want %#v", identities, want)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// join store
 | 
					 | 
				
			||||||
	if entries, err := store.Join(s); err != nil {
 | 
					 | 
				
			||||||
		t.Fatalf("Join: error = %v", err)
 | 
					 | 
				
			||||||
	} else if len(entries) != 3 {
 | 
					 | 
				
			||||||
		t.Fatalf("Join(s) = %#v", entries)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// clear identity 1
 | 
					 | 
				
			||||||
	do(1, func(c store.Cursor) {
 | 
					 | 
				
			||||||
		if err := c.Destroy(tc[insertEntryOtherApp].ID); err != nil {
 | 
					 | 
				
			||||||
			t.Fatalf("Destroy: error = %v", err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	do(1, func(c store.Cursor) {
 | 
					 | 
				
			||||||
		if l, err := c.Len(); err != nil {
 | 
					 | 
				
			||||||
			t.Fatalf("Len: error = %v", err)
 | 
					 | 
				
			||||||
		} else if l != 0 {
 | 
					 | 
				
			||||||
			t.Fatalf("Len: %d, want 0", l)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user