Data-Pool-Shared
view release on metacpan or search on metacpan
Deterministic allocation order
$pool->scan_from(0); # next alloc scans from slot 0 (reproducible low-to-high)
By default each handle begins its bitmap scan at a getpid()-derived word
offset, spreading concurrent allocators across the bitmap to cut CAS
contention -- but that makes the allocated ids non-reproducible across
runs. For a single allocator that wants deterministic, sequential ids,
scan_from($slot) pins the scan start to $slot's 64-slot word (pass 0 for
low-to-high order). It is per-handle (does not affect other processes),
takes effect on the next "alloc", and an out-of-range $slot wraps. The
bitmap is still the source of truth, so this only changes *where* the scan
starts, never correctness. All typed variants inherit it.
Batch Operations
my $slots = $pool->alloc_n($n); # allocate N slots (blocking)
my $slots = $pool->alloc_n($n, $timeout); # with timeout
my $slots = $pool->alloc_n($n, 0); # non-blocking
# returns arrayref of indices, or undef (all-or-nothing)
my $freed = $pool->free_n(\@indices); # batch free, returns count freed
# single used-decrement + single futex wake (faster than N individual frees)
my $slots = $pool->allocated_slots; # arrayref of all allocated indices
Data Access
my $val = $pool->get($idx); # read slot
$pool->set($idx, $val); # write slot
For I64/I32 variants:
my $ok = $pool->cas($idx, $old, $new); # atomic CAS, returns bool
my $old = $pool->cmpxchg($idx, $old, $new); # atomic CAS, returns old value
my $old = $pool->xchg($idx, $val); # atomic exchange, returns old
my $val = $pool->add($idx, $delta); # atomic add, returns new value
my $val = $pool->incr($idx); # atomic increment
my $val = $pool->decr($idx); # atomic decrement
For Str variant:
my $max = $pool->max_len; # maximum string length
Raw Pointers
my $ptr = $pool->ptr($idx); # raw C pointer to slot data (UV)
my $ptr = $pool->data_ptr; # pointer to start of data section
"ptr" returns the memory address of a slot's data as an unsigned integer.
Use with FFI::Platypus, OpenGL "_c" functions, or XS code that needs a
"void*".
"data_ptr" returns the base of the contiguous data region. Slots are laid
out as "data_ptr + idx * elem_size".
Warning: The returned pointer becomes dangling if the pool object is
destroyed. Do not use after the pool goes out of scope.
Zero-Copy Access
my $sv = $pool->slot_sv($idx); # SV backed by slot memory
Returns a read-only scalar whose PV points directly into the shared memory
slot. Reading the returned scalar reads the slot with no "memcpy", which
matters for large slots. It keeps the pool object alive for as long as
that scalar (or a reference to it) is live.
Note that binding it with plain assignment makes an ordinary private
*copy* -- Perl copies the string on assignment, so
my $snap = $pool->slot_sv($idx); # a SNAPSHOT of the slot right now
is frozen and does not track later writes. To keep the live zero-copy view
that continues to reflect the slot's current contents (including after a
free()/re-allocation), use the return value directly or hold a reference:
my $ref = \$pool->slot_sv($idx); # live view; $$ref reads current slot
To modify the slot, use set().
Status
my $ok = $pool->is_allocated($idx);
my $cap = $pool->capacity;
my $esz = $pool->elem_size;
my $n = $pool->used; # allocated count
my $n = $pool->available; # free count
my $pid = $pool->owner($idx); # PID of allocator
Recovery
my $n = $pool->recover_stale; # free slots owned by dead PIDs
$pool->reset; # free all slots (exclusive access only)
Guards
my ($idx, $guard) = $pool->alloc_guard; # auto-free on scope exit
my ($idx, $guard) = $pool->alloc_guard($timeout);
my ($idx, $guard) = $pool->try_alloc_guard; # non-blocking
Convenience
my $idx = $pool->alloc_set($val); # alloc + set
my $idx = $pool->alloc_set($val, $timeout); # with timeout
my $idx = $pool->try_alloc_set($val); # non-blocking
$pool->each_allocated(sub { my $idx = shift; ... });
Common Methods
my $p = $pool->path; # backing file (undef if anon)
my $fd = $pool->memfd; # memfd fd (-1 if not memfd)
$pool->sync; # msync to disk
$pool->unlink; # remove backing file
my $s = $pool->stats; # diagnostic hashref
eventfd Integration
my $fd = $pool->eventfd; # create eventfd
$pool->eventfd_set($fd); # use existing fd
my $fd = $pool->fileno; # current eventfd (-1 if none)
$pool->notify; # signal eventfd
my $n = $pool->eventfd_consume; # drain counter
STATS
stats() returns a hashref with diagnostic counters. All values are
approximate under concurrency.
"capacity" -- total slot count (immutable)
"elem_size" -- bytes per slot (immutable)
"used" -- currently allocated slot count
( run in 0.861 second using v1.01-cache-2.11-cpan-14f38c9f855 )