File Coverage

xs/ss.xs
Criterion Covered Total %
statement 310 359 86.3
branch 294 656 44.8
condition n/a
subroutine n/a
pod n/a
total 604 1015 59.5


line stmt bran cond sub pod time code
1             MODULE = Data::HashMap::Shared PACKAGE = Data::HashMap::Shared::SS
2             PROTOTYPES: DISABLE
3              
4             SV*
5             new(char* class, SV* path_sv, UV max_entries, UV lru_max = 0, UV ttl_default = 0, UV lru_skip = 0)
6             CODE:
7 52 100         char errbuf[SHM_ERR_BUFLEN]; const char* path = SvOK(path_sv) ? SvPV_nolen(path_sv) : NULL; ShmHandle* map = shm_ss_create(path, (uint32_t)max_entries, (uint32_t)lru_max, (uint32_t)ttl_default, (uint32_t)lru_skip, errbuf);
8 52 100         if (!map) croak("HashMap::Shared::SS: %s", errbuf[0] ? errbuf : "unknown error");
    50          
9 49           RETVAL = sv_setref_pv(newSV(0), class, (void*)map);
10             OUTPUT:
11             RETVAL
12              
13             SV*
14             new_sharded(char* class, char* path_prefix, UV num_shards, UV max_entries, UV lru_max = 0, UV ttl_default = 0, UV lru_skip = 0)
15             CODE:
16 5           char errbuf[SHM_ERR_BUFLEN]; ShmHandle* map = shm_ss_create_sharded(path_prefix, (uint32_t)num_shards, (uint32_t)max_entries, (uint32_t)lru_max, (uint32_t)ttl_default, (uint32_t)lru_skip, errbuf);
17 5 50         if (!map) croak("HashMap::Shared::SS: %s", errbuf[0] ? errbuf : "unknown error");
    0          
18 5           RETVAL = sv_setref_pv(newSV(0), class, (void*)map);
19             OUTPUT:
20             RETVAL
21              
22              
23             SV*
24             new_memfd(char* class, SV* name_sv, UV max_entries, UV lru_max = 0, UV ttl_default = 0, UV lru_skip = 0)
25             CODE:
26             char errbuf[SHM_ERR_BUFLEN];
27 1 50         const char* name = SvOK(name_sv) ? SvPV_nolen(name_sv) : NULL;
28 1           ShmHandle* map = shm_ss_create_memfd(name, (uint32_t)max_entries, (uint32_t)lru_max, (uint32_t)ttl_default, (uint32_t)lru_skip, errbuf);
29 1 50         if (!map) croak("Data::HashMap::Shared::SS: %s", errbuf[0] ? errbuf : "unknown error");
    0          
30 1           RETVAL = sv_setref_pv(newSV(0), class, (void*)map);
31             OUTPUT:
32             RETVAL
33              
34             SV*
35             new_from_fd(char* class, int fd)
36             CODE:
37             char errbuf[SHM_ERR_BUFLEN];
38 1           ShmHandle* map = shm_ss_open_fd(fd, errbuf);
39 1 50         if (!map) croak("Data::HashMap::Shared::SS: %s", errbuf[0] ? errbuf : "unknown error");
    0          
40 1           RETVAL = sv_setref_pv(newSV(0), class, (void*)map);
41             OUTPUT:
42             RETVAL
43              
44             IV
45             memfd(SV* self_sv)
46             CODE:
47 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
48 1 50         RETVAL = h->backing_fd;
49             OUTPUT:
50             RETVAL
51              
52              
53             void
54             sync(SV* self_sv)
55             CODE:
56 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
57 0 0         if (shm_msync(h) != 0) croak("Data::HashMap::Shared::SS sync: %s", strerror(errno));
58              
59             void
60             DESTROY(SV* self_sv)
61             CODE:
62 56 50         if (!SvROK(self_sv)) return;
63 56           ShmHandle* h = INT2PTR(ShmHandle*, SvIV(SvRV(self_sv)));
64 56 50         if (!h) return;
65 56           sv_setiv(SvRV(self_sv), 0);
66 56           shm_close_map(h);
67              
68             bool
69             put(SV* self_sv, SV* key_sv, SV* value)
70             CODE:
71 3081 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
72 3081 50         EXTRACT_STR_KEY(key_sv);
73 3081 50         EXTRACT_STR_VAL(value);
74 3081 100         RETVAL = shm_ss_put(h, _kstr, (uint32_t)_klen, _kutf8, _vstr, (uint32_t)_vlen, _vutf8);
75             OUTPUT:
76             RETVAL
77              
78             UV
79             set_multi(SV* self_sv, ...)
80             CODE:
81 3 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
82 3 50         if ((items - 1) % 2 != 0) croak("set_multi requires even number of arguments (key, value pairs)");
83 3           uint32_t count = 0;
84 3 100         if (h->shard_handles) {
85 4 100         for (int i = 1; i < items; i += 2) {
86 3           STRLEN _kl; const char *_ks = SvPV(ST(i), _kl);
87 3           bool _ku = SvUTF8(ST(i)) ? 1 : 0;
88 3           STRLEN _vl; const char *_vs = SvPV(ST(i+1), _vl);
89 3           bool _vu = SvUTF8(ST(i+1)) ? 1 : 0;
90 3           count += shm_ss_put(h, _ks, (uint32_t)_kl, _ku, _vs, (uint32_t)_vl, _vu);
91             }
92             } else {
93 2           ShmHeader *hdr = h->hdr;
94 2           shm_rwlock_wrlock(hdr);
95 2           shm_seqlock_write_begin(&hdr->seq);
96 8 100         for (int i = 1; i < items; i += 2) {
97 6           STRLEN _kl; const char *_ks = SvPV(ST(i), _kl);
98 6           bool _ku = SvUTF8(ST(i)) ? 1 : 0;
99 6 50         if (_kl > SHM_MAX_STR_LEN) { shm_seqlock_write_end(&hdr->seq); shm_rwlock_wrunlock(hdr); croak("key too long"); }
100 6           STRLEN _vl; const char *_vs = SvPV(ST(i+1), _vl);
101 6           bool _vu = SvUTF8(ST(i+1)) ? 1 : 0;
102 6 50         if (_vl > SHM_MAX_STR_LEN) { shm_seqlock_write_end(&hdr->seq); shm_rwlock_wrunlock(hdr); croak("value too long"); }
103 6           count += shm_ss_put_inner(h, _ks, (uint32_t)_kl, _ku, _vs, (uint32_t)_vl, _vu, SHM_TTL_USE_DEFAULT);
104             }
105 2           shm_seqlock_write_end(&hdr->seq);
106 2           shm_rwlock_wrunlock(hdr);
107             }
108 3 50         RETVAL = count;
109             OUTPUT:
110             RETVAL
111              
112             void
113             get_multi(SV* self_sv, ...)
114             PPCODE:
115 3 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
116 3           int nkeys = items - 1;
117 3 50         if (nkeys == 0) XSRETURN_EMPTY;
118 3 50         EXTEND(SP, nkeys);
    50          
119 3 100         if (h->shard_handles) {
120 5 100         for (int i = 0; i < nkeys; i++) {
121 4           STRLEN _kl; const char *_ks = SvPV(ST(i + 1), _kl);
122 4           bool _ku = SvUTF8(ST(i + 1)) ? 1 : 0;
123             const char *out_s; uint32_t out_l; bool out_u;
124 4 100         if (shm_ss_get(h, _ks, (uint32_t)_kl, _ku, &out_s, &out_l, &out_u)) {
125 3           SV *sv = newSVpvn(out_s, out_l);
126 3 50         if (out_u) SvUTF8_on(sv);
127 3           mPUSHs(sv);
128 1           } else PUSHs(&PL_sv_undef);
129             }
130             } else {
131 2           ShmHeader *hdr = h->hdr;
132 2           ShmNodeSS *nodes = (ShmNodeSS *)h->nodes;
133 2           uint8_t *states = h->states;
134 2           char *arena = h->arena;
135 2 50         uint32_t now = h->expires_at ? shm_now() : 0;
136 2           RDLOCK_GUARD(hdr);
137 2           uint32_t mask = hdr->table_cap - 1;
138 11 100         for (int i = 0; i < nkeys; i++) {
139 9           STRLEN _kl; const char *_ks = SvPV(ST(i + 1), _kl);
140 9           bool _ku = SvUTF8(ST(i + 1)) ? 1 : 0;
141 9           uint32_t hash = shm_hash_string(_ks, (uint32_t)_kl);
142 9           uint32_t pos = hash & mask;
143 9           uint8_t tag = SHM_MAKE_TAG(hash);
144 9           int found = 0;
145 9           uint32_t vidx = 0;
146 13 50         for (uint32_t j = 0; j <= mask; j++) {
147 13           uint32_t idx = (pos + j) & mask;
148 13           uint8_t st = states[idx];
149 13 100         if (st == SHM_EMPTY) break;
150 11 100         if (st != tag) continue;
151 7 50         if (shm_ss__key_eq_str(&nodes[idx], arena, _ks, (uint32_t)_kl, _ku)) {
152 7 50         if (h->expires_at && h->expires_at[idx] && now >= h->expires_at[idx]) break;
    0          
    0          
153 7           vidx = idx; found = 1; break;
154             }
155             }
156 9 100         if (found) {
157             char _vib[SHM_INLINE_MAX]; uint32_t vl;
158 7           const char *vp = shm_str_ptr(nodes[vidx].val_off, nodes[vidx].val_len, arena, _vib, &vl);
159 7           SV *sv = newSVpvn(vp, vl);
160 7 50         if (SHM_UNPACK_UTF8(nodes[vidx].val_len)) SvUTF8_on(sv);
161 7           mPUSHs(sv);
162 2           } else PUSHs(&PL_sv_undef);
163             /* Prefetch next key's probe start */
164 9 100         if (i + 1 < nkeys) {
165 7           STRLEN nkl; const char *nks = SvPV(ST(i + 2), nkl);
166 7           uint32_t nh = shm_hash_string(nks, (uint32_t)nkl);
167 7           __builtin_prefetch(&states[nh & mask], 0, 0);
168             }
169             }
170             }
171              
172             SV*
173             stats(SV* self_sv)
174             CODE:
175 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
176 1           HV *hv = newHV();
177 1           hv_store(hv, "size", 4, newSVuv(shm_ss_size(h)), 0);
178 1           hv_store(hv, "capacity", 8, newSVuv(shm_ss_capacity(h)), 0);
179 1           hv_store(hv, "max_entries", 11, newSVuv(shm_ss_max_entries(h)), 0);
180 1           hv_store(hv, "tombstones", 10, newSVuv(shm_ss_tombstones(h)), 0);
181 1           hv_store(hv, "mmap_size", 9, newSVuv(shm_ss_mmap_size(h)), 0);
182 1           hv_store(hv, "arena_used", 10, newSVuv(shm_ss_arena_used(h)), 0);
183 1           hv_store(hv, "arena_cap", 9, newSVuv(shm_ss_arena_cap(h)), 0);
184 1           hv_store(hv, "evictions", 9, newSVuv(shm_ss_stat_evictions(h)), 0);
185 1           hv_store(hv, "expired", 7, newSVuv(shm_ss_stat_expired(h)), 0);
186 1           hv_store(hv, "recoveries", 10, newSVuv(shm_ss_stat_recoveries(h)), 0);
187 1           hv_store(hv, "max_size", 8, newSVuv(shm_ss_max_size(h)), 0);
188 1           hv_store(hv, "ttl", 3, newSVuv(shm_ss_ttl(h)), 0);
189 1           RETVAL = newRV_noinc((SV*)hv);
190             OUTPUT:
191             RETVAL
192              
193             bool
194             persist(SV* self_sv, SV* key_sv)
195             CODE:
196 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
197 0 0         EXTRACT_STR_KEY(key_sv);
198 0 0         RETVAL = shm_ss_persist(h, _kstr, (uint32_t)_klen, _kutf8);
199             OUTPUT:
200             RETVAL
201              
202             bool
203             set_ttl(SV* self_sv, SV* key_sv, UV ttl_sec)
204             CODE:
205 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
206 0 0         EXTRACT_STR_KEY(key_sv);
207 0 0         RETVAL = shm_ss_set_ttl(h, _kstr, (uint32_t)_klen, _kutf8, (uint32_t)ttl_sec);
208             OUTPUT:
209             RETVAL
210              
211             bool
212             put_ttl(SV* self_sv, SV* key_sv, SV* value, UV ttl_sec)
213             CODE:
214 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
215 1 50         EXTRACT_STR_KEY(key_sv);
216 1 50         EXTRACT_STR_VAL(value);
217 1 50         REQUIRE_TTL(h);
    50          
218 1 50         RETVAL = shm_ss_put_ttl(h, _kstr, (uint32_t)_klen, _kutf8, _vstr, (uint32_t)_vlen, _vutf8, (uint32_t)ttl_sec);
219             OUTPUT:
220             RETVAL
221              
222             UV
223             max_size(SV* self_sv)
224             CODE:
225 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
226 0 0         RETVAL = (UV)shm_ss_max_size(h);
227             OUTPUT:
228             RETVAL
229              
230             UV
231             ttl(SV* self_sv)
232             CODE:
233 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
234 0 0         RETVAL = (UV)shm_ss_ttl(h);
235             OUTPUT:
236             RETVAL
237              
238             SV*
239             get(SV* self_sv, SV* key_sv)
240             CODE:
241 2546 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
242 2546 50         EXTRACT_STR_KEY(key_sv);
243             const char* val; uint32_t val_len; bool val_utf8;
244 2546 100         if (!shm_ss_get(h, _kstr, (uint32_t)_klen, _kutf8, &val, &val_len, &val_utf8))
245 5           XSRETURN_UNDEF;
246 2541           RETVAL = newSVpvn(val, val_len);
247 2541 100         if (val_utf8) SvUTF8_on(RETVAL);
248             OUTPUT:
249             RETVAL
250              
251             bool
252             remove(SV* self_sv, SV* key_sv)
253             CODE:
254 5 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
255 5 50         EXTRACT_STR_KEY(key_sv);
256 5 50         RETVAL = shm_ss_remove(h, _kstr, (uint32_t)_klen, _kutf8);
257             OUTPUT:
258             RETVAL
259              
260             bool
261             exists(SV* self_sv, SV* key_sv)
262             CODE:
263 5 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
264 5 50         EXTRACT_STR_KEY(key_sv);
265 5 50         RETVAL = shm_ss_exists(h, _kstr, (uint32_t)_klen, _kutf8);
266             OUTPUT:
267             RETVAL
268              
269             UV
270             size(SV* self_sv)
271             CODE:
272 15 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
273 15 50         RETVAL = (UV)shm_ss_size(h);
274             OUTPUT:
275             RETVAL
276              
277             UV
278             max_entries(SV* self_sv)
279             CODE:
280 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
281 0 0         RETVAL = (UV)shm_ss_max_entries(h);
282             OUTPUT:
283             RETVAL
284              
285             void
286             keys(SV* self_sv)
287             PPCODE:
288 3 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
289 3 100         uint32_t ns = h->shard_handles ? h->num_shards : 1;
290 9 100         for (uint32_t si = 0; si < ns; si++) {
291 6 100         ShmHandle *sh = h->shard_handles ? h->shard_handles[si] : h;
292 6           ShmHeader *hdr = sh->hdr;
293 6           ShmNodeSS *nodes = (ShmNodeSS *)sh->nodes;
294 6 50         uint32_t now = sh->expires_at ? shm_now() : 0;
295 6           RDLOCK_GUARD(hdr);
296 6 50         EXTEND(SP, hdr->size);
297 102 100         for (uint32_t i = 0; i < hdr->table_cap; i++) {
298 96 100         if (SHM_IS_LIVE(sh->states[i]) && !SHM_IS_EXPIRED(sh, i, now)) {
    50          
    0          
    0          
299             char _ib[SHM_INLINE_MAX]; uint32_t klen;
300 34           const char *kp = shm_str_ptr(nodes[i].key_off, nodes[i].key_len, sh->arena, _ib, &klen);
301 34           SV* sv = newSVpvn(kp, klen);
302 34 100         if (SHM_UNPACK_UTF8(nodes[i].key_len)) SvUTF8_on(sv);
303 34 50         mXPUSHs(sv);
304             }
305             }
306             }
307              
308             void
309             values(SV* self_sv)
310             PPCODE:
311 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
312 2 100         uint32_t ns = h->shard_handles ? h->num_shards : 1;
313 7 100         for (uint32_t si = 0; si < ns; si++) {
314 5 100         ShmHandle *sh = h->shard_handles ? h->shard_handles[si] : h;
315 5           ShmHeader *hdr = sh->hdr;
316 5           ShmNodeSS *nodes = (ShmNodeSS *)sh->nodes;
317 5 50         uint32_t now = sh->expires_at ? shm_now() : 0;
318 5           RDLOCK_GUARD(hdr);
319 5 50         EXTEND(SP, hdr->size);
320 85 100         for (uint32_t i = 0; i < hdr->table_cap; i++) {
321 80 100         if (SHM_IS_LIVE(sh->states[i]) && !SHM_IS_EXPIRED(sh, i, now)) {
    50          
    0          
    0          
322             char _ib[SHM_INLINE_MAX]; uint32_t vlen;
323 33           const char *vp = shm_str_ptr(nodes[i].val_off, nodes[i].val_len, sh->arena, _ib, &vlen);
324 33           SV* sv = newSVpvn(vp, vlen);
325 33 50         if (SHM_UNPACK_UTF8(nodes[i].val_len)) SvUTF8_on(sv);
326 33 50         mXPUSHs(sv);
327             }
328             }
329             }
330              
331             void
332             items(SV* self_sv)
333             PPCODE:
334 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
335 1 50         uint32_t ns = h->shard_handles ? h->num_shards : 1;
336 2 100         for (uint32_t si = 0; si < ns; si++) {
337 1 50         ShmHandle *sh = h->shard_handles ? h->shard_handles[si] : h;
338 1           ShmHeader *hdr = sh->hdr;
339 1           ShmNodeSS *nodes = (ShmNodeSS *)sh->nodes;
340 1 50         uint32_t now = sh->expires_at ? shm_now() : 0;
341 1           RDLOCK_GUARD(hdr);
342 1 50         EXTEND(SP, hdr->size * 2);
343 17 100         for (uint32_t i = 0; i < hdr->table_cap; i++) {
344 16 100         if (SHM_IS_LIVE(sh->states[i]) && !SHM_IS_EXPIRED(sh, i, now)) {
    50          
    0          
    0          
345             char _kib[SHM_INLINE_MAX]; uint32_t klen;
346 3           const char *kp = shm_str_ptr(nodes[i].key_off, nodes[i].key_len, sh->arena, _kib, &klen);
347 3           SV* ksv = newSVpvn(kp, klen);
348 3 50         if (SHM_UNPACK_UTF8(nodes[i].key_len)) SvUTF8_on(ksv);
349 3 50         mXPUSHs(ksv);
350             char _vib[SHM_INLINE_MAX]; uint32_t vlen;
351 3           const char *vp = shm_str_ptr(nodes[i].val_off, nodes[i].val_len, sh->arena, _vib, &vlen);
352 3           SV* vsv = newSVpvn(vp, vlen);
353 3 50         if (SHM_UNPACK_UTF8(nodes[i].val_len)) SvUTF8_on(vsv);
354 3 50         mXPUSHs(vsv);
355             }
356             }
357             }
358            
359              
360             void
361             each(SV* self_sv)
362             PPCODE:
363 3 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
364             const char *out_key, *out_val;
365             uint32_t out_klen, out_vlen;
366             bool out_kutf8, out_vutf8;
367 3 100         if (shm_ss_each(h, &out_key, &out_klen, &out_kutf8, &out_val, &out_vlen, &out_vutf8)) {
368 2 50         EXTEND(SP, 2);
369 2           SV* ksv = newSVpvn(out_key, out_klen);
370 2 50         if (out_kutf8) SvUTF8_on(ksv);
371 2 50         mXPUSHs(ksv);
372 2           SV* vsv = newSVpvn(out_val, out_vlen);
373 2 50         if (out_vutf8) SvUTF8_on(vsv);
374 2 50         mXPUSHs(vsv);
375 2           XSRETURN(2);
376             }
377 1           shm_ss_flush_deferred(h);
378 1           XSRETURN_EMPTY;
379              
380             void
381             iter_reset(SV* self_sv)
382             CODE:
383 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
384 0           shm_ss_iter_reset(h);
385 0           shm_ss_flush_deferred(h);
386              
387             void
388             clear(SV* self_sv)
389             CODE:
390 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
391 1           shm_ss_clear(h);
392              
393             SV*
394             to_hash(SV* self_sv)
395             CODE:
396 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
397 2           HV* hv = newHV();
398 2 100         uint32_t ns = h->shard_handles ? h->num_shards : 1;
399 7 100         for (uint32_t si = 0; si < ns; si++) {
400 5 100         ShmHandle *sh = h->shard_handles ? h->shard_handles[si] : h;
401 5           ShmHeader *hdr = sh->hdr;
402 5           ShmNodeSS *nodes = (ShmNodeSS *)sh->nodes;
403 5 50         uint32_t now = sh->expires_at ? shm_now() : 0;
404 5           RDLOCK_GUARD(hdr);
405 85 100         for (uint32_t i = 0; i < hdr->table_cap; i++) {
406 80 100         if (SHM_IS_LIVE(sh->states[i]) && !SHM_IS_EXPIRED(sh, i, now)) {
    50          
    0          
    0          
407             char _kib[SHM_INLINE_MAX]; uint32_t klen;
408 32           const char *kp = shm_str_ptr(nodes[i].key_off, nodes[i].key_len, sh->arena, _kib, &klen);
409 32           bool kutf8 = SHM_UNPACK_UTF8(nodes[i].key_len);
410             char _vib[SHM_INLINE_MAX]; uint32_t vlen;
411 32           const char *vp = shm_str_ptr(nodes[i].val_off, nodes[i].val_len, sh->arena, _vib, &vlen);
412 32           SV* val = newSVpvn(vp, vlen);
413 32 50         if (SHM_UNPACK_UTF8(nodes[i].val_len)) SvUTF8_on(val);
414 32 50         if (!hv_store(hv, kp,
    50          
415 0           kutf8 ? -(I32)klen : (I32)klen, val, 0)) SvREFCNT_dec(val);
416             }
417             }
418             }
419 2           RETVAL = newRV_noinc((SV*)hv);
420             OUTPUT:
421             RETVAL
422              
423             SV*
424             get_or_set(SV* self_sv, SV* key_sv, SV* default_sv)
425             CODE:
426 8 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
427 8 50         EXTRACT_STR_KEY(key_sv);
428             const char *out_str; uint32_t out_len; bool out_utf8;
429 8 50         EXTRACT_STR_VAL(default_sv);
430 8           int rc = shm_ss_get_or_set(h, _kstr, (uint32_t)_klen, _kutf8, _vstr, (uint32_t)_vlen, _vutf8, &out_str, &out_len, &out_utf8);
431 8 50         if (!rc) XSRETURN_UNDEF;
432 8           RETVAL = newSVpvn(out_str, out_len);
433 8 50         if (out_utf8) SvUTF8_on(RETVAL);
434             OUTPUT:
435             RETVAL
436              
437             SV*
438             ttl_remaining(SV* self_sv, SV* key_sv)
439             CODE:
440 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
441 2 50         EXTRACT_STR_KEY(key_sv);
442 2           int64_t remaining = shm_ss_ttl_remaining(h, _kstr, (uint32_t)_klen, _kutf8);
443 2 100         if (remaining < 0) XSRETURN_UNDEF;
444 1           RETVAL = newSViv(remaining);
445             OUTPUT:
446             RETVAL
447              
448             UV
449             capacity(SV* self_sv)
450             CODE:
451 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
452 2 50         RETVAL = (UV)shm_ss_capacity(h);
453             OUTPUT:
454             RETVAL
455              
456             UV
457             tombstones(SV* self_sv)
458             CODE:
459 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
460 0 0         RETVAL = (UV)shm_ss_tombstones(h);
461             OUTPUT:
462             RETVAL
463              
464             SV*
465             cursor(SV* self_sv)
466             CODE:
467 4 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
468 4           ShmCursor* c = shm_cursor_create(h);
469 4 50         if (!c) croak("Failed to allocate cursor");
470 4           RETVAL = sv_setref_pv(newSV(0), "Data::HashMap::Shared::SS::Cursor", (void*)c);
471             OUTPUT:
472             RETVAL
473              
474             SV*
475             take(SV* self_sv, SV* key_sv)
476             CODE:
477 6 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
478 6 50         EXTRACT_STR_KEY(key_sv);
479             const char *out_str; uint32_t out_len; bool out_utf8;
480 6 100         if (!shm_ss_take(h, _kstr, (uint32_t)_klen, _kutf8, &out_str, &out_len, &out_utf8)) XSRETURN_UNDEF;
481 5           RETVAL = newSVpvn(out_str, out_len);
482 5 100         if (out_utf8) SvUTF8_on(RETVAL);
483             OUTPUT:
484             RETVAL
485              
486             void
487             pop(SV* self_sv)
488             PPCODE:
489 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
490             const char *out_key; uint32_t out_klen; bool out_kutf8;
491             const char *out_val; uint32_t out_vlen; bool out_vutf8;
492 2 50         if (!shm_ss_pop(h, &out_key, &out_klen, &out_kutf8, &out_val, &out_vlen, &out_vutf8)) XSRETURN_EMPTY;
493 2 50         EXTEND(SP, 2);
494 2           SV *ksv = newSVpvn(out_key, out_klen);
495 2 50         if (out_kutf8) SvUTF8_on(ksv);
496 2           mPUSHs(ksv);
497 2           SV *vsv = newSVpvn(out_val, out_vlen);
498 2 50         if (out_vutf8) SvUTF8_on(vsv);
499 2           mPUSHs(vsv);
500              
501             void
502             shift(SV* self_sv)
503             PPCODE:
504 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
505             const char *out_key; uint32_t out_klen; bool out_kutf8;
506             const char *out_val; uint32_t out_vlen; bool out_vutf8;
507 1 50         if (!shm_ss_shift(h, &out_key, &out_klen, &out_kutf8, &out_val, &out_vlen, &out_vutf8)) XSRETURN_EMPTY;
508 1 50         EXTEND(SP, 2);
509 1           SV *ksv = newSVpvn(out_key, out_klen);
510 1 50         if (out_kutf8) SvUTF8_on(ksv);
511 1           mPUSHs(ksv);
512 1           SV *vsv = newSVpvn(out_val, out_vlen);
513 1 50         if (out_vutf8) SvUTF8_on(vsv);
514 1           mPUSHs(vsv);
515              
516             void
517             drain(SV* self_sv, UV limit)
518             PPCODE:
519 3 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
520 3 50         if (limit == 0) XSRETURN_EMPTY;
521             shm_ss_drain_entry *entries;
522 3 50         Newxz(entries, limit, shm_ss_drain_entry);
523            
524 3           SAVEFREEPV(entries);
525 3           char *buf = NULL; uint32_t buf_cap = 0;
526 3           uint32_t n = shm_ss_drain(h, (uint32_t)limit, entries, &buf, &buf_cap);
527            
528 3 50         EXTEND(SP, n * 2);
529 12 100         for (uint32_t i = 0; i < n; i++) {
530 9           SV *ksv = newSVpvn(buf + entries[i].key_off, entries[i].key_len);
531 9 50         if (entries[i].key_utf8) SvUTF8_on(ksv);
532 9           mPUSHs(ksv);
533 9           SV *vsv = newSVpvn(buf + entries[i].val_off, entries[i].val_len);
534 9 50         if (entries[i].val_utf8) SvUTF8_on(vsv);
535 9           mPUSHs(vsv);
536             }
537 3 50         if (buf) free(buf);
538            
539              
540             UV
541             flush_expired(SV* self_sv)
542             CODE:
543 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
544 1 50         RETVAL = (UV)shm_ss_flush_expired(h);
545             OUTPUT:
546             RETVAL
547              
548             void
549             flush_expired_partial(SV* self_sv, UV limit)
550             PPCODE:
551 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
552 0           int done = 0;
553 0           uint32_t flushed = shm_ss_flush_expired_partial(h, (uint32_t)limit, &done);
554 0 0         EXTEND(SP, 2);
555 0           mPUSHu(flushed);
556 0           mPUSHi(done);
557              
558             UV
559             mmap_size(SV* self_sv)
560             CODE:
561 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
562 1           RETVAL = (UV)shm_ss_mmap_size(h);
563             OUTPUT:
564             RETVAL
565              
566             bool
567             touch(SV* self_sv, SV* key_sv)
568             CODE:
569 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
570 2 50         EXTRACT_STR_KEY(key_sv);
571 2 100         RETVAL = shm_ss_touch(h, _kstr, (uint32_t)_klen, _kutf8);
572             OUTPUT:
573             RETVAL
574              
575             bool
576             reserve(SV* self_sv, UV target)
577             CODE:
578 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
579 1 50         RETVAL = shm_ss_reserve(h, (uint32_t)target);
580             OUTPUT:
581             RETVAL
582              
583             UV
584             stat_evictions(SV* self_sv)
585             CODE:
586 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
587 2           RETVAL = (UV)shm_ss_stat_evictions(h);
588             OUTPUT:
589             RETVAL
590              
591             UV
592             stat_expired(SV* self_sv)
593             CODE:
594 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
595 0           RETVAL = (UV)shm_ss_stat_expired(h);
596             OUTPUT:
597             RETVAL
598              
599             UV
600             stat_recoveries(SV* self_sv)
601             CODE:
602 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
603 0 0         RETVAL = (UV)shm_ss_stat_recoveries(h);
604             OUTPUT:
605             RETVAL
606              
607             UV
608             arena_used(SV* self_sv)
609             CODE:
610 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
611 2           RETVAL = (UV)shm_ss_arena_used(h);
612             OUTPUT:
613             RETVAL
614              
615             UV
616             arena_cap(SV* self_sv)
617             CODE:
618 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
619 1           RETVAL = (UV)shm_ss_arena_cap(h);
620             OUTPUT:
621             RETVAL
622              
623             bool
624             add(SV* self_sv, SV* key_sv, SV* val_sv)
625             CODE:
626 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
627 0 0         EXTRACT_STR_KEY(key_sv);
628 0 0         EXTRACT_STR_VAL(val_sv);
629 0 0         RETVAL = shm_ss_add(h, _kstr, (uint32_t)_klen, _kutf8, _vstr, (uint32_t)_vlen, _vutf8);
630             OUTPUT:
631             RETVAL
632              
633             bool
634             update(SV* self_sv, SV* key_sv, SV* val_sv)
635             CODE:
636 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
637 0 0         EXTRACT_STR_KEY(key_sv);
638 0 0         EXTRACT_STR_VAL(val_sv);
639 0 0         RETVAL = shm_ss_update(h, _kstr, (uint32_t)_klen, _kutf8, _vstr, (uint32_t)_vlen, _vutf8);
640             OUTPUT:
641             RETVAL
642              
643             SV*
644             swap(SV* self_sv, SV* key_sv, SV* val_sv)
645             CODE:
646 4 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
647 4 50         EXTRACT_STR_KEY(key_sv);
648 4 50         EXTRACT_STR_VAL(val_sv);
649             const char *out_s; uint32_t out_l; bool out_u;
650 4           int rc = shm_ss_swap(h, _kstr, (uint32_t)_klen, _kutf8, _vstr, (uint32_t)_vlen, _vutf8, &out_s, &out_l, &out_u);
651 4 100         if (rc != 1) XSRETURN_UNDEF;
652 2           RETVAL = newSVpvn(out_s, out_l);
653 2 50         if (out_u) SvUTF8_on(RETVAL);
654             OUTPUT:
655             RETVAL
656              
657             SV*
658             path(SV* self_sv)
659             CODE:
660 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
661 2 100         RETVAL = h->path ? newSVpv(h->path, 0) : &PL_sv_undef;
662             OUTPUT:
663             RETVAL
664              
665             bool
666             unlink(SV* self_or_class, ...)
667             CODE:
668             const char *p;
669 0 0         if (SvROK(self_or_class) && SvOBJECT(SvRV(self_or_class))) {
    0          
670 0           ShmHandle* h = INT2PTR(ShmHandle*, SvIV(SvRV(self_or_class)));
671 0 0         if (!h) croak("Attempted to use a destroyed Data::HashMap::Shared::SS object");
672 0           p = h->path;
673             } else {
674 0 0         if (items < 2) croak("Usage: Data::HashMap::Shared::SS->unlink($path)");
675 0           p = SvPV_nolen(ST(1));
676             }
677 0 0         RETVAL = (SvROK(self_or_class) && SvOBJECT(SvRV(self_or_class))) ?
    0          
678 0 0         shm_unlink_sharded(INT2PTR(ShmHandle*, SvIV(SvRV(self_or_class)))) :
679 0           shm_unlink_path(p);
680             OUTPUT:
681             RETVAL
682              
683             MODULE = Data::HashMap::Shared PACKAGE = Data::HashMap::Shared::SS::Cursor
684             PROTOTYPES: DISABLE
685              
686             void
687             DESTROY(SV* self_sv)
688             CODE:
689 4 50         if (!SvROK(self_sv)) return;
690 4           ShmCursor* c = INT2PTR(ShmCursor*, SvIV(SvRV(self_sv)));
691 4 50         if (!c) return;
692 4           ShmHandle* h = c->current;
693 4           shm_cursor_destroy(c);
694 4 50         if (h) shm_ss_flush_deferred(h);
695 4           sv_setiv(SvRV(self_sv), 0);
696              
697             void
698             next(SV* self_sv)
699             PPCODE:
700 29 50         EXTRACT_CURSOR("Data::HashMap::Shared::SS::Cursor", self_sv);
    50          
    50          
701             const char *out_key, *out_val;
702             uint32_t out_klen, out_vlen;
703             bool out_kutf8, out_vutf8;
704 29 100         if (shm_ss_cursor_next(c, &out_key, &out_klen, &out_kutf8, &out_val, &out_vlen, &out_vutf8)) {
705 27 50         EXTEND(SP, 2);
706 27           SV* ksv = newSVpvn(out_key, out_klen);
707 27 50         if (out_kutf8) SvUTF8_on(ksv);
708 27 50         mXPUSHs(ksv);
709 27           SV* vsv = newSVpvn(out_val, out_vlen);
710 27 50         if (out_vutf8) SvUTF8_on(vsv);
711 27 50         mXPUSHs(vsv);
712 27           XSRETURN(2);
713             }
714 2           XSRETURN_EMPTY;
715              
716             void
717             reset(SV* self_sv)
718             CODE:
719 0 0         EXTRACT_CURSOR("Data::HashMap::Shared::SS::Cursor", self_sv);
    0          
    0          
720 0           shm_ss_cursor_reset(c);
721              
722             bool
723             seek(SV* self_sv, SV* key_sv)
724             CODE:
725 3 50         EXTRACT_CURSOR("Data::HashMap::Shared::SS::Cursor", self_sv);
    50          
    50          
726 3 50         EXTRACT_STR_KEY(key_sv);
727 3 100         RETVAL = shm_ss_cursor_seek(c, _kstr, (uint32_t)_klen, _kutf8);
728             OUTPUT:
729             RETVAL
730