File Coverage

xs/is.xs
Criterion Covered Total %
statement 56 354 15.8
branch 79 690 11.4
condition n/a
subroutine n/a
pod n/a
total 135 1044 12.9


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