File Coverage

Shared.xs
Criterion Covered Total %
statement 86 86 100.0
branch 69 110 62.7
condition n/a
subroutine n/a
pod n/a
total 155 196 79.0


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5             #include "ppport.h"
6             #include "radix.h"
7              
8             #define EXTRACT(sv) \
9             if (!sv_isobject(sv) || !sv_derived_from(sv, "Data::RadixTree::Shared")) \
10             croak("Expected a Data::RadixTree::Shared object"); \
11             RdxHandle *h = INT2PTR(RdxHandle*, SvIV(SvRV(sv))); \
12             if (!h) croak("Attempted to use a destroyed Data::RadixTree::Shared object")
13              
14             #define MAKE_OBJ(class, handle) \
15             SV *obj = newSViv(PTR2IV(handle)); \
16             SV *ref = newRV_noinc(obj); \
17             sv_bless(ref, gv_stashpv(class, GV_ADD)); \
18             RETVAL = ref
19              
20             MODULE = Data::RadixTree::Shared PACKAGE = Data::RadixTree::Shared
21              
22             PROTOTYPES: DISABLE
23              
24             SV *
25             new(class, path = &PL_sv_undef, node_capacity = 4096, arena_capacity = 65536)
26             const char *class
27             SV *path
28             UV node_capacity
29             UV arena_capacity
30             PREINIT:
31             char errbuf[RDX_ERR_BUFLEN];
32             CODE:
33 26 100         const char *p = SvOK(path) ? SvPV_nolen(path) : NULL;
34 26           RdxHandle *h = rdx_create(p, (uint64_t)node_capacity, (uint64_t)arena_capacity, errbuf); /* validates args into errbuf */
35 26 100         if (!h) croak("Data::RadixTree::Shared->new: %s", errbuf);
36 21           MAKE_OBJ(class, h);
37             OUTPUT:
38             RETVAL
39              
40             SV *
41             new_memfd(class, name = &PL_sv_undef, node_capacity = 4096, arena_capacity = 65536)
42             const char *class
43             SV *name
44             UV node_capacity
45             UV arena_capacity
46             PREINIT:
47             char errbuf[RDX_ERR_BUFLEN];
48             CODE:
49 3 100         const char *nm = SvOK(name) ? SvPV_nolen(name) : NULL; /* undef -> default label */
50 3           RdxHandle *h = rdx_create_memfd(nm, (uint64_t)node_capacity, (uint64_t)arena_capacity, errbuf); /* validates args into errbuf */
51 3 100         if (!h) croak("Data::RadixTree::Shared->new_memfd: %s", errbuf);
52 2           MAKE_OBJ(class, h);
53             OUTPUT:
54             RETVAL
55              
56             SV *
57             new_from_fd(class, fd)
58             const char *class
59             int fd
60             PREINIT:
61             char errbuf[RDX_ERR_BUFLEN];
62             CODE:
63 2           RdxHandle *h = rdx_open_fd(fd, errbuf);
64 2 100         if (!h) croak("Data::RadixTree::Shared->new_from_fd: %s", errbuf);
65 1           MAKE_OBJ(class, h);
66             OUTPUT:
67             RETVAL
68              
69             void
70             DESTROY(self)
71             SV *self
72             CODE:
73 26 50         if (sv_isobject(self) && sv_derived_from(self, "Data::RadixTree::Shared")) {
    50          
74 26           RdxHandle *h = INT2PTR(RdxHandle*, SvIV(SvRV(self)));
75 26 100         if (h) { sv_setiv(SvRV(self), 0); rdx_destroy(h); } /* null first: activates EXTRACT's use-after-destroy croak + makes a double DESTROY a no-op */
76             }
77              
78             IV
79             insert(self, key, value = 1)
80             SV *self
81             SV *key
82             UV value
83             PREINIT:
84 1093 50         EXTRACT(self);
    50          
    50          
85             STRLEN klen;
86             const char *kp;
87             int isnew;
88             CODE:
89             /* Resolve key bytes BEFORE locking: SvPVbyte croaks on wide chars, and a
90             croak must never happen while holding the lock. */
91 1093           kp = SvPVbyte(key, klen);
92 1091           rdx_rwlock_wrlock(h);
93 1091 100         if (!rdx_insert_has_room(h, (uint32_t)klen)) {
94 3           rdx_rwlock_wrunlock(h); /* release BEFORE croak */
95 3           croak("Data::RadixTree::Shared->insert: capacity exhausted "
96             "(node pool or label arena full; grow node/arena capacity)");
97             }
98 1088           isnew = rdx_insert_locked(h, (const uint8_t *)kp, (uint32_t)klen, (uint64_t)value);
99 1088           __atomic_fetch_add(&h->hdr->stat_ops, 1, __ATOMIC_RELAXED);
100 1088           rdx_rwlock_wrunlock(h);
101 1088 100         RETVAL = (IV)isnew;
102             OUTPUT:
103             RETVAL
104              
105             SV *
106             lookup(self, key)
107             SV *self
108             SV *key
109             PREINIT:
110 1604 50         EXTRACT(self);
    50          
    100          
111             STRLEN klen;
112             const char *kp;
113             uint64_t val;
114             int found;
115             CODE:
116 1603           kp = SvPVbyte(key, klen); /* before the lock */
117 1602           rdx_rwlock_rdlock(h);
118 1602           found = rdx_lookup_locked(h, (const uint8_t *)kp, (uint32_t)klen, &val);
119 1602           rdx_rwlock_rdunlock(h);
120 1602 100         RETVAL = found ? newSVuv((UV)val) : &PL_sv_undef;
121             OUTPUT:
122             RETVAL
123              
124             bool
125             exists(self, key)
126             SV *self
127             SV *key
128             PREINIT:
129 1592 50         EXTRACT(self);
    50          
    50          
130             STRLEN klen;
131             const char *kp;
132             CODE:
133 1592           kp = SvPVbyte(key, klen); /* before the lock */
134 1591           rdx_rwlock_rdlock(h);
135 1591           RETVAL = rdx_lookup_locked(h, (const uint8_t *)kp, (uint32_t)klen, NULL) ? 1 : 0;
136 1591           rdx_rwlock_rdunlock(h);
137             OUTPUT:
138             RETVAL
139              
140             SV *
141             longest_prefix(self, key)
142             SV *self
143             SV *key
144             PREINIT:
145 44 50         EXTRACT(self);
    50          
    50          
146             STRLEN klen;
147             const char *kp;
148             uint64_t val;
149             int found;
150             CODE:
151 44           kp = SvPVbyte(key, klen); /* before the lock */
152 43           rdx_rwlock_rdlock(h);
153 43           found = rdx_longest_prefix_locked(h, (const uint8_t *)kp, (uint32_t)klen, &val);
154 43           rdx_rwlock_rdunlock(h);
155 43 100         RETVAL = found ? newSVuv((UV)val) : &PL_sv_undef;
156             OUTPUT:
157             RETVAL
158              
159             IV
160             delete(self, key)
161             SV *self
162             SV *key
163             PREINIT:
164 525 50         EXTRACT(self);
    50          
    50          
165             STRLEN klen;
166             const char *kp;
167             int removed;
168             CODE:
169 525           kp = SvPVbyte(key, klen); /* before the lock */
170 524           rdx_rwlock_wrlock(h);
171 524           removed = rdx_delete_locked(h, (const uint8_t *)kp, (uint32_t)klen);
172 524           __atomic_fetch_add(&h->hdr->stat_ops, 1, __ATOMIC_RELAXED);
173 524           rdx_rwlock_wrunlock(h);
174 524 100         RETVAL = (IV)removed;
175             OUTPUT:
176             RETVAL
177              
178             void
179             clear(self)
180             SV *self
181             PREINIT:
182 1 50         EXTRACT(self);
    50          
    50          
183             CODE:
184 1           rdx_rwlock_wrlock(h);
185 1           rdx_clear_locked(h);
186 1           __atomic_fetch_add(&h->hdr->stat_ops, 1, __ATOMIC_RELAXED);
187 1           rdx_rwlock_wrunlock(h);
188              
189             UV
190             count(self)
191             SV *self
192             PREINIT:
193 26 50         EXTRACT(self);
    50          
    50          
194             CODE:
195 26           rdx_rwlock_rdlock(h);
196 26           RETVAL = (UV)h->hdr->keys;
197 26           rdx_rwlock_rdunlock(h);
198             OUTPUT:
199             RETVAL
200              
201             SV *
202             stats(self)
203             SV *self
204             PREINIT:
205 2 50         EXTRACT(self);
    50          
    50          
206             CODE:
207             {
208             uint64_t keys, ops;
209             uint32_t node_used, node_cap, arena_used, arena_cap;
210             /* Snapshot under the lock; do all (croak-capable) Perl allocation after
211             releasing it -- so an OOM in newHV/newSV* can never strand the lock. */
212 2           rdx_rwlock_rdlock(h);
213 2           keys = h->hdr->keys;
214 2           node_used = h->hdr->node_used;
215 2           node_cap = h->hdr->node_cap;
216 2           arena_used = h->hdr->arena_used;
217 2           arena_cap = h->hdr->arena_cap;
218 2           ops = h->hdr->stat_ops;
219 2           rdx_rwlock_rdunlock(h);
220              
221 2           HV *hv = newHV();
222 2           hv_stores(hv, "keys", newSVuv((UV)keys));
223 2           hv_stores(hv, "nodes_used", newSVuv((UV)node_used));
224 2           hv_stores(hv, "nodes_capacity", newSVuv((UV)node_cap));
225 2           hv_stores(hv, "arena_used", newSVuv((UV)arena_used));
226 2           hv_stores(hv, "arena_capacity", newSVuv((UV)arena_cap));
227 2           hv_stores(hv, "ops", newSVuv((UV)ops));
228 2           hv_stores(hv, "mmap_size", newSVuv((UV)h->mmap_size));
229 2           RETVAL = newRV_noinc((SV *)hv);
230             }
231             OUTPUT:
232             RETVAL
233              
234             SV *
235             path(self)
236             SV *self
237             PREINIT:
238 3 50         EXTRACT(self);
    50          
    50          
239             CODE:
240 3 100         RETVAL = h->path ? newSVpv(h->path, 0) : &PL_sv_undef;
241             OUTPUT:
242             RETVAL
243              
244             int
245             memfd(self)
246             SV *self
247             PREINIT:
248 3 50         EXTRACT(self);
    50          
    50          
249             CODE:
250 3 50         RETVAL = h->backing_fd;
251             OUTPUT:
252             RETVAL
253              
254             void
255             sync(self)
256             SV *self
257             PREINIT:
258 2 50         EXTRACT(self);
    50          
    50          
259             CODE:
260 2 50         if (rdx_msync(h) != 0) croak("sync: %s", strerror(errno));
261              
262             void
263             unlink(self, ...)
264             SV *self
265             CODE:
266 3 100         if (sv_isobject(self) && sv_derived_from(self, "Data::RadixTree::Shared")) {
    50          
267 1           RdxHandle *h = INT2PTR(RdxHandle*, SvIV(SvRV(self)));
268 1 50         if (h && h->path) unlink(h->path);
    50          
269 1 50         } else if (items >= 2 && SvOK(ST(1))) {
    50          
270 1           unlink(SvPV_nolen(ST(1)));
271             }