Data-SortedSet-Shared

 view release on metacpan or  search on metacpan

Shared.xs  view on Meta::CPAN

        if (nr > 0) {
            Newx(mem, nr, int64_t); SAVEFREEPV(mem);   /* freed on return OR a longjmp from SvNV/SvIV magic */
            Newx(sco, nr, double);  SAVEFREEPV(sco);
            for (SSize_t i = 0; i < nr; i++) {
                SV **rv = av_fetch(av, i, 0);
                if (!rv) continue;
                SV *rsv = *rv;
                SvREFCNT_inc(rsv); sv_2mortal(rsv);   /* FETCH magic can drop the element from av */
                SvGETMAGIC(rsv);   /* a tied-array element is a deferred-magic PVLV */
                if (!SvROK(rsv) || SvTYPE(SvRV(rsv)) != SVt_PVAV) continue;   /* skip malformed */
                AV *row = (AV *)SvRV(rsv);
                SvREFCNT_inc((SV *)row); sv_2mortal((SV *)row);   /* element magic below can free the row AV */
                if (av_len(row) + 1 < 2) continue;
                SV **ms = av_fetch(row, 0, 0), **sv = av_fetch(row, 1, 0);
                if (!ms || !sv) continue;
                /* Pin both element SVs by value BEFORE any magic runs: the
                 * score's SvNV can free or reassign the row AV, dangling the
                 * other's raw SV** slot. */
                SV *memsv = *ms, *scosv = *sv;
                SvREFCNT_inc(memsv); sv_2mortal(memsv);
                SvREFCNT_inc(scosv); sv_2mortal(scosv);
                double score = SvNV(scosv);
                if (score != score) continue;                                       /* skip NaN */
                mem[n] = (int64_t)SvIV(memsv);
                sco[n] = score;
                n++;
            }
        }
        REEXTRACT(self);
        ss_rwlock_wrlock(h);
        if (h->hdr->sealed) { ss_rwlock_wrunlock(h); croak("Data::SortedSet::Shared->add_many: sorted set is frozen (read-only)"); }
        for (SSize_t i = 0; i < n; i++) {
            int rc = ss_add_locked(h, mem[i], sco[i]);
            if (rc == 1) added++;
            else if (rc == -1) break;                                           /* pool full */
        }
        __atomic_fetch_add(&h->hdr->stat_ops, 1, __ATOMIC_RELAXED);
        ss_rwlock_wrunlock(h);
        /* mem/sco freed by SAVEFREEPV at scope exit (croak-safe) */
    }
    RETVAL = added;
  OUTPUT:
    RETVAL

SV *
stats(self)
    SV *self
  PREINIT:
    EXTRACT(self);
  CODE:
    {
        uint32_t count, max_entries, height, node_capacity, index_slots, nodes_used;
        uint64_t ops;
        /* Snapshot the header fields under the lock; do all (croak-capable) Perl
           allocation after releasing it -- an OOM in newHV/newSVuv must never
           strand the read lock. */
        if (!h->readonly) ss_rwlock_rdlock(h);   /* frozen: immutable, no lock */
        SsHeader *hd = h->hdr;
        uint32_t nfree = 0, f = hd->node_free_head;
        /* node_free_head / parent free-links are file-stored: bound the index and
           cap iterations so a crafted out-of-range or cyclic free-list can't OOB
           or spin (never taken for a valid free-list of length <= node_capacity) */
        while (f != SS_NONE && ss_node_ok(h, f) && nfree <= h->node_capacity) { nfree++; f = h->nodes[f].parent; }   /* cached cap: trusted anti-spin bound */
        count         = hd->count;   /* backward-shift delete leaves no tombstones: occupied slots == count */
        max_entries   = hd->max_entries;
        height        = hd->height;
        node_capacity = hd->node_capacity;
        index_slots   = hd->index_slots;
        nodes_used    = hd->node_capacity - nfree;
        ops           = hd->stat_ops;
        if (!h->readonly) ss_rwlock_rdunlock(h);

        HV *hv = newHV();
        hv_stores(hv, "count",         newSVuv(count));
        hv_stores(hv, "max_entries",   newSVuv(max_entries));
        hv_stores(hv, "height",        newSVuv(height));
        hv_stores(hv, "node_capacity", newSVuv(node_capacity));
        hv_stores(hv, "nodes_used",    newSVuv(nodes_used));
        hv_stores(hv, "index_slots",   newSVuv(index_slots));
        hv_stores(hv, "index_load",    newSVnv((double)count / (double)index_slots));
        hv_stores(hv, "ops",           newSVuv(ops));
        hv_stores(hv, "mmap_size",     newSVuv((UV)h->mmap_size));
        hv_stores(hv, "frozen",        newSVuv(h->hdr->sealed ? 1 : 0));
        hv_stores(hv, "readonly",      newSVuv(h->readonly ? 1 : 0));
        RETVAL = newRV_noinc((SV *)hv);
    }
  OUTPUT:
    RETVAL



( run in 1.194 second using v1.01-cache-2.11-cpan-4ab04211f4c )