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/check.c>
6 #include <ccan/tap/tap.h>
10 static tdb_len_t free_record_length(struct tdb_context *tdb, tdb_off_t off)
12 struct tdb_free_record f;
14 if (tdb_read_convert(tdb, off, &f, sizeof(f)) != 0)
16 if (frec_magic(&f) != TDB_FREE_MAGIC)
21 int main(int argc, char *argv[])
23 tdb_off_t b_off, zone_off;
24 struct tdb_context *tdb;
25 struct tdb_layout *layout;
26 struct tdb_data data, key;
28 unsigned int zone_bits = 16;
30 /* FIXME: Test TDB_CONVERT */
33 data.dptr = (void *)"world";
35 key.dptr = (void *)"hello";
38 /* No coalescing can be done due to EOF */
39 layout = new_tdb_layout();
40 tdb_layout_add_zone(layout, zone_bits, false);
41 tdb_layout_add_hashtable(layout, 12, 0);
42 tdb = tdb_layout_get(layout);
43 len = layout->elem[2].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[2].base.off) == len);
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[2].base.off,
54 tdb_unlock_free_bucket(tdb, b_off);
55 tdb_unlock_list(tdb, 0, F_WRLCK);
56 ok1(free_record_length(tdb, layout->elem[2].base.off) == len);
57 ok1(tdb_check(tdb, NULL, NULL) == 0);
60 /* No coalescing can be done due to used record */
61 layout = new_tdb_layout();
62 tdb_layout_add_zone(layout, zone_bits, false);
63 tdb_layout_add_hashtable(layout, 12, 0);
64 tdb_layout_add_free(layout, 1024);
65 tdb_layout_add_used(layout, key, data, 6);
66 tdb = tdb_layout_get(layout);
67 zone_off = layout->elem[0].base.off;
68 ok1(free_record_length(tdb, layout->elem[2].base.off) == 1024);
69 ok1(tdb_check(tdb, NULL, NULL) == 0);
71 /* Figure out which bucket free entry is. */
72 b_off = bucket_off(zone_off, size_to_bucket(zone_bits, 1024));
73 /* Lock and fail to coalesce. */
74 ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0);
75 ok1(coalesce(tdb, zone_off, zone_bits, layout->elem[2].base.off,
77 tdb_unlock_free_bucket(tdb, b_off);
78 ok1(free_record_length(tdb, layout->elem[2].base.off) == 1024);
79 ok1(tdb_check(tdb, NULL, NULL) == 0);
82 /* Coalescing can be done due to two free records, then EOF */
83 layout = new_tdb_layout();
84 tdb_layout_add_zone(layout, zone_bits, false);
85 tdb_layout_add_hashtable(layout, 12, 0);
86 tdb_layout_add_free(layout, 1024);
87 tdb = tdb_layout_get(layout);
88 zone_off = layout->elem[0].base.off;
89 len = layout->elem[3].free.len;
90 ok1(free_record_length(tdb, layout->elem[2].base.off) == 1024);
91 ok1(free_record_length(tdb, layout->elem[3].base.off) == len);
92 ok1(tdb_check(tdb, NULL, NULL) == 0);
94 /* Figure out which bucket (first) free entry is. */
95 b_off = bucket_off(zone_off, size_to_bucket(zone_bits, 1024));
96 /* Lock and coalesce. */
97 ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0);
98 ok1(coalesce(tdb, zone_off, zone_bits, layout->elem[2].base.off,
100 ok1(!tdb_has_locks(tdb));
101 ok1(free_record_length(tdb, layout->elem[2].base.off)
102 == 1024 + sizeof(struct tdb_used_record) + len);
103 ok1(tdb_check(tdb, NULL, NULL) == 0);
106 /* Coalescing can be done due to two free records, then data */
107 layout = new_tdb_layout();
108 tdb_layout_add_zone(layout, zone_bits, false);
109 tdb_layout_add_hashtable(layout, 12, 0);
110 tdb_layout_add_free(layout, 1024);
111 tdb_layout_add_free(layout, 512);
112 tdb_layout_add_used(layout, key, data, 6);
113 tdb = tdb_layout_get(layout);
114 zone_off = layout->elem[0].base.off;
115 ok1(free_record_length(tdb, layout->elem[2].base.off) == 1024);
116 ok1(free_record_length(tdb, layout->elem[3].base.off) == 512);
117 ok1(tdb_check(tdb, NULL, NULL) == 0);
119 /* Figure out which bucket free entry is. */
120 b_off = bucket_off(zone_off, size_to_bucket(zone_bits, 1024));
121 /* Lock and coalesce. */
122 ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0);
123 ok1(coalesce(tdb, zone_off, zone_bits, layout->elem[2].base.off,
125 ok1(!tdb_has_locks(tdb));
126 ok1(free_record_length(tdb, layout->elem[2].base.off)
127 == 1024 + sizeof(struct tdb_used_record) + 512);
128 ok1(tdb_check(tdb, NULL, NULL) == 0);
131 /* Coalescing can be done due to three free records, then EOF */
132 layout = new_tdb_layout();
133 tdb_layout_add_zone(layout, zone_bits, false);
134 tdb_layout_add_hashtable(layout, 12, 0);
135 tdb_layout_add_free(layout, 1024);
136 tdb_layout_add_free(layout, 512);
137 tdb = tdb_layout_get(layout);
138 zone_off = layout->elem[0].base.off;
139 len = layout->elem[4].free.len;
140 ok1(free_record_length(tdb, layout->elem[2].base.off) == 1024);
141 ok1(free_record_length(tdb, layout->elem[3].base.off) == 512);
142 ok1(free_record_length(tdb, layout->elem[4].base.off) == len);
143 ok1(tdb_check(tdb, NULL, NULL) == 0);
145 /* Figure out which bucket free entry is. */
146 b_off = bucket_off(zone_off, size_to_bucket(zone_bits, 1024));
147 /* Lock and coalesce. */
148 ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0);
149 ok1(coalesce(tdb, zone_off, zone_bits, layout->elem[2].base.off,
151 ok1(!tdb_has_locks(tdb));
152 ok1(free_record_length(tdb, layout->elem[2].base.off)
153 == 1024 + sizeof(struct tdb_used_record) + 512
154 + sizeof(struct tdb_used_record) + len);
155 ok1(tdb_check(tdb, NULL, NULL) == 0);
158 /* Coalescing across two zones isn't possible. */
159 layout = new_tdb_layout();
160 tdb_layout_add_zone(layout, zone_bits, false);
161 tdb_layout_add_hashtable(layout, 12, 0);
162 tdb_layout_add_zone(layout, zone_bits, true);
163 tdb = tdb_layout_get(layout);
164 zone_off = layout->elem[0].base.off;
165 len = layout->elem[2].free.len;
166 ok1(free_record_length(tdb, layout->elem[2].base.off) == len);
167 ok1(tdb_check(tdb, NULL, NULL) == 0);
169 /* Figure out which list free entry is. */
170 b_off = bucket_off(zone_off, size_to_bucket(zone_bits, len));
171 /* Lock and coalesce. */
172 ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0);
173 ok1(coalesce(tdb, zone_off, zone_bits, layout->elem[2].base.off,
175 tdb_unlock_free_bucket(tdb, b_off);
176 ok1(!tdb_has_locks(tdb));
177 ok1(free_record_length(tdb, layout->elem[2].base.off) == len);
178 ok1(tdb_check(tdb, NULL, NULL) == 0);
181 ok1(tap_log_messages == 0);
182 return exit_status();