Data-Reservoir-Shared
view release on metacpan or search on metacpan
SvGETMAGIC(wsv);
{ double w = SvOK(wsv) ? SvNV(wsv) : 0.0; /* undef -> 0 -> clean croak below, no warning */
if (!(w > 0.0) || !isfinite(w))
croak("Data::Reservoir::Shared->add_many: weight must be a finite number > 0");
ws[i] = w; }
} else if (el && *el) {
STRLEN len;
const char *src = SvPVbyte(*el, len); /* may run overload/tie/get-magic = arbitrary Perl */
/* Copy bytes into a private mortal SV NOW: a LATER element SvPVbyte can
* grow/free THIS element PV, dangling src before the locked loop uses it. */
SV *copy = sv_2mortal(newSVpvn(src, len));
ps[i] = SvPVX_const(copy);
ls[i] = len;
} else { ps[i] = ""; ls[i] = 0; }
}
}
/* Element get-magic in the resolve loop above (SvPVbyte / SvGETMAGIC on
* the weight) can also have destroyed self. Outside the `if (cnt)`
* block: an empty or tied size-0 array skips the loop but still
* reaches this lock. */
REEXTRACT(self);
rsv_rwlock_wrlock(h);
if (weighted)
for (i = 0; i < cnt; i++) stored += (UV)rsv_add_weighted_locked(h, ps[i], (uint64_t)ls[i], ws[i]);
else
for (i = 0; i < cnt; i++) stored += (UV)rsv_add_locked(h, ps[i], (uint64_t)ls[i]);
__atomic_fetch_add(&h->hdr->stat_ops, 1, __ATOMIC_RELAXED);
rsv_rwlock_wrunlock(h);
}
RETVAL = stored;
OUTPUT:
RETVAL
# ---- reading the sample ----
SV *
get(self, i)
SV *self
UV i
PREINIT:
EXTRACT(self);
const uint8_t *ptr; uint64_t len; int ok;
uint8_t *tmp = NULL;
CODE:
/* copy the item out under the read lock, then build the SV (no croak-capable
* Perl allocation while the lock is held) */
Newx(tmp, (size_t)h->item_size, uint8_t); SAVEFREEPV(tmp); /* cached: matches rsv_get_locked's clamp */
rsv_rwlock_rdlock(h);
ok = rsv_get_locked(h, (uint64_t)i, &ptr, &len);
if (ok) memcpy(tmp, ptr, (size_t)len);
rsv_rwlock_rdunlock(h);
RETVAL = ok ? newSVpvn((char *)tmp, (STRLEN)len) : &PL_sv_undef;
OUTPUT:
RETVAL
void
sample(self)
SV *self
PREINIT:
EXTRACT(self);
PPCODE:
{
uint64_t k = h->k, isz = h->stride, cnt, i; /* cached geometry: alloc + copy agree */
uint8_t *buf;
/* worst-case snapshot buffer (k slots) allocated BEFORE the lock */
Newx(buf, (size_t)(k * isz), uint8_t); SAVEFREEPV(buf);
rsv_rwlock_rdlock(h);
cnt = rsv_count_locked(h);
{
uint64_t smax = rsv_slots_max(h);
if (cnt > smax) cnt = smax;
memcpy(buf, rsv_slots(h), (size_t)(cnt * isz)); /* snapshot filled slots */
}
rsv_rwlock_rdunlock(h);
EXTEND(SP, (SSize_t)cnt);
for (i = 0; i < cnt; i++) {
uint8_t *slot = buf + i * isz;
uint64_t len; memcpy(&len, slot, sizeof(uint64_t));
if (len > h->item_size) len = h->item_size; /* cached clamp */
PUSHs(sv_2mortal(newSVpvn((char *)(slot + 8), (STRLEN)len)));
}
}
UV
count(self)
SV *self
PREINIT:
EXTRACT(self);
UV c;
CODE:
rsv_rwlock_rdlock(h);
c = (UV)rsv_count_locked(h);
rsv_rwlock_rdunlock(h);
RETVAL = c;
OUTPUT:
RETVAL
UV
seen(self)
SV *self
PREINIT:
EXTRACT(self);
UV s;
CODE:
rsv_rwlock_rdlock(h);
s = (UV)h->hdr->seen;
rsv_rwlock_rdunlock(h);
RETVAL = s;
OUTPUT:
RETVAL
# ---- mutation / introspection ----
void
clear(self)
SV *self
PREINIT:
EXTRACT(self);
CODE:
rsv_rwlock_wrlock(h);
rsv_clear_locked(h);
( run in 2.656 seconds using v1.01-cache-2.11-cpan-92ad3014f07 )