File Coverage

Shared.xs
Criterion Covered Total %
statement 85 91 93.4
branch 91 174 52.3
condition n/a
subroutine n/a
pod n/a
total 176 265 66.4


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5             #include "ppport.h"
6             #include "log.h"
7              
8             #define EXTRACT_LOG(sv) \
9             if (!sv_isobject(sv) || !sv_derived_from(sv, "Data::Log::Shared")) \
10             croak("Expected a Data::Log::Shared object"); \
11             LogHandle *h = INT2PTR(LogHandle*, SvIV(SvRV(sv))); \
12             if (!h) croak("Attempted to use a destroyed Data::Log::Shared object")
13              
14             #define MAKE_OBJ(class, handle) \
15             SV *obj = newSViv(PTR2IV(handle)); \
16             SV *ref = newRV_noinc(obj); \
17             sv_bless(ref, gv_stashpv(class, GV_ADD)); \
18             RETVAL = ref
19              
20             MODULE = Data::Log::Shared PACKAGE = Data::Log::Shared
21              
22             PROTOTYPES: DISABLE
23              
24             SV *
25             new(class, path, data_size)
26             const char *class
27             SV *path
28             UV data_size
29             PREINIT:
30             char errbuf[LOG_ERR_BUFLEN];
31             CODE:
32 6 100         const char *p = SvOK(path) ? SvPV_nolen(path) : NULL;
33 6           LogHandle *h = log_create(p, data_size, errbuf);
34 6 50         if (!h) croak("Data::Log::Shared->new: %s", errbuf);
35 6           MAKE_OBJ(class, h);
36             OUTPUT:
37             RETVAL
38              
39             SV *
40             new_memfd(class, name, data_size)
41             const char *class
42             const char *name
43             UV data_size
44             PREINIT:
45             char errbuf[LOG_ERR_BUFLEN];
46             CODE:
47 7           LogHandle *h = log_create_memfd(name, data_size, errbuf);
48 7 50         if (!h) croak("Data::Log::Shared->new_memfd: %s", errbuf);
49 7           MAKE_OBJ(class, h);
50             OUTPUT:
51             RETVAL
52              
53             SV *
54             new_from_fd(class, fd)
55             const char *class
56             int fd
57             PREINIT:
58             char errbuf[LOG_ERR_BUFLEN];
59             CODE:
60 1           LogHandle *h = log_open_fd(fd, errbuf);
61 1 50         if (!h) croak("Data::Log::Shared->new_from_fd: %s", errbuf);
62 1           MAKE_OBJ(class, h);
63             OUTPUT:
64             RETVAL
65              
66             void
67             DESTROY(self)
68             SV *self
69             CODE:
70 14 50         if (!SvROK(self)) return;
71 14           LogHandle *h = INT2PTR(LogHandle*, SvIV(SvRV(self)));
72 14 50         if (!h) return;
73 14           sv_setiv(SvRV(self), 0);
74 14           log_destroy(h);
75              
76             SV *
77             append(self, data)
78             SV *self
79             SV *data
80             PREINIT:
81 115 50         EXTRACT_LOG(self);
    50          
    50          
82             CODE:
83             STRLEN len;
84 115           const char *buf = SvPV(data, len);
85 115 100         if (len == 0) croak("append: data must not be empty");
86 113 50         if (len > (STRLEN)(UINT32_MAX - LOG_ENTRY_HDR - 3))
87 0           croak("append: data too large");
88 113           int64_t off = log_append(h, buf, (uint32_t)len);
89 113 100         RETVAL = (off >= 0) ? newSViv((IV)off) : &PL_sv_undef;
90             OUTPUT:
91             RETVAL
92              
93             void
94             read_entry(self, offset, ...)
95             SV *self
96             UV offset
97             PREINIT:
98 240 50         EXTRACT_LOG(self);
    50          
    50          
99             PPCODE:
100             const uint8_t *out_data;
101             uint32_t out_len;
102             uint64_t next_off;
103             /* Optional third arg: abandon_wait_us (default LOG_ABANDON_WAIT_US).
104             * Pass 0 to immediately treat any uncommitted slot as abandoned. */
105 240 50         uint64_t wait_us = (items > 2) ? (uint64_t)SvUV(ST(2)) : (uint64_t)LOG_ABANDON_WAIT_US;
106 240           int rc = log_read_ex(h, offset, &out_data, &out_len, &next_off, wait_us);
107 240 100         if (rc == LOG_READ_OK) {
108 229 50         EXTEND(SP, 2);
109 229           PUSHs(sv_2mortal(newSVpvn((const char *)out_data, out_len)));
110 229           PUSHs(sv_2mortal(newSVuv((UV)next_off)));
111 11 50         } else if (rc == LOG_READ_ABANDONED) {
112             /* Signal "skip this slot" — data is undef, next_off is set. */
113 0 0         EXTEND(SP, 2);
114 0           PUSHs(sv_newmortal()); /* undef */
115 0           PUSHs(sv_2mortal(newSVuv((UV)next_off)));
116             }
117             /* LOG_READ_EMPTY: return empty list. */
118              
119             UV
120             tail_offset(self)
121             SV *self
122             PREINIT:
123 3 50         EXTRACT_LOG(self);
    50          
    50          
124             CODE:
125 3           RETVAL = (UV)log_tail_offset(h);
126             OUTPUT:
127             RETVAL
128              
129             UV
130             entry_count(self)
131             SV *self
132             PREINIT:
133 14 50         EXTRACT_LOG(self);
    50          
    50          
134             CODE:
135 14           RETVAL = (UV)log_entry_count(h);
136             OUTPUT:
137             RETVAL
138              
139             UV
140             data_size(self)
141             SV *self
142             PREINIT:
143 1 50         EXTRACT_LOG(self);
    50          
    50          
144             CODE:
145 1           RETVAL = (UV)log_data_size(h);
146             OUTPUT:
147             RETVAL
148              
149             UV
150             available(self)
151             SV *self
152             PREINIT:
153 1 50         EXTRACT_LOG(self);
    50          
    50          
154             CODE:
155 1           RETVAL = (UV)log_available(h);
156             OUTPUT:
157             RETVAL
158              
159             bool
160             wait_for(self, expected_count, ...)
161             SV *self
162             UV expected_count
163             PREINIT:
164 2 50         EXTRACT_LOG(self);
    50          
    50          
165 2           double timeout = -1;
166             CODE:
167 2 50         if (items > 2) timeout = SvNV(ST(2));
168 2 100         RETVAL = log_wait(h, expected_count, timeout);
169             OUTPUT:
170             RETVAL
171              
172             void
173             reset(self)
174             SV *self
175             PREINIT:
176 7 50         EXTRACT_LOG(self);
    50          
    50          
177             CODE:
178 7           log_reset(h);
179              
180             void
181             truncate(self, offset)
182             SV *self
183             UV offset
184             PREINIT:
185 4 50         EXTRACT_LOG(self);
    50          
    50          
186             CODE:
187 4           log_truncate(h, (uint64_t)offset);
188              
189             UV
190             truncation(self)
191             SV *self
192             PREINIT:
193 13 50         EXTRACT_LOG(self);
    50          
    50          
194             CODE:
195 13           RETVAL = (UV)log_truncation(h);
196             OUTPUT:
197             RETVAL
198              
199             SV *
200             path(self)
201             SV *self
202             PREINIT:
203 1 50         EXTRACT_LOG(self);
    50          
    50          
204             CODE:
205 1 50         RETVAL = h->path ? newSVpv(h->path, 0) : &PL_sv_undef;
206             OUTPUT:
207             RETVAL
208              
209             IV
210             memfd(self)
211             SV *self
212             PREINIT:
213 1 50         EXTRACT_LOG(self);
    50          
    50          
214             CODE:
215 1 50         RETVAL = h->backing_fd;
216             OUTPUT:
217             RETVAL
218              
219             IV
220             eventfd(self)
221             SV *self
222             PREINIT:
223 2 50         EXTRACT_LOG(self);
    50          
    50          
224             CODE:
225 2           RETVAL = log_create_eventfd(h);
226 2 50         if (RETVAL < 0) croak("eventfd: %s", strerror(errno));
227             OUTPUT:
228             RETVAL
229              
230             void
231             eventfd_set(self, fd)
232             SV *self
233             int fd
234             PREINIT:
235 3 50         EXTRACT_LOG(self);
    50          
    50          
236             CODE:
237 3 50         if (h->notify_fd >= 0 && h->notify_fd != fd) close(h->notify_fd);
    100          
238 3           h->notify_fd = fd;
239              
240             IV
241             fileno(self)
242             SV *self
243             PREINIT:
244 3 50         EXTRACT_LOG(self);
    50          
    50          
245             CODE:
246 3 50         RETVAL = h->notify_fd;
247             OUTPUT:
248             RETVAL
249              
250             bool
251             notify(self)
252             SV *self
253             PREINIT:
254 2 50         EXTRACT_LOG(self);
    50          
    50          
255             CODE:
256 2 50         RETVAL = log_notify(h);
257             OUTPUT:
258             RETVAL
259              
260             SV *
261             eventfd_consume(self)
262             SV *self
263             PREINIT:
264 2 50         EXTRACT_LOG(self);
    50          
    50          
265             CODE:
266 2           int64_t v = log_eventfd_consume(h);
267 2 50         RETVAL = (v >= 0) ? newSViv((IV)v) : &PL_sv_undef;
268             OUTPUT:
269             RETVAL
270              
271             void
272             sync(self)
273             SV *self
274             PREINIT:
275 1 50         EXTRACT_LOG(self);
    50          
    50          
276             CODE:
277 1 50         if (log_msync(h) != 0) croak("msync: %s", strerror(errno));
278              
279             void
280             unlink(self_or_class, ...)
281             SV *self_or_class
282             CODE:
283             const char *p;
284 1 50         if (sv_isobject(self_or_class)) {
285 1           LogHandle *h = INT2PTR(LogHandle*, SvIV(SvRV(self_or_class)));
286 1 50         if (!h) croak("Attempted to use a destroyed object");
287 1           p = h->path;
288             } else {
289 0 0         if (items < 2) croak("Usage: ...->unlink($path)");
290 0           p = SvPV_nolen(ST(1));
291             }
292 1 50         if (!p) croak("cannot unlink anonymous or memfd object");
293 1 50         if (unlink(p) != 0) croak("unlink(%s): %s", p, strerror(errno));
294              
295             SV *
296             stats(self)
297             SV *self
298             PREINIT:
299 1 50         EXTRACT_LOG(self);
    50          
    50          
300             CODE:
301 1           HV *hv = newHV();
302 1           LogHeader *hdr = h->hdr;
303 1           hv_store(hv, "data_size", 9, newSVuv((UV)hdr->data_size), 0);
304 1           hv_store(hv, "tail", 4, newSVuv((UV)log_tail_offset(h)), 0);
305 1           hv_store(hv, "count", 5, newSVuv((UV)log_entry_count(h)), 0);
306 1           hv_store(hv, "available", 9, newSVuv((UV)log_available(h)), 0);
307 1           hv_store(hv, "waiters", 7, newSVuv(__atomic_load_n(&hdr->waiters, __ATOMIC_RELAXED)), 0);
308 1           hv_store(hv, "appends", 7, newSVuv((UV)__atomic_load_n(&hdr->stat_appends, __ATOMIC_RELAXED)), 0);
309 1           hv_store(hv, "waits", 5, newSVuv((UV)__atomic_load_n(&hdr->stat_waits, __ATOMIC_RELAXED)), 0);
310 1           hv_store(hv, "timeouts", 8, newSVuv((UV)__atomic_load_n(&hdr->stat_timeouts, __ATOMIC_RELAXED)), 0);
311 1           hv_store(hv, "mmap_size", 9, newSVuv((UV)h->mmap_size), 0);
312 1           RETVAL = newRV_noinc((SV *)hv);
313             OUTPUT:
314             RETVAL