Data-HashMap-Shared

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN

    as the path creates an anonymous "MAP_SHARED|MAP_ANONYMOUS" mapping that
    is inherited across "fork" but has no filesystem presence.

    "new_memfd" creates an unlinked memfd-backed map whose file descriptor
    can be passed to another process (via "SCM_RIGHTS", "fork"+"exec", or
    duped+open). "new_from_fd" reopens such a descriptor. Both require a
    64-bit Perl on Linux (memfd_create(2)). $max_entries, $max_size, $ttl,
    and $lru_skip are used only when creating a new file; when opening an
    existing one, all parameters are read from the stored header and the
    constructor arguments are ignored. Multiple processes can open the same
    file simultaneously. Dies if the file exists but was created by a
    different variant or is corrupt.

    Optional $max_size enables LRU eviction: when the map reaches $max_size
    entries, the least-recently-used entry is evicted on insert. Set to 0
    (default) to disable. LRU uses a clock/second-chance algorithm: "get"
    sets an accessed bit (lock-free, no write lock), and eviction gives a
    second chance to recently accessed entries before evicting.

    Optional $ttl sets a default time-to-live in seconds for all entries.
    Expired entries are lazily removed on access. Set to 0 (default) to
    disable. When TTL is active, "get" and "exists" check expiry.

    Optional $lru_skip (0-99, default 0) sets the probability (as a
    percentage) of skipping LRU promotion on "get". This reduces write-lock
    contention for Zipfian (power-law) access patterns where a small set of
    hot keys dominates reads. The LRU tail (eviction victim) is never
    skipped, preserving eviction correctness. Set to 0 for strict LRU
    ordering.

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

  String Keys and UTF-8
    String-key variants ("SS", "SI", "IS", "I16S", "I32S", "SI16", "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 not part of key identity. Consequences:

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

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

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

    Creates $shards independent maps (files "$path_prefix.0",
    "$path_prefix.1", ...) behind a single handle, each with up to
    $max_entries entries (total capacity is "$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.

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

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

  API
    Replace "xx" with variant prefix: "i16", "i32", "ii", "i16s", "i32s",
    "is", "si16", "si32", "si", "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 $n  = $map->set_multi($k, $v, ...);   # batch put under single lock, returns count
        my @v  = $map->get_multi($k1, $k2, ...); # batch get under single lock with prefetch pipeline
        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

    Integer-value variants also have:

        my $n = shm_xx_incr $map, $key;           # returns new value
        my $n = shm_xx_decr $map, $key;           # returns new value
        my $ok = shm_xx_cas $map, $key, $expected, $desired; # compare-and-swap
        my $n = shm_xx_incr_by $map, $key, $delta;

    LRU/TTL operations (require TTL-enabled map for "put_ttl"):

        my $ok = shm_xx_put_ttl $map, $key, $value, $ttl_sec;  # per-key TTL (0 = permanent); requires TTL-enabled map
        my $ms = shm_xx_max_size $map;            # LRU capacity (0 = disabled)
        my $t  = shm_xx_ttl $map;                 # default TTL in seconds
        my $r  = shm_xx_ttl_remaining $map, $key; # seconds left (0 = permanent, undef if missing/expired/no TTL)
        my $ok = shm_xx_touch $map, $key;         # reset TTL to default; promotes in LRU; false if no TTL/LRU
        my $ok = shm_xx_persist $map, $key;       # remove TTL, make key permanent; false on non-TTL maps
        my $ok = shm_xx_set_ttl $map, $key, $sec; # change TTL without changing value (0 = permanent); false on non-TTL maps
        my $n  = shm_xx_flush_expired $map;       # proactively expire all stale entries, returns count
        my ($n, $done) = shm_xx_flush_expired_partial $map, $limit;  # gradual: scan $limit slots

    Atomic remove-and-return:

        my $v = shm_xx_take $map, $key;           # remove key and return value (undef if missing)
        my ($k, $v) = shm_xx_pop $map;            # remove+return from LRU tail / scan forward
        my ($k, $v) = shm_xx_shift $map;          # remove+return from LRU head / scan backward
        my @kv = shm_xx_drain $map, $n;           # remove+return up to N entries as flat (k,v,...) list



( run in 0.745 second using v1.01-cache-2.11-cpan-39bf76dae61 )