Data-Intern-Shared
view release on metacpan or search on metacpan
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:
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:
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).
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;
}
}
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;
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 )