File Coverage

xs/ss.xs
Criterion Covered Total %
statement 302 349 86.5
branch 282 626 45.0
condition n/a
subroutine n/a
pod n/a
total 584 975 59.9


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