Data-Intern-Shared

 view release on metacpan or  search on metacpan

Shared.xs  view on Meta::CPAN

  OUTPUT:
    RETVAL

void
clear(self)
    SV *self
  PREINIT:
    EXTRACT(self);
  CODE:
    si_rwlock_wrlock(h);
    si_clear_locked(h);
    si_rwlock_wrunlock(h);

SV *
intern(self, str)
    SV *self
    SV *str
  PREINIT:
    EXTRACT(self);
    STRLEN n;
    const char *s;
    int64_t id;
  CODE:
    s = SvPVbyte(str, n);
    si_rwlock_wrlock(h);
    id = si_intern_locked(h, s, n);
    __atomic_fetch_add(&h->hdr->stat_ops, 1, __ATOMIC_RELAXED);
    si_rwlock_wrunlock(h);
    RETVAL = (id < 0) ? &PL_sv_undef : newSVuv((UV)id);
  OUTPUT:
    RETVAL

SV *
id_of(self, str)
    SV *self
    SV *str
  PREINIT:
    EXTRACT(self);
    STRLEN n;
    const char *s;
    uint32_t id;
  CODE:
    s = SvPVbyte(str, n);
    si_rwlock_rdlock(h);
    int found = si_id_of_locked(h, s, n, &id);
    si_rwlock_rdunlock(h);
    RETVAL = found ? newSVuv(id) : &PL_sv_undef;
  OUTPUT:
    RETVAL

SV *
string(self, id)
    SV *self
    UV id
  PREINIT:

Shared.xs  view on Meta::CPAN

    SV *self
    SV *str
  PREINIT:
    EXTRACT(self);
    STRLEN n;
    const char *s;
    uint32_t id;
  CODE:
    s = SvPVbyte(str, n);
    si_rwlock_rdlock(h);
    RETVAL = si_id_of_locked(h, s, n, &id);
    si_rwlock_rdunlock(h);
  OUTPUT:
    RETVAL

SV *
stats(self)
    SV *self
  PREINIT:
    EXTRACT(self);
  CODE:

intern.h  view on Meta::CPAN

static inline void si_rwlock_spin_pause(void) {
#if defined(__x86_64__) || defined(__i386__)
    __asm__ volatile("pause" ::: "memory");
#elif defined(__aarch64__)
    __asm__ volatile("yield" ::: "memory");
#else
    __asm__ volatile("" ::: "memory");
#endif
}

/* Extract writer PID from rwlock value (lower 31 bits when write-locked). */
#define SI_RWLOCK_WRITER_BIT 0x80000000U
#define SI_RWLOCK_PID_MASK   0x7FFFFFFFU
#define SI_RWLOCK_WR(pid)    (SI_RWLOCK_WRITER_BIT | ((uint32_t)(pid) & SI_RWLOCK_PID_MASK))

/* Check if a PID is alive. Returns 1 if alive or unknown, 0 if definitely dead. */
/* Liveness via kill(pid,0). NOTE: cannot detect PID reuse -- if a dead
 * lock-holder's PID is recycled to an unrelated live process before recovery
 * runs, this reports "alive" and that slot's orphaned contribution is not
 * reclaimed until the recycled process exits. Robust detection would require
 * a per-slot process-start-time epoch (a header-layout/version change).

intern.h  view on Meta::CPAN

            if (__atomic_compare_exchange_n(lock, &cur, 1,
                    1, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
                return;
        }
        if (__builtin_expect(spin < SI_RWLOCK_SPIN_LIMIT, 1)) {
            si_rwlock_spin_pause();
            continue;
        }
        si_park_reader(h);
        cur = __atomic_load_n(lock, __ATOMIC_RELAXED);
        /* Sleep when write-locked OR when yielding to waiting writers */
        if (cur >= SI_RWLOCK_WRITER_BIT || cur == 0) {
            long rc = syscall(SYS_futex, lock, FUTEX_WAIT, cur,
                              &si_lock_timeout, NULL, 0);
            if (rc == -1 && errno == ETIMEDOUT) {
                si_unpark_reader(h);
                si_recover_after_timeout(h);
                spin = 0;
                continue;
            }
        }

intern.h  view on Meta::CPAN

static inline int si_msync(SiHandle *h) {
    if (!h || !h->hdr) return 0;
    return msync(h->hdr, h->mmap_size, MS_SYNC);
}

/* ================================================================
 * Interning (callers hold the lock)
 * ================================================================ */

/* reset to empty (caller holds the write lock) */
static inline void si_clear_locked(SiHandle *h) {
    SiHeader *hdr = h->hdr;
    hdr->count      = 0;
    hdr->arena_used = 0;
    memset(h->slots, 0, (size_t)hdr->hash_slots * sizeof(SiSlot));
}

/* the string record at arena offset `off`: sets *len, returns a pointer to the
   bytes (the uint32 length prefix is read unaligned-safely) */
static inline const char *si_arena_str(SiHandle *h, uint32_t off, uint32_t *len) {
    uint32_t l;

intern.h  view on Meta::CPAN

            const char *cand = si_arena_str(h, h->reverse[h->slots[i].id], &l);
            if (l == n && memcmp(cand, s, n) == 0) { *found = 1; return i; }
        }
        i = (i + 1) & mask;
    }
    *found = 0;
    return i;
}

/* id of (s,n) if present: returns 1 and sets *id, else 0 */
static inline int si_id_of_locked(SiHandle *h, const char *s, size_t n, uint32_t *id) {
    int f;
    uint32_t i = si_idx_find(h, s, n, si_hash(s, n), &f);
    if (f) { *id = h->slots[i].id; return 1; }
    return 0;
}

/* intern (s,n): returns the id (>=0, existing or new), or -1 if the id space or
   the arena is exhausted */
static int64_t si_intern_locked(SiHandle *h, const char *s, size_t n) {
    SiHeader *hdr = h->hdr;
    uint64_t hash = si_hash(s, n);
    int f;
    uint32_t slot = si_idx_find(h, s, n, hash, &f);
    if (f) return h->slots[slot].id;
    if (hdr->count >= hdr->max_strings) return -1;
    uint64_t need = (uint64_t)sizeof(uint32_t) + n;   /* arena cap (<= UINT32_MAX) also bounds n */
    if ((uint64_t)hdr->arena_used + need > hdr->arena_bytes) return -1;
    uint32_t off = hdr->arena_used;
    uint32_t l = (uint32_t)n;



( run in 0.372 second using v1.01-cache-2.11-cpan-bbe5e583499 )