File Coverage

xs/ss.xs
Criterion Covered Total %
statement 218 400 54.5
branch 255 752 33.9
condition n/a
subroutine n/a
pod n/a
total 473 1152 41.0


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