github.com/zhiqiangxu/util@v0.0.0-20230112053021-0a7aee056cd5/skl/lf/arena.go (about)

     1  package lf
     2  
     3  import (
     4  	"errors"
     5  	"sync/atomic"
     6  	"unsafe"
     7  
     8  	"github.com/zhiqiangxu/util/bytes"
     9  )
    10  
    11  // Arena is lock free
    12  type Arena struct {
    13  	n   uint32
    14  	buf []byte
    15  }
    16  
    17  var (
    18  	// ErrOOM used by Arena
    19  	ErrOOM = errors.New("oom")
    20  )
    21  
    22  // NewArena is ctor for Arena
    23  func NewArena(n uint32) *Arena {
    24  
    25  	// offset 0 is reserved for nil value
    26  	out := &Arena{n: 1, buf: bytes.AlignedTo8(n)}
    27  
    28  	return out
    29  }
    30  
    31  func (a *Arena) putKV(k, v []byte) (koff, voff uint32, err error) {
    32  	lk := uint32(len(k))
    33  	lv := uint32(len(v))
    34  	l := lk + lv
    35  	n := atomic.AddUint32(&a.n, l)
    36  	if int(n) > len(a.buf) {
    37  		err = ErrOOM
    38  		return
    39  	}
    40  
    41  	koff = n - l
    42  	copy(a.buf[koff:koff+lk], k)
    43  	voff = koff + lk
    44  	copy(a.buf[voff:voff+lv], v)
    45  	return
    46  }
    47  
    48  func (a *Arena) putBytes(b []byte) (offset uint32, err error) {
    49  	l := uint32(len(b))
    50  	n := atomic.AddUint32(&a.n, l)
    51  	if int(n) > len(a.buf) {
    52  		err = ErrOOM
    53  		return
    54  	}
    55  
    56  	offset = n - l
    57  	copy(a.buf[offset:n], b)
    58  	return
    59  
    60  }
    61  
    62  const (
    63  	nodeAlign = int(unsafe.Sizeof(uint64(0))) - 1
    64  )
    65  
    66  func (a *Arena) putListNode() (offset uint32, err error) {
    67  
    68  	// Pad the allocation with enough bytes to ensure pointer alignment.
    69  	l := uint32(ListNodeSize + nodeAlign)
    70  	n := atomic.AddUint32(&a.n, l)
    71  	if int(n) > len(a.buf) {
    72  		err = ErrOOM
    73  		return
    74  	}
    75  
    76  	// Return the aligned offset.
    77  	offset = (n - l + uint32(nodeAlign)) & ^uint32(nodeAlign)
    78  	return
    79  }
    80  
    81  func (a *Arena) getBytes(offset uint32, size uint16) []byte {
    82  	if offset == 0 {
    83  		return nil
    84  	}
    85  
    86  	return a.buf[offset : offset+uint32(size)]
    87  }
    88  func (a *Arena) getListNode(offset uint32) *listNode {
    89  	if offset == 0 {
    90  		return nil
    91  	}
    92  
    93  	return (*listNode)(unsafe.Pointer(&a.buf[offset]))
    94  }
    95  
    96  func (a *Arena) getListNodeOffset(n *listNode) uint32 {
    97  	if n == nil {
    98  		return 0
    99  	}
   100  
   101  	offset := uintptr(unsafe.Pointer(n)) - uintptr(unsafe.Pointer(&a.buf[0]))
   102  	return uint32(offset)
   103  }