File Coverage

xs/ii.xs
Criterion Covered Total %
statement 327 330 99.0
branch 397 660 60.1
condition n/a
subroutine n/a
pod n/a
total 724 990 73.1


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