dc97137f3c62976392fd6025217b80b41d7db377
[ccan] / ccan / tdb2 / test / run-03-coalesce.c
1 #include <ccan/tdb2/tdb.c>
2 #include <ccan/tdb2/free.c>
3 #include <ccan/tdb2/lock.c>
4 #include <ccan/tdb2/io.c>
5 #include <ccan/tdb2/hash.c>
6 #include <ccan/tdb2/check.c>
7 #include <ccan/tap/tap.h>
8 #include "logging.h"
9 #include "layout.h"
10
11 static tdb_len_t free_record_length(struct tdb_context *tdb, tdb_off_t off)
12 {
13         struct tdb_free_record f;
14
15         if (tdb_read_convert(tdb, off, &f, sizeof(f)) != 0)
16                 return TDB_OFF_ERR;
17         if (frec_magic(&f) != TDB_FREE_MAGIC)
18                 return TDB_OFF_ERR;
19         return f.data_len;
20 }
21
22 int main(int argc, char *argv[])
23 {
24         tdb_off_t b_off, zone_off;
25         struct tdb_context *tdb;
26         struct tdb_layout *layout;
27         struct tdb_data data, key;
28         tdb_len_t len;
29         unsigned int zone_bits = 16;
30
31         /* FIXME: Test TDB_CONVERT */
32
33         plan_tests(45);
34         data.dptr = (void *)"world";
35         data.dsize = 5;
36         key.dptr = (void *)"hello";
37         key.dsize = 5;
38
39         /* No coalescing can be done due to EOF */
40         layout = new_tdb_layout(NULL);
41         tdb_layout_add_zone(layout, zone_bits, false);
42         tdb = tdb_layout_get(layout);
43         len = layout->elem[1].free.len;
44         zone_off = layout->elem[0].base.off;
45         ok1(tdb_check(tdb, NULL, NULL) == 0);
46         ok1(free_record_length(tdb, layout->elem[1].base.off) == len);
47
48         /* Figure out which bucket free entry is. */
49         b_off = bucket_off(zone_off, size_to_bucket(zone_bits, len));
50         /* Lock and fail to coalesce. */
51         ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0);
52         ok1(coalesce(tdb, zone_off, zone_bits, layout->elem[1].base.off,
53                      b_off, len) == 0);
54         tdb_unlock_free_bucket(tdb, b_off);
55         ok1(free_record_length(tdb, layout->elem[1].base.off) == len);
56         ok1(tdb_check(tdb, NULL, NULL) == 0);
57         tdb_close(tdb);
58
59         /* No coalescing can be done due to used record */
60         layout = new_tdb_layout(NULL);
61         tdb_layout_add_zone(layout, zone_bits, false);
62         tdb_layout_add_free(layout, 1024);
63         tdb_layout_add_used(layout, key, data, 6);
64         tdb = tdb_layout_get(layout);
65         zone_off = layout->elem[0].base.off;
66         ok1(free_record_length(tdb, layout->elem[1].base.off) == 1024);
67         ok1(tdb_check(tdb, NULL, NULL) == 0);
68
69         /* Figure out which bucket free entry is. */
70         b_off = bucket_off(zone_off, size_to_bucket(zone_bits, 1024));
71         /* Lock and fail to coalesce. */
72         ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0);
73         ok1(coalesce(tdb, zone_off, zone_bits, layout->elem[1].base.off,
74                      b_off, 1024) == 0);
75         tdb_unlock_free_bucket(tdb, b_off);
76         ok1(free_record_length(tdb, layout->elem[1].base.off) == 1024);
77         ok1(tdb_check(tdb, NULL, NULL) == 0);
78         tdb_close(tdb);
79
80         /* Coalescing can be done due to two free records, then EOF */
81         layout = new_tdb_layout(NULL);
82         tdb_layout_add_zone(layout, zone_bits, false);
83         tdb_layout_add_free(layout, 1024);
84         tdb = tdb_layout_get(layout);
85         zone_off = layout->elem[0].base.off;
86         len = layout->elem[2].free.len;
87         ok1(free_record_length(tdb, layout->elem[1].base.off) == 1024);
88         ok1(free_record_length(tdb, layout->elem[2].base.off) == len);
89         ok1(tdb_check(tdb, NULL, NULL) == 0);
90
91         /* Figure out which bucket (first) free entry is. */
92         b_off = bucket_off(zone_off, size_to_bucket(zone_bits, 1024));
93         /* Lock and coalesce. */
94         ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0);
95         ok1(coalesce(tdb, zone_off, zone_bits, layout->elem[1].base.off,
96                      b_off, 1024) == 1);
97         ok1(!tdb_has_locks(tdb));
98         ok1(free_record_length(tdb, layout->elem[1].base.off)
99             == 1024 + sizeof(struct tdb_used_record) + len);
100         ok1(tdb_check(tdb, NULL, NULL) == 0);
101         tdb_close(tdb);
102
103         /* Coalescing can be done due to two free records, then data */
104         layout = new_tdb_layout(NULL);
105         tdb_layout_add_zone(layout, zone_bits, false);
106         tdb_layout_add_free(layout, 1024);
107         tdb_layout_add_free(layout, 512);
108         tdb_layout_add_used(layout, key, data, 6);
109         tdb = tdb_layout_get(layout);
110         zone_off = layout->elem[0].base.off;
111         ok1(free_record_length(tdb, layout->elem[1].base.off) == 1024);
112         ok1(free_record_length(tdb, layout->elem[2].base.off) == 512);
113         ok1(tdb_check(tdb, NULL, NULL) == 0);
114
115         /* Figure out which bucket free entry is. */
116         b_off = bucket_off(zone_off, size_to_bucket(zone_bits, 1024));
117         /* Lock and coalesce. */
118         ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0);
119         ok1(coalesce(tdb, zone_off, zone_bits, layout->elem[1].base.off,
120                      b_off, 1024) == 1);
121         ok1(!tdb_has_locks(tdb));
122         ok1(free_record_length(tdb, layout->elem[1].base.off)
123             == 1024 + sizeof(struct tdb_used_record) + 512);
124         ok1(tdb_check(tdb, NULL, NULL) == 0);
125         tdb_close(tdb);
126
127         /* Coalescing can be done due to three free records, then EOF */
128         layout = new_tdb_layout(NULL);
129         tdb_layout_add_zone(layout, zone_bits, false);
130         tdb_layout_add_free(layout, 1024);
131         tdb_layout_add_free(layout, 512);
132         tdb = tdb_layout_get(layout);
133         zone_off = layout->elem[0].base.off;
134         len = layout->elem[3].free.len;
135         ok1(free_record_length(tdb, layout->elem[1].base.off) == 1024);
136         ok1(free_record_length(tdb, layout->elem[2].base.off) == 512);
137         ok1(free_record_length(tdb, layout->elem[3].base.off) == len);
138         ok1(tdb_check(tdb, NULL, NULL) == 0);
139
140         /* Figure out which bucket free entry is. */
141         b_off = bucket_off(zone_off, size_to_bucket(zone_bits, 1024));
142         /* Lock and coalesce. */
143         ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0);
144         ok1(coalesce(tdb, zone_off, zone_bits, layout->elem[1].base.off,
145                      b_off, 1024) == 1);
146         ok1(!tdb_has_locks(tdb));
147         ok1(free_record_length(tdb, layout->elem[1].base.off)
148             == 1024 + sizeof(struct tdb_used_record) + 512
149             + sizeof(struct tdb_used_record) + len);
150         ok1(tdb_check(tdb, NULL, NULL) == 0);
151         tdb_close(tdb);
152
153         /* Coalescing across two zones isn't possible. */
154         layout = new_tdb_layout(NULL);
155         tdb_layout_add_zone(layout, zone_bits, false);
156         tdb_layout_add_zone(layout, zone_bits, true);
157         tdb = tdb_layout_get(layout);
158         zone_off = layout->elem[0].base.off;
159         len = layout->elem[1].free.len;
160         ok1(free_record_length(tdb, layout->elem[1].base.off) == len);
161         ok1(tdb_check(tdb, NULL, NULL) == 0);
162
163         /* Figure out which list free entry is. */
164         b_off = bucket_off(zone_off, size_to_bucket(zone_bits, len));
165         /* Lock and coalesce. */
166         ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0);
167         ok1(coalesce(tdb, zone_off, zone_bits, layout->elem[1].base.off,
168                      b_off, len) == 0);
169         tdb_unlock_free_bucket(tdb, b_off);
170         ok1(!tdb_has_locks(tdb));
171         ok1(free_record_length(tdb, layout->elem[1].base.off) == len);
172         ok1(tdb_check(tdb, NULL, NULL) == 0);
173         tdb_close(tdb);
174
175         ok1(tap_log_messages == 0);
176         return exit_status();
177 }