update go-structr to v0.8.11 (#3380)

This commit is contained in:
kim 2024-10-02 10:58:20 +00:00 committed by GitHub
parent e3019eada4
commit c17abea921
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 306 additions and 91 deletions

2
go.mod
View file

@ -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

4
go.sum
View file

@ -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=

View file

@ -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

View file

@ -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 @@ type index_entry struct {
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

View file

@ -24,18 +24,22 @@ type indexed_item struct {
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]

View file

@ -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
}
}

180
vendor/codeberg.org/gruf/go-structr/ordered_list.bak generated vendored Normal file
View file

@ -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) {
}

View file

@ -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

View file

@ -2,7 +2,10 @@
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")
}

View file

@ -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
}

2
vendor/modules.txt vendored
View file

@ -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