12 #include "randomness.h"
13 #include "test_suite.h"
15 reservoir_t
reservoir_new(size_t sz
) {
16 reservoir_t reservoir
;
18 reservoir
= malloc((sz
* sizeof *reservoir
->reservoir
) + sizeof *reservoir
);
19 if (reservoir
== NULL
) {
20 NOTIFY_ERROR("%s:%s", "malloc", strerror(errno
));
23 reservoir
->reservoir_sz
= sz
;
24 reservoir
->reservoir_used
= 0;
25 reservoir
->reservoir_tally
= 0;
26 memset(reservoir
->reservoir
, 0, reservoir
->reservoir_sz
* sizeof *reservoir
->reservoir
);
31 int reservoir_grow(reservoir_t
*preservoir
, size_t growby
) {
32 assert(preservoir
!= NULL
);
35 void *tmp_ptr
= realloc(*preservoir
, (((*preservoir
)->reservoir_sz
+ growby
) * sizeof *(*preservoir
)->reservoir
) + sizeof **preservoir
);
36 if (tmp_ptr
== NULL
) {
37 NOTIFY_ERROR("%s:%s", "realloc", strerror(errno
));
40 *preservoir
= tmp_ptr
;
41 (*preservoir
)->reservoir_sz
+= growby
;
42 memset((*preservoir
)->reservoir
+ (*preservoir
)->reservoir_used
, 0, (*preservoir
)->reservoir_sz
- (*preservoir
)->reservoir_used
);
45 D_RESERVOIR(*preservoir
);
50 void reservoir_remember(reservoir_t reservoir
, buf_t buf
) {
53 assert(reservoir
!= NULL
);
55 D_BUF("reserving ", buf
);
57 if (reservoir
->reservoir_sz
> 0) {
58 unsigned long randomness
;
60 if (reservoir
->reservoir_used
< reservoir
->reservoir_sz
) {
61 /* there are still unused slots, fill them up without discarding anything */
62 /* do this by moving our random victim slot contents to the end of the list, before inserting the new item in its old place */
63 randomness
= randomness_upto_inclusive(reservoir
->reservoir_used
);
65 assert(reservoir
->reservoir
[reservoir
->reservoir_used
] == NULL
); /* yet-unused slots will be null-initialized */
67 NOTIFY_DEBUG("preserving existing index %zu to end index (%zu)", randomness
, reservoir
->reservoir_used
);
68 reservoir
->reservoir
[reservoir
->reservoir_used
] = reservoir
->reservoir
[randomness
];
69 old_buf
= NULL
; /* no old entry to discard */
70 reservoir
->reservoir_used
+= 1;
72 randomness
= randomness_upto_inclusive(reservoir
->reservoir_sz
- 1);
73 old_buf
= reservoir
->reservoir
[randomness
];
75 NOTIFY_DEBUG("replacing reservoir index %zu", randomness
);
76 reservoir
->reservoir
[randomness
] = buf
;
78 /* can't add anything to a zero-size reservoir, so just dispose of new item */
82 reservoir
->reservoir_tally
+= 1;
84 if (old_buf
!= NULL
) {
85 D_BUF("FREEING ", old_buf
);
86 memset(old_buf
, 0, old_buf
->buf_sz
+ sizeof *old_buf
);
90 D_RESERVOIR(reservoir
);
93 int reservoir_write(int fd
, reservoir_t reservoir
, char delim
) {
98 iov
[1].iov_base
= &delim
;
99 iov
[1].iov_len
= sizeof delim
;
101 assert(reservoir
!= NULL
);
102 D_RESERVOIR(reservoir
);
104 for (i
= 0; i
< reservoir
->reservoir_sz
; i
++) {
105 if (reservoir
->reservoir
[i
]) {
106 iov
[0].iov_base
= reservoir
->reservoir
[i
]->buf
+ reservoir
->reservoir
[i
]->buf_start
;
107 iov
[0].iov_len
= reservoir
->reservoir
[i
]->buf_used
;
109 iov
[0].iov_base
= NULL
;
114 len
= writev(fd
, iov
, sizeof iov
/ sizeof *iov
);
115 } while (len
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
117 NOTIFY_ERROR("%s:%s", "writev", strerror(errno
));
125 #define META_BUF_SZ 128
126 int reservoir_write_meta(int fd
, reservoir_t reservoir
, unsigned long samples
, char delim
) {
127 char buf
[META_BUF_SZ
];
131 metalen
= snprintf(buf
, sizeof buf
, "sz:%zu%cused:%zu%crecorded:%lu%csamples:%lu%c",
132 reservoir
->reservoir_sz
, delim
,
133 reservoir
->reservoir_used
, delim
,
134 reservoir
->reservoir_tally
, delim
,
136 if ((size_t)metalen
>= sizeof buf
) {
137 NOTIFY_ERROR("out of buffer");
141 len
= write(fd
, buf
, metalen
);
142 } while (len
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
145 NOTIFY_ERROR("%s:%s", "write", strerror(errno
));
155 void *test_suite_data
;
157 int test_suite_pre(void *suite_data
) {
159 if (randomness_init(NULL
)) {
165 int test_suite_post(void *suite_data
) {
170 test_t test_suite
[] = {
171 { NULL
, NULL
, NULL
, NULL
, NULL
},