Data-HashMap-Shared

 view release on metacpan or  search on metacpan

lib/Data/HashMap/Shared.pm  view on Meta::CPAN

it. For sharded maps it is the per-shard cap, like C<$max_entries>.

Optional C<$file_mode> (octal, default C<0600>) sets the permission bits
used when the backing file is created, with C<open(2)> semantics (masked
by the process umask). It is ignored when attaching an existing file and
for anonymous or memfd-backed maps. The default is owner-only; pass a
wider mode such as C<0666> to opt in to cross-user sharing. Before
version 0.14 the default was C<0666>.

B<Zero-cost when disabled>: with both C<$max_size=0> and C<$ttl=0>, the fast
lock-free read path is used. The only overhead is a branch (predicted away).

=head2 String Keys/Values and UTF-8

String-key variants (C<SS>, C<SI>, C<SI16>, C<SI32>) compare keys as raw
bytes: two keys are the same entry if and only if they contain the same
byte sequence. The SV UTF-8 flag is stored alongside the key so retrieval
round-trips it to the returned SV, but it is B<not> part of key identity.
Consequences:

=over

=item *

ASCII keys with a toggled UTF-8 flag hash and match the same entry
(C<use utf8>, C<utf8::upgrade>, and C<utf8::downgrade> on ASCII are all
equivalent from the map's point of view).

=item *

Non-ASCII keys with different byte encodings are B<distinct>. C<"caf\xe9">
(latin-1, 4 bytes) and C<"café"> with C<use utf8> (5 UTF-8 bytes) are two
different keys. If your input comes in mixed encodings, normalize with
C<Encode::encode_utf8> before use.

=back

String-value variants (C<SS>, C<IS>, C<I16S>, C<I32S>) store the SV UTF-8
flag alongside each value and round-trip it on retrieval. The C<cas>
comparison of C<$expected> against the stored value is byte-only -- the
UTF-8 flag on C<$expected> is ignored (same rationale as string-key
equality).

=head2 Sharding

    my $map = Data::HashMap::Shared::II->new_sharded($path_prefix, $shards, $max_entries, ...);

Creates C<$shards> independent maps (files C<$path_prefix.0>, C<$path_prefix.1>,
...) behind a single handle, each with up to C<$max_entries> entries
(total capacity is C<$shards * $max_entries>). Per-key operations automatically
route to the correct shard via hash dispatch. Writes to different shards
proceed in parallel with independent locks. C<new_sharded> requires a
filesystem C<$path_prefix>; anonymous (C<undef>-path) sharded maps are not
supported.

The batch ops (C<set_multi>, C<get_multi>, C<remove_multi>) dispatch each key
to its shard independently rather than holding one lock for the whole call, so
on a sharded map a batch is B<not> atomic across shards (the "single lock"
note in the API below applies to non-sharded maps).

All operations work transparently on sharded maps: C<put>, C<get>, C<remove>,
C<exists>, C<add>, C<update>, C<swap>, C<take>, C<incr>, C<max>, C<min>, C<cas>, C<cas_take>,
C<get_or_set>, C<put_ttl>, C<add_ttl>, C<update_ttl>, C<touch>, C<persist>,
C<set_ttl>, C<keys>, C<values>, C<items>, C<to_hash>, C<set_multi> (method only),
C<remove_multi> (method only), C<get_multi> (method only),
C<get_with_ttl> (method only), C<each>, C<pop>, C<shift>, C<drain>,
C<clear>, C<flush_expired>, C<flush_expired_partial>, C<size>,
C<stats> (method only), C<reserve>, and all diagnostic keywords.

Diagnostic counters and capacities reported for a sharded handle are
aggregate totals across all shards: C<size>, C<capacity>, C<max_entries>,
C<max_size>, C<tombstones>, C<mmap_size>, C<arena_used>, C<arena_cap>, and the
C<stats> eviction/expiry/recovery counts all sum over the shards. (C<ttl> is
the shared per-entry default, so it reports a single shard's value.)
C<reserve $n> pre-grows B<each> shard to C<$n> entries (not C<$n> in total).

Cursors chain across shards automatically. C<cursor_seek> routes to the
correct shard based on key hash. C<$shards> is rounded up to the next
power of 2.

=head2 API

Replace C<xx> with variant prefix: C<i16>, C<i32>, C<ii>, C<i16s>,
C<i32s>, C<is>, C<si16>, C<si32>, C<si>, C<ss>.

    my $ok = shm_xx_put $map, $key, $value;   # insert or overwrite
    my $ok = shm_xx_add $map, $key, $value;   # insert only if key absent
    my $ok = shm_xx_update $map, $key, $value; # overwrite only if key exists
    my $old = shm_xx_swap $map, $key, $value; # put + return old value (undef if new)
    my $ok = shm_xx_cas $map, $key, $expected, $desired; # compare-and-swap
    my $v  = shm_xx_cas_take $map, $key, $expected; # compare-and-remove; returns value on match, undef otherwise
    my $n  = $map->set_multi($k, $v, ...);   # batch put under single lock, returns count
    my $n  = $map->remove_multi(@keys);      # batch remove under single lock, returns count
    my @v  = $map->get_multi($k1, $k2, ...); # batch get under single lock with prefetch pipeline
    my ($v, $ttl) = $map->get_with_ttl($key); # atomic snapshot; () if missing, $ttl is undef on non-TTL map, 0 = permanent; sets LRU clock bit
    my $v  = shm_xx_get $map, $key;           # returns undef if not found
    my $ok = shm_xx_remove $map, $key;        # returns false if not found
    my $ok = shm_xx_exists $map, $key;        # returns boolean
    my $s  = shm_xx_size $map;
    my $m  = shm_xx_max_entries $map;
    my @k  = shm_xx_keys $map;
    my @v  = shm_xx_values $map;
    my @items = shm_xx_items $map;            # flat (k, v, k, v, ...)
    while (my ($k, $v) = shm_xx_each $map) { ... }  # auto-resets at end
    shm_xx_iter_reset $map;
    shm_xx_clear $map;
    my $href = shm_xx_to_hash $map;
    my $v  = shm_xx_get_or_set $map, $key, $default;  # returns value

C<get_or_set> returns the existing value, or stores and returns C<$default>
when the key is absent. It returns C<undef> only if the key is absent and the
value cannot be stored -- the map is at C<max_entries>, or (string-value
variants) the arena is full.

C<cas> is available for all variants. Returns true when the stored value
matched C<$expected> and was atomically replaced with C<$desired>; false
if the key is missing or expired, the value did not match, or (string-value
variants) the arena is full. See L</"String Keys/Values and UTF-8"> for
the byte-only comparison rule.

C<swap> returns the previous value, or C<undef> when the key did not exist



( run in 2.558 seconds using v1.01-cache-2.11-cpan-7fcb06a456a )