diff --git a/go.mod b/go.mod index 34634df58..8ea13ead0 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( codeberg.org/gruf/go-runners v1.6.3 codeberg.org/gruf/go-sched v1.2.4 codeberg.org/gruf/go-storage v0.2.0 - codeberg.org/gruf/go-structr v0.8.10 + codeberg.org/gruf/go-structr v0.8.11 codeberg.org/superseriousbusiness/exif-terminator v0.9.0 github.com/DmitriyVTitov/size v1.5.0 github.com/KimMachineGun/automemlimit v0.6.1 diff --git a/go.sum b/go.sum index e2f262f2c..ab0892565 100644 --- a/go.sum +++ b/go.sum @@ -72,8 +72,8 @@ codeberg.org/gruf/go-sched v1.2.4 h1:ddBB9o0D/2oU8NbQ0ldN5aWxogpXPRBATWi58+p++Hw codeberg.org/gruf/go-sched v1.2.4/go.mod h1:wad6l+OcYGWMA2TzNLMmLObsrbBDxdJfEy5WvTgBjNk= codeberg.org/gruf/go-storage v0.2.0 h1:mKj3Lx6AavEkuXXtxqPhdq+akW9YwrnP16yQBF7K5ZI= codeberg.org/gruf/go-storage v0.2.0/go.mod h1:o3GzMDE5QNUaRnm/daUzFqvuAaC4utlgXDXYO79sWKU= -codeberg.org/gruf/go-structr v0.8.10 h1:uSapW97/StRnYEhCtycaM0isCsEMYC+tx/knYr6SiVo= -codeberg.org/gruf/go-structr v0.8.10/go.mod h1:zkoXVrAnKosh8VFAsbP/Hhs8FmLBjbVVy5w/Ngm8ApM= +codeberg.org/gruf/go-structr v0.8.11 h1:I3cQCHpK3fQSXWaaUfksAJRN4+efULiuF11Oi/m8c+o= +codeberg.org/gruf/go-structr v0.8.11/go.mod h1:zkoXVrAnKosh8VFAsbP/Hhs8FmLBjbVVy5w/Ngm8ApM= codeberg.org/superseriousbusiness/exif-terminator v0.9.0 h1:/EfyGI6HIrbkhFwgXGSjZ9o1kr/+k8v4mKdfXTH02Go= codeberg.org/superseriousbusiness/exif-terminator v0.9.0/go.mod h1:gCWKduudUWFzsnixoMzu0FYVdxHWG+AbXnZ50DqxsUE= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= diff --git a/vendor/codeberg.org/gruf/go-structr/cache.go b/vendor/codeberg.org/gruf/go-structr/cache.go index 4bea32c89..3705d7c7c 100644 --- a/vendor/codeberg.org/gruf/go-structr/cache.go +++ b/vendor/codeberg.org/gruf/go-structr/cache.go @@ -119,9 +119,9 @@ func (c *Cache[T]) Init(config CacheConfig[T]) { // Index selects index with given name from cache, else panics. func (c *Cache[T]) Index(name string) *Index { - for i := range c.indices { - if c.indices[i].name == name { - return &c.indices[i] + for i, idx := range c.indices { + if idx.name == name { + return &(c.indices[i]) } } panic("unknown index: " + name) @@ -337,13 +337,16 @@ func (c *Cache[T]) Load(index *Index, keys []Key, load func([]Key) ([]T, error)) panic("not initialized") } - for i := 0; i < len(keys); { + // Iterate keys and catch uncached. + toLoad := make([]Key, 0, len(keys)) + for _, key := range keys { + // Value length before // any below appends. before := len(values) // Concatenate all *values* from cached items. - index.get(keys[i].key, func(item *indexed_item) { + index.get(key.key, func(item *indexed_item) { if value, ok := item.data.(T); ok { // Append value COPY. value = c.copy(value) @@ -358,30 +361,22 @@ func (c *Cache[T]) Load(index *Index, keys []Key, load func([]Key) ([]T, error)) // Only if values changed did // we actually find anything. - if len(values) != before { - - // We found values at key, - // drop key from the slice. - copy(keys[i:], keys[i+1:]) - keys = keys[:len(keys)-1] - continue + if len(values) == before { + toLoad = append(toLoad, key) } - - // Iter - i++ } // Done with // the lock. unlock() - if len(keys) == 0 { + if len(toLoad) == 0 { // We loaded everything! return values, nil } - // Load uncached values. - uncached, err := load(keys) + // Load uncached key values. + uncached, err := load(toLoad) if err != nil { return nil, err } @@ -515,8 +510,8 @@ func (c *Cache[T]) Trim(perc float64) { } // Compact index data stores. - for i := range c.indices { - c.indices[i].data.Compact() + for _, idx := range c.indices { + (&idx).data.Compact() } // Done with lock. @@ -536,17 +531,17 @@ func (c *Cache[T]) Len() int { // Debug returns debug stats about cache. func (c *Cache[T]) Debug() map[string]any { - m := make(map[string]any) + m := make(map[string]any, 2) c.mutex.Lock() m["lru"] = c.lru.len - indices := make(map[string]any) + indices := make(map[string]any, len(c.indices)) m["indices"] = indices - for i := range c.indices { + for _, idx := range c.indices { var n uint64 - for _, l := range c.indices[i].data.m { + for _, l := range idx.data.m { n += uint64(l.len) } - indices[c.indices[i].name] = n + indices[idx.name] = n } c.mutex.Unlock() return m @@ -588,7 +583,7 @@ func (c *Cache[T]) store_value(index *Index, key string, value T) { for i := range c.indices { // Get current index ptr. - idx := &(c.indices[i]) + idx := (&c.indices[i]) if idx == index { // Already stored under diff --git a/vendor/codeberg.org/gruf/go-structr/index.go b/vendor/codeberg.org/gruf/go-structr/index.go index 127bddb1f..558832da9 100644 --- a/vendor/codeberg.org/gruf/go-structr/index.go +++ b/vendor/codeberg.org/gruf/go-structr/index.go @@ -197,8 +197,13 @@ func (i *Index) get(key string, hook func(*indexed_item)) { return } - // Iterate all entries in list. - l.rangefn(func(elem *list_elem) { + // Iterate the list. + for elem := l.head; // + elem != nil; // + { + // Get next before + // any modification. + next := elem.next // Extract element entry + item. entry := (*index_entry)(elem.data) @@ -206,18 +211,21 @@ func (i *Index) get(key string, hook func(*indexed_item)) { // Pass to hook. hook(item) - }) + + // Set next. + elem = next + } } // key uses hasher to generate Key{} from given raw parts. func (i *Index) key(buf *byteutil.Buffer, parts []unsafe.Pointer) string { + buf.B = buf.B[:0] if len(parts) != len(i.fields) { panicf("incorrect number key parts: want=%d received=%d", len(i.fields), len(parts), ) } - buf.B = buf.B[:0] if !allow_zero(i.flags) { for x, field := range i.fields { before := len(buf.B) @@ -301,8 +309,13 @@ func (i *Index) delete(key string, hook func(*indexed_item)) { // Delete at hash. i.data.Delete(key) - // Iterate entries in list. - l.rangefn(func(elem *list_elem) { + // Iterate the list. + for elem := l.head; // + elem != nil; // + { + // Get next before + // any modification. + next := elem.next // Remove elem. l.remove(elem) @@ -319,7 +332,10 @@ func (i *Index) delete(key string, hook func(*indexed_item)) { // Pass to hook. hook(item) - }) + + // Set next. + elem = next + } // Release list. free_list(l) @@ -375,17 +391,21 @@ var index_entry_pool sync.Pool func new_index_entry() *index_entry { v := index_entry_pool.Get() if v == nil { - v = new(index_entry) + e := new(index_entry) + e.elem.data = unsafe.Pointer(e) + v = e } entry := v.(*index_entry) - ptr := unsafe.Pointer(entry) - entry.elem.data = ptr return entry } // free_index_entry releases the index_entry. func free_index_entry(entry *index_entry) { - entry.elem.data = nil + if entry.elem.next != nil || + entry.elem.prev != nil { + should_not_reach() + return + } entry.key = "" entry.index = nil entry.item = nil diff --git a/vendor/codeberg.org/gruf/go-structr/item.go b/vendor/codeberg.org/gruf/go-structr/item.go index 3191f2beb..6178e18e3 100644 --- a/vendor/codeberg.org/gruf/go-structr/item.go +++ b/vendor/codeberg.org/gruf/go-structr/item.go @@ -24,18 +24,22 @@ var indexed_item_pool sync.Pool func new_indexed_item() *indexed_item { v := indexed_item_pool.Get() if v == nil { - v = new(indexed_item) + i := new(indexed_item) + i.elem.data = unsafe.Pointer(i) + v = i } item := v.(*indexed_item) - ptr := unsafe.Pointer(item) - item.elem.data = ptr return item } // free_indexed_item releases the indexed_item. func free_indexed_item(item *indexed_item) { - item.elem.data = nil - item.indexed = item.indexed[:0] + if len(item.indexed) > 0 || + item.elem.next != nil || + item.elem.prev != nil { + should_not_reach() + return + } item.data = nil indexed_item_pool.Put(item) } @@ -50,7 +54,7 @@ func (i *indexed_item) drop_index(entry *index_entry) { continue } - // Move all index entries down + reslice. + // Reslice index entries minus 'x'. _ = copy(i.indexed[x:], i.indexed[x+1:]) i.indexed[len(i.indexed)-1] = nil i.indexed = i.indexed[:len(i.indexed)-1] diff --git a/vendor/codeberg.org/gruf/go-structr/list.go b/vendor/codeberg.org/gruf/go-structr/list.go index 764036d47..bf380aa26 100644 --- a/vendor/codeberg.org/gruf/go-structr/list.go +++ b/vendor/codeberg.org/gruf/go-structr/list.go @@ -40,9 +40,12 @@ func new_list() *list { // free_list releases the list. func free_list(list *list) { - list.head = nil - list.tail = nil - list.len = 0 + if list.head != nil || + list.tail != nil || + list.len != 0 { + should_not_reach() + return + } list_pool.Put(list) } @@ -115,21 +118,28 @@ func (l *list) remove(elem *list_elem) { elem.prev = nil switch { - // elem is ONLY one in list. - case next == nil && prev == nil: - l.head = nil - l.tail = nil + case next == nil: + if prev == nil { + // next == nil && prev == nil + // + // elem is ONLY one in list. + l.head = nil + l.tail = nil + } else { + // next == nil && prev != nil + // + // elem is last in list. + l.tail = prev + prev.next = nil + } - // elem is front in list. - case next != nil && prev == nil: + case prev == nil: + // next != nil && prev == nil + // + // elem is front in list. l.head = next next.prev = nil - // elem is last in list. - case prev != nil && next == nil: - l.tail = prev - prev.next = nil - // elem in middle of list. default: next.prev = prev @@ -139,17 +149,3 @@ func (l *list) remove(elem *list_elem) { // Decr count l.len-- } - -// rangefn will range all elems in list, passing each to fn. -func (l *list) rangefn(fn func(*list_elem)) { - if fn == nil { - panic("nil fn") - } - for e := l.head; // - e != nil; // - { - n := e.next - fn(e) - e = n - } -} diff --git a/vendor/codeberg.org/gruf/go-structr/ordered_list.bak b/vendor/codeberg.org/gruf/go-structr/ordered_list.bak new file mode 100644 index 000000000..46b56853f --- /dev/null +++ b/vendor/codeberg.org/gruf/go-structr/ordered_list.bak @@ -0,0 +1,180 @@ +package structr + +import "sync" + +type Timeline[StructType any, PK comparable] struct { + + // hook functions. + pkey func(StructType) PK + gte func(PK, PK) bool + lte func(PK, PK) bool + copy func(StructType) StructType + + // main underlying + // ordered item list. + list list + + // indices used in storing passed struct + // types by user defined sets of fields. + indices []Index + + // protective mutex, guards: + // - TODO + mutex sync.Mutex +} + +func (t *Timeline[T, PK]) Init(config any) { + +} + +func (t *Timeline[T, PK]) Index(name string) *Index { + for i := range t.indices { + if t.indices[i].name == name { + return &t.indices[i] + } + } + panic("unknown index: " + name) +} + +func (t *Timeline[T, PK]) Insert(values ...T) { + +} + +func (t *Timeline[T, PK]) LoadTop(min, max PK, length int, load func(min, max PK, length int) ([]T, error)) ([]T, error) { + // Allocate expected no. values. + values := make([]T, 0, length) + + // Acquire lock. + t.mutex.Lock() + + // Wrap unlock to only do once. + unlock := once(t.mutex.Unlock) + defer unlock() + + // Check init'd. + if t.copy == nil { + panic("not initialized") + } + + // Iterate through linked list from top (i.e. head). + for next := t.list.head; next != nil; next = next.next { + + // Check if we've gathered + // enough values from timeline. + if len(values) >= length { + return values, nil + } + + item := (*indexed_item)(next.data) + value := item.data.(T) + pkey := t.pkey(value) + + // Check if below min. + if t.lte(pkey, min) { + continue + } + + // Update min. + min = pkey + + // Check if above max. + if t.gte(pkey, max) { + break + } + + // Append value copy. + value = t.copy(value) + values = append(values, value) + } +} + +func (t *Timeline[T, PK]) LoadBottom(min, max PK, length int, load func(min, max PK, length int) ([]T, error)) ([]T, error) { + // Allocate expected no. values. + values := make([]T, 0, length) + + // Acquire lock. + t.mutex.Lock() + + // Wrap unlock to only do once. + unlock := once(t.mutex.Unlock) + defer unlock() + + // Check init'd. + if t.copy == nil { + panic("not initialized") + } + + // Iterate through linked list from bottom (i.e. tail). + for next := t.list.tail; next != nil; next = next.prev { + + // Check if we've gathered + // enough values from timeline. + if len(values) >= length { + return values, nil + } + + item := (*indexed_item)(next.data) + value := item.data.(T) + pkey := t.pkey(value) + + // Check if above max. + if t.gte(pkey, max) { + continue + } + + // Update max. + max = pkey + + // Check if below min. + if t.lte(pkey, min) { + break + } + + // Append value copy. + value = t.copy(value) + values = append(values, value) + } + + // Done with + // the lock. + unlock() + + // Attempt to load values up to given length. + next, err := load(min, max, length-len(values)) + if err != nil { + return nil, err + } + + // Acquire lock. + t.mutex.Lock() + + // Store uncached values. + for i := range next { + t.store_value( + nil, "", + uncached[i], + ) + } + + // Done with lock. + t.mutex.Unlock() + + // Append uncached to return values. + values = append(values, next...) + + return values, nil +} + +func (t *Timeline[T, PK]) index(value T) *indexed_item { + pk := t.pkey(value) + + switch { + case t.list.len == 0: + + case pk < t.list.head.data: + } +} + +func (t *Timeline[T, PK]) delete(item *indexed_item) { + +} diff --git a/vendor/codeberg.org/gruf/go-structr/queue.go b/vendor/codeberg.org/gruf/go-structr/queue.go index 0e4f4e3cf..dab925f95 100644 --- a/vendor/codeberg.org/gruf/go-structr/queue.go +++ b/vendor/codeberg.org/gruf/go-structr/queue.go @@ -68,9 +68,9 @@ func (q *Queue[T]) Init(config QueueConfig[T]) { // Index selects index with given name from queue, else panics. func (q *Queue[T]) Index(name string) *Index { - for i := range q.indices { - if q.indices[i].name == name { - return &q.indices[i] + for i, idx := range q.indices { + if idx.name == name { + return &(q.indices[i]) } } panic("unknown index: " + name) @@ -207,17 +207,17 @@ func (q *Queue[T]) Len() int { // Debug returns debug stats about queue. func (q *Queue[T]) Debug() map[string]any { - m := make(map[string]any) + m := make(map[string]any, 2) q.mutex.Lock() m["queue"] = q.queue.len - indices := make(map[string]any) + indices := make(map[string]any, len(q.indices)) m["indices"] = indices - for i := range q.indices { + for _, idx := range q.indices { var n uint64 - for _, l := range q.indices[i].data.m { + for _, l := range idx.data.m { n += uint64(l.len) } - indices[q.indices[i].name] = n + indices[idx.name] = n } q.mutex.Unlock() return m diff --git a/vendor/codeberg.org/gruf/go-structr/runtime.go b/vendor/codeberg.org/gruf/go-structr/runtime.go index d2bdba380..6e8af83dd 100644 --- a/vendor/codeberg.org/gruf/go-structr/runtime.go +++ b/vendor/codeberg.org/gruf/go-structr/runtime.go @@ -2,7 +2,10 @@ package structr import ( "fmt" + "os" "reflect" + "runtime" + "strings" "unicode" "unicode/utf8" "unsafe" @@ -182,7 +185,32 @@ func deref(p unsafe.Pointer, n uint) unsafe.Pointer { return p } +// eface_data returns the data ptr from an empty interface. +func eface_data(a any) unsafe.Pointer { + type eface struct{ _, data unsafe.Pointer } + return (*eface)(unsafe.Pointer(&a)).data +} + // panicf provides a panic with string formatting. func panicf(format string, args ...any) { panic(fmt.Sprintf(format, args...)) } + +// should_not_reach can be called to indicated a +// block of code should not be able to be reached, +// else it prints callsite info with a BUG report. +// +//go:noinline +func should_not_reach() { + pcs := make([]uintptr, 1) + _ = runtime.Callers(2, pcs) + fn := runtime.FuncForPC(pcs[0]) + funcname := "go-structr" // by default use just our library name + if fn != nil { + funcname = fn.Name() + if i := strings.LastIndexByte(funcname, '/'); i != -1 { + funcname = funcname[i+1:] + } + } + os.Stderr.WriteString("BUG: assertion failed in " + funcname + "\n") +} diff --git a/vendor/codeberg.org/gruf/go-structr/util.go b/vendor/codeberg.org/gruf/go-structr/util.go index 84c98074d..46535fcff 100644 --- a/vendor/codeberg.org/gruf/go-structr/util.go +++ b/vendor/codeberg.org/gruf/go-structr/util.go @@ -1,7 +1,5 @@ package structr -import "unsafe" - // once only executes 'fn' once. func once(fn func()) func() { var once int32 @@ -13,9 +11,3 @@ func once(fn func()) func() { fn() } } - -// eface_data returns the data ptr from an empty interface. -func eface_data(a any) unsafe.Pointer { - type eface struct{ _, data unsafe.Pointer } - return (*eface)(unsafe.Pointer(&a)).data -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 81907ce93..ea6f6b10a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -66,7 +66,7 @@ codeberg.org/gruf/go-storage/disk codeberg.org/gruf/go-storage/internal codeberg.org/gruf/go-storage/memory codeberg.org/gruf/go-storage/s3 -# codeberg.org/gruf/go-structr v0.8.10 +# codeberg.org/gruf/go-structr v0.8.11 ## explicit; go 1.21 codeberg.org/gruf/go-structr # codeberg.org/superseriousbusiness/exif-terminator v0.9.0