File Coverage

xs/ss.xs
Criterion Covered Total %
statement 353 408 86.5
branch 352 752 46.8
condition n/a
subroutine n/a
pod n/a
total 705 1160 60.7


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 61 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 61 100         if (!map) croak("HashMap::Shared::SS: %s", errbuf[0] ? errbuf : "unknown error");
    50          
9 58           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 65 50         if (!SvROK(self_sv)) return;
63 65           ShmHandle* h = INT2PTR(ShmHandle*, SvIV(SvRV(self_sv)));
64 65 50         if (!h) return;
65 65           sv_setiv(SvRV(self_sv), 0);
66 65           shm_close_map(h);
67              
68             bool
69             put(SV* self_sv, SV* key_sv, SV* value)
70             CODE:
71 8097 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
72 8097 50         EXTRACT_STR_KEY(key_sv);
73 8097 50         EXTRACT_STR_VAL(value);
74 8097 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             UV
113             remove_multi(SV* self_sv, ...)
114             CODE:
115 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
116 1           uint32_t count = 0;
117 1 50         if (h->shard_handles) {
118 0 0         for (int i = 1; i < items; i++) {
119 0           STRLEN _kl; const char *_ks = SvPV(ST(i), _kl);
120 0           bool _ku = SvUTF8(ST(i)) ? 1 : 0;
121 0 0         if (_kl > SHM_MAX_STR_LEN) croak("key too long (max 2GB)");
122 0           count += shm_ss_remove(h, _ks, (uint32_t)_kl, _ku);
123             }
124             } else {
125 1           ShmHeader *hdr = h->hdr;
126 1           shm_rwlock_wrlock(hdr);
127 1           shm_seqlock_write_begin(&hdr->seq);
128 4 100         for (int i = 1; i < items; i++) {
129 3           STRLEN _kl; const char *_ks = SvPV(ST(i), _kl);
130 3           bool _ku = SvUTF8(ST(i)) ? 1 : 0;
131 3 50         if (_kl > SHM_MAX_STR_LEN) { shm_seqlock_write_end(&hdr->seq); shm_rwlock_wrunlock(hdr); croak("key too long (max 2GB)"); }
132 3           count += shm_ss_remove_inner(h, _ks, (uint32_t)_kl, _ku);
133             }
134 1 50         if (count) shm_ss_maybe_shrink(h);
135 1           shm_seqlock_write_end(&hdr->seq);
136 1           shm_rwlock_wrunlock(hdr);
137             }
138 1 50         RETVAL = count;
139             OUTPUT:
140             RETVAL
141              
142             void
143             get_multi(SV* self_sv, ...)
144             PPCODE:
145 3 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
146 3           int nkeys = items - 1;
147 3 50         if (nkeys == 0) XSRETURN_EMPTY;
148 3 50         EXTEND(SP, nkeys);
    50          
149 3 100         if (h->shard_handles) {
150 5 100         for (int i = 0; i < nkeys; i++) {
151 4           STRLEN _kl; const char *_ks = SvPV(ST(i + 1), _kl);
152 4           bool _ku = SvUTF8(ST(i + 1)) ? 1 : 0;
153             const char *out_s; uint32_t out_l; bool out_u;
154 4 100         if (shm_ss_get(h, _ks, (uint32_t)_kl, _ku, &out_s, &out_l, &out_u)) {
155 3           SV *sv = newSVpvn(out_s, out_l);
156 3 50         if (out_u) SvUTF8_on(sv);
157 3           mPUSHs(sv);
158 1           } else PUSHs(&PL_sv_undef);
159             }
160             } else {
161 2           ShmHeader *hdr = h->hdr;
162 2           ShmNodeSS *nodes = (ShmNodeSS *)h->nodes;
163 2           uint8_t *states = h->states;
164 2           char *arena = h->arena;
165 2 50         uint32_t now = h->expires_at ? shm_now() : 0;
166 2           RDLOCK_GUARD(hdr);
167 2           uint32_t mask = hdr->table_cap - 1;
168 11 100         for (int i = 0; i < nkeys; i++) {
169 9           STRLEN _kl; const char *_ks = SvPV(ST(i + 1), _kl);
170 9           bool _ku = SvUTF8(ST(i + 1)) ? 1 : 0;
171 9           uint32_t hash = shm_hash_string(_ks, (uint32_t)_kl);
172 9           uint32_t pos = hash & mask;
173 9           uint8_t tag = SHM_MAKE_TAG(hash);
174 9           int found = 0;
175 9           uint32_t vidx = 0;
176 13 50         for (uint32_t j = 0; j <= mask; j++) {
177 13           uint32_t idx = (pos + j) & mask;
178 13           uint8_t st = states[idx];
179 13 100         if (st == SHM_EMPTY) break;
180 11 100         if (st != tag) continue;
181 7 50         if (shm_ss__key_eq_str(&nodes[idx], arena, _ks, (uint32_t)_kl, _ku)) {
182 7 50         if (h->expires_at && h->expires_at[idx] && now >= h->expires_at[idx]) break;
    0          
    0          
183 7           vidx = idx; found = 1; break;
184             }
185             }
186 9 100         if (found) {
187             char _vib[SHM_INLINE_MAX]; uint32_t vl;
188 7           const char *vp = shm_str_ptr(nodes[vidx].val_off, nodes[vidx].val_len, arena, _vib, &vl);
189 7           SV *sv = newSVpvn(vp, vl);
190 7 50         if (SHM_UNPACK_UTF8(nodes[vidx].val_len)) SvUTF8_on(sv);
191 7           mPUSHs(sv);
192 2           } else PUSHs(&PL_sv_undef);
193             /* Prefetch next key's probe start */
194 9 100         if (i + 1 < nkeys) {
195 7           STRLEN nkl; const char *nks = SvPV(ST(i + 2), nkl);
196 7           uint32_t nh = shm_hash_string(nks, (uint32_t)nkl);
197 7           __builtin_prefetch(&states[nh & mask], 0, 0);
198             }
199             }
200             }
201              
202             void
203             get_with_ttl(SV* self_sv, SV* key_sv)
204             PPCODE:
205 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
206 0 0         EXTRACT_STR_KEY(key_sv);
207             const char *out_s; uint32_t out_l; bool out_u;
208             int64_t out_ttl;
209 0 0         if (!shm_ss_get_with_ttl(h, _kstr, (uint32_t)_klen, _kutf8, &out_s, &out_l, &out_u, &out_ttl)) XSRETURN_EMPTY;
210 0 0         EXTEND(SP, 2);
211 0           SV *vsv = newSVpvn(out_s, out_l);
212 0 0         if (out_u) SvUTF8_on(vsv);
213 0           mPUSHs(vsv);
214 0 0         if (out_ttl < 0) PUSHs(&PL_sv_undef);
215 0           else mPUSHi(out_ttl);
216              
217             SV*
218             stats(SV* self_sv)
219             CODE:
220 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
221 1           HV *hv = newHV();
222 1           hv_store(hv, "size", 4, newSVuv(shm_ss_size(h)), 0);
223 1           hv_store(hv, "capacity", 8, newSVuv(shm_ss_capacity(h)), 0);
224 1           hv_store(hv, "max_entries", 11, newSVuv(shm_ss_max_entries(h)), 0);
225 1           hv_store(hv, "tombstones", 10, newSVuv(shm_ss_tombstones(h)), 0);
226 1           hv_store(hv, "mmap_size", 9, newSVuv(shm_ss_mmap_size(h)), 0);
227 1           hv_store(hv, "arena_used", 10, newSVuv(shm_ss_arena_used(h)), 0);
228 1           hv_store(hv, "arena_cap", 9, newSVuv(shm_ss_arena_cap(h)), 0);
229 1           hv_store(hv, "evictions", 9, newSVuv(shm_ss_stat_evictions(h)), 0);
230 1           hv_store(hv, "expired", 7, newSVuv(shm_ss_stat_expired(h)), 0);
231 1           hv_store(hv, "recoveries", 10, newSVuv(shm_ss_stat_recoveries(h)), 0);
232 1           hv_store(hv, "max_size", 8, newSVuv(shm_ss_max_size(h)), 0);
233 1           hv_store(hv, "ttl", 3, newSVuv(shm_ss_ttl(h)), 0);
234 1           RETVAL = newRV_noinc((SV*)hv);
235             OUTPUT:
236             RETVAL
237              
238             bool
239             persist(SV* self_sv, SV* key_sv)
240             CODE:
241 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
242 0 0         EXTRACT_STR_KEY(key_sv);
243 0 0         RETVAL = shm_ss_persist(h, _kstr, (uint32_t)_klen, _kutf8);
244             OUTPUT:
245             RETVAL
246              
247             bool
248             set_ttl(SV* self_sv, SV* key_sv, UV ttl_sec)
249             CODE:
250 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
251 0 0         EXTRACT_STR_KEY(key_sv);
252 0 0         RETVAL = shm_ss_set_ttl(h, _kstr, (uint32_t)_klen, _kutf8, (uint32_t)ttl_sec);
253             OUTPUT:
254             RETVAL
255              
256             bool
257             put_ttl(SV* self_sv, SV* key_sv, SV* value, UV ttl_sec)
258             CODE:
259 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
260 1 50         EXTRACT_STR_KEY(key_sv);
261 1 50         EXTRACT_STR_VAL(value);
262 1 50         REQUIRE_TTL(h);
    50          
263 1 50         RETVAL = shm_ss_put_ttl(h, _kstr, (uint32_t)_klen, _kutf8, _vstr, (uint32_t)_vlen, _vutf8, (uint32_t)ttl_sec);
264             OUTPUT:
265             RETVAL
266              
267             UV
268             max_size(SV* self_sv)
269             CODE:
270 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
271 0 0         RETVAL = (UV)shm_ss_max_size(h);
272             OUTPUT:
273             RETVAL
274              
275             UV
276             ttl(SV* self_sv)
277             CODE:
278 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
279 0 0         RETVAL = (UV)shm_ss_ttl(h);
280             OUTPUT:
281             RETVAL
282              
283             SV*
284             get(SV* self_sv, SV* key_sv)
285             CODE:
286 2561 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
287 2561 50         EXTRACT_STR_KEY(key_sv);
288             const char* val; uint32_t val_len; bool val_utf8;
289 2561 100         if (!shm_ss_get(h, _kstr, (uint32_t)_klen, _kutf8, &val, &val_len, &val_utf8))
290 5           XSRETURN_UNDEF;
291 2556           RETVAL = newSVpvn(val, val_len);
292 2556 100         if (val_utf8) SvUTF8_on(RETVAL);
293             OUTPUT:
294             RETVAL
295              
296             bool
297             remove(SV* self_sv, SV* key_sv)
298             CODE:
299 5005 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
300 5005 50         EXTRACT_STR_KEY(key_sv);
301 5005 50         RETVAL = shm_ss_remove(h, _kstr, (uint32_t)_klen, _kutf8);
302             OUTPUT:
303             RETVAL
304              
305             bool
306             exists(SV* self_sv, SV* key_sv)
307             CODE:
308 11 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
309 11 50         EXTRACT_STR_KEY(key_sv);
310 11 100         RETVAL = shm_ss_exists(h, _kstr, (uint32_t)_klen, _kutf8);
311             OUTPUT:
312             RETVAL
313              
314             UV
315             size(SV* self_sv)
316             CODE:
317 19 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
318 19 50         RETVAL = (UV)shm_ss_size(h);
319             OUTPUT:
320             RETVAL
321              
322             UV
323             max_entries(SV* self_sv)
324             CODE:
325 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
326 0 0         RETVAL = (UV)shm_ss_max_entries(h);
327             OUTPUT:
328             RETVAL
329              
330             void
331             keys(SV* self_sv)
332             PPCODE:
333 3 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
334 3 100         uint32_t ns = h->shard_handles ? h->num_shards : 1;
335 9 100         for (uint32_t si = 0; si < ns; si++) {
336 6 100         ShmHandle *sh = h->shard_handles ? h->shard_handles[si] : h;
337 6           ShmHeader *hdr = sh->hdr;
338 6           ShmNodeSS *nodes = (ShmNodeSS *)sh->nodes;
339 6 50         uint32_t now = sh->expires_at ? shm_now() : 0;
340 6           RDLOCK_GUARD(hdr);
341 6 50         EXTEND(SP, hdr->size);
342 102 100         for (uint32_t i = 0; i < hdr->table_cap; i++) {
343 96 100         if (SHM_IS_LIVE(sh->states[i]) && !SHM_IS_EXPIRED(sh, i, now)) {
    50          
    0          
    0          
344             char _ib[SHM_INLINE_MAX]; uint32_t klen;
345 34           const char *kp = shm_str_ptr(nodes[i].key_off, nodes[i].key_len, sh->arena, _ib, &klen);
346 34           SV* sv = newSVpvn(kp, klen);
347 34 100         if (SHM_UNPACK_UTF8(nodes[i].key_len)) SvUTF8_on(sv);
348 34 50         mXPUSHs(sv);
349             }
350             }
351             }
352              
353             void
354             values(SV* self_sv)
355             PPCODE:
356 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
357 2 100         uint32_t ns = h->shard_handles ? h->num_shards : 1;
358 7 100         for (uint32_t si = 0; si < ns; si++) {
359 5 100         ShmHandle *sh = h->shard_handles ? h->shard_handles[si] : h;
360 5           ShmHeader *hdr = sh->hdr;
361 5           ShmNodeSS *nodes = (ShmNodeSS *)sh->nodes;
362 5 50         uint32_t now = sh->expires_at ? shm_now() : 0;
363 5           RDLOCK_GUARD(hdr);
364 5 50         EXTEND(SP, hdr->size);
365 85 100         for (uint32_t i = 0; i < hdr->table_cap; i++) {
366 80 100         if (SHM_IS_LIVE(sh->states[i]) && !SHM_IS_EXPIRED(sh, i, now)) {
    50          
    0          
    0          
367             char _ib[SHM_INLINE_MAX]; uint32_t vlen;
368 33           const char *vp = shm_str_ptr(nodes[i].val_off, nodes[i].val_len, sh->arena, _ib, &vlen);
369 33           SV* sv = newSVpvn(vp, vlen);
370 33 50         if (SHM_UNPACK_UTF8(nodes[i].val_len)) SvUTF8_on(sv);
371 33 50         mXPUSHs(sv);
372             }
373             }
374             }
375              
376             void
377             items(SV* self_sv)
378             PPCODE:
379 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
380 1 50         uint32_t ns = h->shard_handles ? h->num_shards : 1;
381 2 100         for (uint32_t si = 0; si < ns; si++) {
382 1 50         ShmHandle *sh = h->shard_handles ? h->shard_handles[si] : h;
383 1           ShmHeader *hdr = sh->hdr;
384 1           ShmNodeSS *nodes = (ShmNodeSS *)sh->nodes;
385 1 50         uint32_t now = sh->expires_at ? shm_now() : 0;
386 1           RDLOCK_GUARD(hdr);
387 1 50         EXTEND(SP, hdr->size * 2);
388 17 100         for (uint32_t i = 0; i < hdr->table_cap; i++) {
389 16 100         if (SHM_IS_LIVE(sh->states[i]) && !SHM_IS_EXPIRED(sh, i, now)) {
    50          
    0          
    0          
390             char _kib[SHM_INLINE_MAX]; uint32_t klen;
391 3           const char *kp = shm_str_ptr(nodes[i].key_off, nodes[i].key_len, sh->arena, _kib, &klen);
392 3           SV* ksv = newSVpvn(kp, klen);
393 3 50         if (SHM_UNPACK_UTF8(nodes[i].key_len)) SvUTF8_on(ksv);
394 3 50         mXPUSHs(ksv);
395             char _vib[SHM_INLINE_MAX]; uint32_t vlen;
396 3           const char *vp = shm_str_ptr(nodes[i].val_off, nodes[i].val_len, sh->arena, _vib, &vlen);
397 3           SV* vsv = newSVpvn(vp, vlen);
398 3 50         if (SHM_UNPACK_UTF8(nodes[i].val_len)) SvUTF8_on(vsv);
399 3 50         mXPUSHs(vsv);
400             }
401             }
402             }
403            
404              
405             void
406             each(SV* self_sv)
407             PPCODE:
408 3 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
409             const char *out_key, *out_val;
410             uint32_t out_klen, out_vlen;
411             bool out_kutf8, out_vutf8;
412 3 100         if (shm_ss_each(h, &out_key, &out_klen, &out_kutf8, &out_val, &out_vlen, &out_vutf8)) {
413 2 50         EXTEND(SP, 2);
414 2           SV* ksv = newSVpvn(out_key, out_klen);
415 2 50         if (out_kutf8) SvUTF8_on(ksv);
416 2 50         mXPUSHs(ksv);
417 2           SV* vsv = newSVpvn(out_val, out_vlen);
418 2 50         if (out_vutf8) SvUTF8_on(vsv);
419 2 50         mXPUSHs(vsv);
420 2           XSRETURN(2);
421             }
422 1           shm_ss_flush_deferred(h);
423 1           XSRETURN_EMPTY;
424              
425             void
426             iter_reset(SV* self_sv)
427             CODE:
428 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
429 0           shm_ss_iter_reset(h);
430 0           shm_ss_flush_deferred(h);
431              
432             void
433             clear(SV* self_sv)
434             CODE:
435 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
436 1           shm_ss_clear(h);
437              
438             SV*
439             to_hash(SV* self_sv)
440             CODE:
441 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
442 2           HV* hv = newHV();
443 2 100         uint32_t ns = h->shard_handles ? h->num_shards : 1;
444 7 100         for (uint32_t si = 0; si < ns; si++) {
445 5 100         ShmHandle *sh = h->shard_handles ? h->shard_handles[si] : h;
446 5           ShmHeader *hdr = sh->hdr;
447 5           ShmNodeSS *nodes = (ShmNodeSS *)sh->nodes;
448 5 50         uint32_t now = sh->expires_at ? shm_now() : 0;
449 5           RDLOCK_GUARD(hdr);
450 85 100         for (uint32_t i = 0; i < hdr->table_cap; i++) {
451 80 100         if (SHM_IS_LIVE(sh->states[i]) && !SHM_IS_EXPIRED(sh, i, now)) {
    50          
    0          
    0          
452             char _kib[SHM_INLINE_MAX]; uint32_t klen;
453 32           const char *kp = shm_str_ptr(nodes[i].key_off, nodes[i].key_len, sh->arena, _kib, &klen);
454 32           bool kutf8 = SHM_UNPACK_UTF8(nodes[i].key_len);
455             char _vib[SHM_INLINE_MAX]; uint32_t vlen;
456 32           const char *vp = shm_str_ptr(nodes[i].val_off, nodes[i].val_len, sh->arena, _vib, &vlen);
457 32           SV* val = newSVpvn(vp, vlen);
458 32 50         if (SHM_UNPACK_UTF8(nodes[i].val_len)) SvUTF8_on(val);
459 32 50         if (!hv_store(hv, kp,
    50          
460 0           kutf8 ? -(I32)klen : (I32)klen, val, 0)) SvREFCNT_dec(val);
461             }
462             }
463             }
464 2           RETVAL = newRV_noinc((SV*)hv);
465             OUTPUT:
466             RETVAL
467              
468             SV*
469             get_or_set(SV* self_sv, SV* key_sv, SV* default_sv)
470             CODE:
471 8 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
472 8 50         EXTRACT_STR_KEY(key_sv);
473             const char *out_str; uint32_t out_len; bool out_utf8;
474 8 50         EXTRACT_STR_VAL(default_sv);
475 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);
476 8 50         if (!rc) XSRETURN_UNDEF;
477 8           RETVAL = newSVpvn(out_str, out_len);
478 8 50         if (out_utf8) SvUTF8_on(RETVAL);
479             OUTPUT:
480             RETVAL
481              
482             SV*
483             ttl_remaining(SV* self_sv, SV* key_sv)
484             CODE:
485 6 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
486 6 50         EXTRACT_STR_KEY(key_sv);
487 6           int64_t remaining = shm_ss_ttl_remaining(h, _kstr, (uint32_t)_klen, _kutf8);
488 6 100         if (remaining < 0) XSRETURN_UNDEF;
489 5           RETVAL = newSViv(remaining);
490             OUTPUT:
491             RETVAL
492              
493             UV
494             capacity(SV* self_sv)
495             CODE:
496 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
497 2 50         RETVAL = (UV)shm_ss_capacity(h);
498             OUTPUT:
499             RETVAL
500              
501             UV
502             tombstones(SV* self_sv)
503             CODE:
504 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
505 0 0         RETVAL = (UV)shm_ss_tombstones(h);
506             OUTPUT:
507             RETVAL
508              
509             SV*
510             cursor(SV* self_sv)
511             CODE:
512 4 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
513 4           ShmCursor* c = shm_cursor_create(h);
514 4 50         if (!c) croak("Failed to allocate cursor");
515 4           RETVAL = sv_setref_pv(newSV(0), "Data::HashMap::Shared::SS::Cursor", (void*)c);
516             OUTPUT:
517             RETVAL
518              
519             SV*
520             take(SV* self_sv, SV* key_sv)
521             CODE:
522 6 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
523 6 50         EXTRACT_STR_KEY(key_sv);
524             const char *out_str; uint32_t out_len; bool out_utf8;
525 6 100         if (!shm_ss_take(h, _kstr, (uint32_t)_klen, _kutf8, &out_str, &out_len, &out_utf8)) XSRETURN_UNDEF;
526 5           RETVAL = newSVpvn(out_str, out_len);
527 5 100         if (out_utf8) SvUTF8_on(RETVAL);
528             OUTPUT:
529             RETVAL
530              
531             void
532             pop(SV* self_sv)
533             PPCODE:
534 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
535             const char *out_key; uint32_t out_klen; bool out_kutf8;
536             const char *out_val; uint32_t out_vlen; bool out_vutf8;
537 2 50         if (!shm_ss_pop(h, &out_key, &out_klen, &out_kutf8, &out_val, &out_vlen, &out_vutf8)) XSRETURN_EMPTY;
538 2 50         EXTEND(SP, 2);
539 2           SV *ksv = newSVpvn(out_key, out_klen);
540 2 50         if (out_kutf8) SvUTF8_on(ksv);
541 2           mPUSHs(ksv);
542 2           SV *vsv = newSVpvn(out_val, out_vlen);
543 2 50         if (out_vutf8) SvUTF8_on(vsv);
544 2           mPUSHs(vsv);
545              
546             void
547             shift(SV* self_sv)
548             PPCODE:
549 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
550             const char *out_key; uint32_t out_klen; bool out_kutf8;
551             const char *out_val; uint32_t out_vlen; bool out_vutf8;
552 1 50         if (!shm_ss_shift(h, &out_key, &out_klen, &out_kutf8, &out_val, &out_vlen, &out_vutf8)) XSRETURN_EMPTY;
553 1 50         EXTEND(SP, 2);
554 1           SV *ksv = newSVpvn(out_key, out_klen);
555 1 50         if (out_kutf8) SvUTF8_on(ksv);
556 1           mPUSHs(ksv);
557 1           SV *vsv = newSVpvn(out_val, out_vlen);
558 1 50         if (out_vutf8) SvUTF8_on(vsv);
559 1           mPUSHs(vsv);
560              
561             void
562             drain(SV* self_sv, UV limit)
563             PPCODE:
564 3 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
565 3 50         if (limit == 0) XSRETURN_EMPTY;
566             shm_ss_drain_entry *entries;
567 3 50         Newxz(entries, limit, shm_ss_drain_entry);
568            
569 3           SAVEFREEPV(entries);
570 3           char *buf = NULL; uint32_t buf_cap = 0;
571 3           uint32_t n = shm_ss_drain(h, (uint32_t)limit, entries, &buf, &buf_cap);
572            
573 3 50         EXTEND(SP, n * 2);
574 12 100         for (uint32_t i = 0; i < n; i++) {
575 9           SV *ksv = newSVpvn(buf + entries[i].key_off, entries[i].key_len);
576 9 50         if (entries[i].key_utf8) SvUTF8_on(ksv);
577 9           mPUSHs(ksv);
578 9           SV *vsv = newSVpvn(buf + entries[i].val_off, entries[i].val_len);
579 9 50         if (entries[i].val_utf8) SvUTF8_on(vsv);
580 9           mPUSHs(vsv);
581             }
582 3 50         if (buf) free(buf);
583            
584              
585             UV
586             flush_expired(SV* self_sv)
587             CODE:
588 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
589 1 50         RETVAL = (UV)shm_ss_flush_expired(h);
590             OUTPUT:
591             RETVAL
592              
593             void
594             flush_expired_partial(SV* self_sv, UV limit)
595             PPCODE:
596 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
597 0           int done = 0;
598 0           uint32_t flushed = shm_ss_flush_expired_partial(h, (uint32_t)limit, &done);
599 0 0         EXTEND(SP, 2);
600 0           mPUSHu(flushed);
601 0           mPUSHi(done);
602              
603             UV
604             mmap_size(SV* self_sv)
605             CODE:
606 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
607 1           RETVAL = (UV)shm_ss_mmap_size(h);
608             OUTPUT:
609             RETVAL
610              
611             bool
612             touch(SV* self_sv, SV* key_sv)
613             CODE:
614 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
615 2 50         EXTRACT_STR_KEY(key_sv);
616 2 100         RETVAL = shm_ss_touch(h, _kstr, (uint32_t)_klen, _kutf8);
617             OUTPUT:
618             RETVAL
619              
620             bool
621             reserve(SV* self_sv, UV target)
622             CODE:
623 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
624 1 50         RETVAL = shm_ss_reserve(h, (uint32_t)target);
625             OUTPUT:
626             RETVAL
627              
628             UV
629             stat_evictions(SV* self_sv)
630             CODE:
631 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
632 2           RETVAL = (UV)shm_ss_stat_evictions(h);
633             OUTPUT:
634             RETVAL
635              
636             UV
637             stat_expired(SV* self_sv)
638             CODE:
639 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
640 0           RETVAL = (UV)shm_ss_stat_expired(h);
641             OUTPUT:
642             RETVAL
643              
644             UV
645             stat_recoveries(SV* self_sv)
646             CODE:
647 0 0         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    0          
    0          
648 0 0         RETVAL = (UV)shm_ss_stat_recoveries(h);
649             OUTPUT:
650             RETVAL
651              
652             UV
653             arena_used(SV* self_sv)
654             CODE:
655 4 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
656 4           RETVAL = (UV)shm_ss_arena_used(h);
657             OUTPUT:
658             RETVAL
659              
660             UV
661             arena_cap(SV* self_sv)
662             CODE:
663 1 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
664 1           RETVAL = (UV)shm_ss_arena_cap(h);
665             OUTPUT:
666             RETVAL
667              
668             bool
669             add(SV* self_sv, SV* key_sv, SV* val_sv)
670             CODE:
671 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
672 2 50         EXTRACT_STR_KEY(key_sv);
673 2 50         EXTRACT_STR_VAL(val_sv);
674 2 100         RETVAL = shm_ss_add(h, _kstr, (uint32_t)_klen, _kutf8, _vstr, (uint32_t)_vlen, _vutf8);
675             OUTPUT:
676             RETVAL
677              
678             bool
679             add_ttl(SV* self_sv, SV* key_sv, SV* val_sv, UV ttl_sec)
680             CODE:
681 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
682 2 50         EXTRACT_STR_KEY(key_sv);
683 2 50         EXTRACT_STR_VAL(val_sv);
684 2 50         REQUIRE_TTL(h);
    50          
685 2 100         RETVAL = shm_ss_add_ttl(h, _kstr, (uint32_t)_klen, _kutf8,
686             _vstr, (uint32_t)_vlen, _vutf8, (uint32_t)ttl_sec);
687             OUTPUT:
688             RETVAL
689              
690             bool
691             update(SV* self_sv, SV* key_sv, SV* val_sv)
692             CODE:
693 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
694 2 50         EXTRACT_STR_KEY(key_sv);
695 2 50         EXTRACT_STR_VAL(val_sv);
696 2 100         RETVAL = shm_ss_update(h, _kstr, (uint32_t)_klen, _kutf8, _vstr, (uint32_t)_vlen, _vutf8);
697             OUTPUT:
698             RETVAL
699              
700             bool
701             update_ttl(SV* self_sv, SV* key_sv, SV* val_sv, UV ttl_sec)
702             CODE:
703 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
704 2 50         EXTRACT_STR_KEY(key_sv);
705 2 50         EXTRACT_STR_VAL(val_sv);
706 2 50         REQUIRE_TTL(h);
    50          
707 2 100         RETVAL = shm_ss_update_ttl(h, _kstr, (uint32_t)_klen, _kutf8, _vstr, (uint32_t)_vlen, _vutf8, (uint32_t)ttl_sec);
708             OUTPUT:
709             RETVAL
710              
711             SV*
712             swap(SV* self_sv, SV* key_sv, SV* val_sv)
713             CODE:
714 5 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
715 5 50         EXTRACT_STR_KEY(key_sv);
716 5 50         EXTRACT_STR_VAL(val_sv);
717             const char *out_s; uint32_t out_l; bool out_u;
718 5           int rc = shm_ss_swap(h, _kstr, (uint32_t)_klen, _kutf8, _vstr, (uint32_t)_vlen, _vutf8, &out_s, &out_l, &out_u);
719 5 100         if (rc != 1) XSRETURN_UNDEF;
720 3           RETVAL = newSVpvn(out_s, out_l);
721 3 50         if (out_u) SvUTF8_on(RETVAL);
722             OUTPUT:
723             RETVAL
724              
725             bool
726             cas(SV* self_sv, SV* key_sv, SV* expected_sv, SV* desired_sv)
727             CODE:
728 10 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
729 10 50         EXTRACT_STR_KEY(key_sv);
730 10 50         EXTRACT_STR_EXPECTED_DESIRED(expected_sv, desired_sv);
    50          
731 10 100         RETVAL = shm_ss_cas(h, _kstr, (uint32_t)_klen, _kutf8,
732             _estr, (uint32_t)_elen, _dstr, (uint32_t)_dlen, _dutf8);
733             OUTPUT:
734             RETVAL
735              
736             SV*
737             cas_take(SV* self_sv, SV* key_sv, SV* expected_sv)
738             CODE:
739 3 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
740 3 50         EXTRACT_STR_KEY(key_sv);
741 3 50         EXTRACT_STR_EXPECTED(expected_sv);
742             const char *out_s; uint32_t out_l; bool out_u;
743 3 100         if (!shm_ss_cas_take(h, _kstr, (uint32_t)_klen, _kutf8, _estr, (uint32_t)_elen, &out_s, &out_l, &out_u)) XSRETURN_UNDEF;
744 2           RETVAL = newSVpvn(out_s, out_l);
745 2 50         if (out_u) SvUTF8_on(RETVAL);
746             OUTPUT:
747             RETVAL
748              
749             SV*
750             path(SV* self_sv)
751             CODE:
752 2 50         EXTRACT_MAP("Data::HashMap::Shared::SS", self_sv);
    50          
    50          
753 2 100         RETVAL = h->path ? newSVpv(h->path, 0) : &PL_sv_undef;
754             OUTPUT:
755             RETVAL
756              
757             bool
758             unlink(SV* self_or_class, ...)
759             CODE:
760             const char *p;
761 0 0         if (SvROK(self_or_class) && SvOBJECT(SvRV(self_or_class))) {
    0          
762 0           ShmHandle* h = INT2PTR(ShmHandle*, SvIV(SvRV(self_or_class)));
763 0 0         if (!h) croak("Attempted to use a destroyed Data::HashMap::Shared::SS object");
764 0           p = h->path;
765             } else {
766 0 0         if (items < 2) croak("Usage: Data::HashMap::Shared::SS->unlink($path)");
767 0           p = SvPV_nolen(ST(1));
768             }
769 0 0         RETVAL = (SvROK(self_or_class) && SvOBJECT(SvRV(self_or_class))) ?
    0          
770 0 0         shm_unlink_sharded(INT2PTR(ShmHandle*, SvIV(SvRV(self_or_class)))) :
771 0           shm_unlink_path(p);
772             OUTPUT:
773             RETVAL
774              
775             MODULE = Data::HashMap::Shared PACKAGE = Data::HashMap::Shared::SS::Cursor
776             PROTOTYPES: DISABLE
777              
778             void
779             DESTROY(SV* self_sv)
780             CODE:
781 4 50         if (!SvROK(self_sv)) return;
782 4           ShmCursor* c = INT2PTR(ShmCursor*, SvIV(SvRV(self_sv)));
783 4 50         if (!c) return;
784 4           ShmHandle* h = c->current;
785 4           shm_cursor_destroy(c);
786 4 50         if (h) shm_ss_flush_deferred(h);
787 4           sv_setiv(SvRV(self_sv), 0);
788              
789             void
790             next(SV* self_sv)
791             PPCODE:
792 29 50         EXTRACT_CURSOR("Data::HashMap::Shared::SS::Cursor", self_sv);
    50          
    50          
793             const char *out_key, *out_val;
794             uint32_t out_klen, out_vlen;
795             bool out_kutf8, out_vutf8;
796 29 100         if (shm_ss_cursor_next(c, &out_key, &out_klen, &out_kutf8, &out_val, &out_vlen, &out_vutf8)) {
797 27 50         EXTEND(SP, 2);
798 27           SV* ksv = newSVpvn(out_key, out_klen);
799 27 50         if (out_kutf8) SvUTF8_on(ksv);
800 27 50         mXPUSHs(ksv);
801 27           SV* vsv = newSVpvn(out_val, out_vlen);
802 27 50         if (out_vutf8) SvUTF8_on(vsv);
803 27 50         mXPUSHs(vsv);
804 27           XSRETURN(2);
805             }
806 2           XSRETURN_EMPTY;
807              
808             void
809             reset(SV* self_sv)
810             CODE:
811 0 0         EXTRACT_CURSOR("Data::HashMap::Shared::SS::Cursor", self_sv);
    0          
    0          
812 0           shm_ss_cursor_reset(c);
813              
814             bool
815             seek(SV* self_sv, SV* key_sv)
816             CODE:
817 3 50         EXTRACT_CURSOR("Data::HashMap::Shared::SS::Cursor", self_sv);
    50          
    50          
818 3 50         EXTRACT_STR_KEY(key_sv);
819 3 100         RETVAL = shm_ss_cursor_seek(c, _kstr, (uint32_t)_klen, _kutf8);
820             OUTPUT:
821             RETVAL
822