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 (f.magic != TDB_FREE_MAGIC)
21 int main(int argc, char *argv[])
24 struct tdb_context *tdb;
25 struct tdb_layout *layout;
26 struct tdb_data data, key;
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_hashtable(layout, 12, 0);
41 tdb_layout_add_freetable(layout, 1, 16, 12, 0);
42 tdb_layout_add_free(layout, 1024);
43 tdb = tdb_layout_get(layout);
44 ok1(tdb_check(tdb, NULL, NULL) == 0);
45 ok1(free_record_length(tdb, layout->elem[2].base.off) == 1024);
47 /* Figure out which list free entry is. */
48 list = size_to_bucket(tdb, 1024);
49 /* Lock and fail to coalesce. */
50 ok1(tdb_lock_list(tdb, 0, F_WRLCK, TDB_LOCK_WAIT) == 0);
51 ok1(tdb_lock_free_list(tdb, list, TDB_LOCK_WAIT) == 0);
52 ok1(coalesce(tdb, layout->elem[2].base.off, list, 1024) == 0);
53 tdb_unlock_free_list(tdb, list);
54 tdb_unlock_list(tdb, 0, F_WRLCK);
55 ok1(free_record_length(tdb, layout->elem[2].base.off) == 1024);
56 ok1(tdb_check(tdb, NULL, NULL) == 0);
59 /* No coalescing can be done due to used record */
60 layout = new_tdb_layout();
61 tdb_layout_add_hashtable(layout, 12, 0);
62 tdb_layout_add_freetable(layout, 1, 16, 12, 0);
63 tdb_layout_add_free(layout, 1024);
64 tdb_layout_add_used(layout, key, data, 6);
65 tdb = tdb_layout_get(layout);
66 ok1(free_record_length(tdb, layout->elem[2].base.off) == 1024);
67 ok1(tdb_check(tdb, NULL, NULL) == 0);
69 /* Figure out which list free entry is. */
70 list = size_to_bucket(tdb, 1024);
71 /* Lock and fail to coalesce. */
72 ok1(tdb_lock_list(tdb, 0, F_WRLCK, TDB_LOCK_WAIT) == 0);
73 ok1(tdb_lock_free_list(tdb, list, TDB_LOCK_WAIT) == 0);
74 ok1(coalesce(tdb, layout->elem[2].base.off, list, 1024) == 0);
75 tdb_unlock_free_list(tdb, list);
76 tdb_unlock_list(tdb, 0, F_WRLCK);
77 ok1(free_record_length(tdb, layout->elem[2].base.off) == 1024);
78 ok1(tdb_check(tdb, NULL, NULL) == 0);
81 /* Coalescing can be done due to two free records, then EOF */
82 layout = new_tdb_layout();
83 tdb_layout_add_hashtable(layout, 12, 0);
84 tdb_layout_add_freetable(layout, 1, 16, 12, 0);
85 tdb_layout_add_free(layout, 1024);
86 tdb_layout_add_free(layout, 512);
87 tdb = tdb_layout_get(layout);
88 ok1(free_record_length(tdb, layout->elem[2].base.off) == 1024);
89 ok1(free_record_length(tdb, layout->elem[3].base.off) == 512);
90 ok1(tdb_check(tdb, NULL, NULL) == 0);
92 /* Figure out which list free entry is. */
93 list = size_to_bucket(tdb, 1024);
94 /* Lock and coalesce. */
95 ok1(tdb_lock_list(tdb, 0, F_WRLCK, TDB_LOCK_WAIT) == 0);
96 ok1(tdb_lock_free_list(tdb, list, TDB_LOCK_WAIT) == 0);
97 ok1(coalesce(tdb, layout->elem[2].base.off, list, 1024) == 1);
98 tdb_unlock_list(tdb, 0, F_WRLCK);
99 ok1(!tdb_has_locks(tdb));
100 ok1(free_record_length(tdb, layout->elem[2].base.off)
101 == 1024 + sizeof(struct tdb_used_record) + 512);
102 ok1(tdb_check(tdb, NULL, NULL) == 0);
105 /* Coalescing can be done due to two free records, then data */
106 layout = new_tdb_layout();
107 tdb_layout_add_hashtable(layout, 12, 0);
108 tdb_layout_add_freetable(layout, 1, 16, 12, 0);
109 tdb_layout_add_free(layout, 1024);
110 tdb_layout_add_free(layout, 512);
111 tdb_layout_add_used(layout, key, data, 6);
112 tdb = tdb_layout_get(layout);
113 ok1(free_record_length(tdb, layout->elem[2].base.off) == 1024);
114 ok1(free_record_length(tdb, layout->elem[3].base.off) == 512);
115 ok1(tdb_check(tdb, NULL, NULL) == 0);
117 /* Figure out which list free entry is. */
118 list = size_to_bucket(tdb, 1024);
119 /* Lock and coalesce. */
120 ok1(tdb_lock_list(tdb, 0, F_WRLCK, TDB_LOCK_WAIT) == 0);
121 ok1(tdb_lock_free_list(tdb, list, TDB_LOCK_WAIT) == 0);
122 ok1(coalesce(tdb, layout->elem[2].base.off, list, 1024) == 1);
123 tdb_unlock_list(tdb, 0, F_WRLCK);
124 ok1(!tdb_has_locks(tdb));
125 ok1(free_record_length(tdb, layout->elem[2].base.off)
126 == 1024 + sizeof(struct tdb_used_record) + 512);
127 ok1(tdb_check(tdb, NULL, NULL) == 0);
130 /* Coalescing can be done due to three free records, then EOF */
131 layout = new_tdb_layout();
132 tdb_layout_add_hashtable(layout, 12, 0);
133 tdb_layout_add_freetable(layout, 1, 16, 12, 0);
134 tdb_layout_add_free(layout, 1024);
135 tdb_layout_add_free(layout, 512);
136 tdb_layout_add_free(layout, 32);
137 tdb = tdb_layout_get(layout);
138 ok1(free_record_length(tdb, layout->elem[2].base.off) == 1024);
139 ok1(free_record_length(tdb, layout->elem[3].base.off) == 512);
140 ok1(free_record_length(tdb, layout->elem[4].base.off) == 32);
141 ok1(tdb_check(tdb, NULL, NULL) == 0);
143 /* Figure out which list free entry is. */
144 list = size_to_bucket(tdb, 1024);
145 /* Lock and coalesce. */
146 ok1(tdb_lock_list(tdb, 0, F_WRLCK, TDB_LOCK_WAIT) == 0);
147 ok1(tdb_lock_free_list(tdb, list, TDB_LOCK_WAIT) == 0);
148 ok1(coalesce(tdb, layout->elem[2].base.off, list, 1024) == 1);
149 tdb_unlock_list(tdb, 0, F_WRLCK);
150 ok1(!tdb_has_locks(tdb));
151 ok1(free_record_length(tdb, layout->elem[2].base.off)
152 == 1024 + sizeof(struct tdb_used_record) + 512
153 + sizeof(struct tdb_used_record) + 32);
154 ok1(tdb_check(tdb, NULL, NULL) == 0);
157 /* Coalescing across two zones. */
158 layout = new_tdb_layout();
159 tdb_layout_add_hashtable(layout, 12, 0);
160 tdb_layout_add_freetable(layout, 2, 16, 12, 0);
161 tdb_layout_add_free(layout, 32768);
162 tdb_layout_add_free(layout, 30000);
163 tdb = tdb_layout_get(layout);
164 ok1(free_record_length(tdb, layout->elem[2].base.off) == 32768);
165 ok1(zone_of(tdb, layout->elem[2].base.off) == 0);
166 ok1(free_record_length(tdb, layout->elem[3].base.off) == 30000);
167 ok1(zone_of(tdb, layout->elem[3].base.off) == 1);
168 ok1(tdb_check(tdb, NULL, NULL) == 0);
170 /* Figure out which list free entry is. */
171 list = size_to_bucket(tdb, 32768);
172 /* Lock and coalesce. */
173 ok1(tdb_lock_list(tdb, 0, F_WRLCK, TDB_LOCK_WAIT) == 0);
174 ok1(tdb_lock_free_list(tdb, list, TDB_LOCK_WAIT) == 0);
175 ok1(coalesce(tdb, layout->elem[2].base.off, list, 32768) == 1);
176 tdb_unlock_list(tdb, 0, F_WRLCK);
177 ok1(!tdb_has_locks(tdb));
178 ok1(free_record_length(tdb, layout->elem[2].base.off)
179 == 32768 + sizeof(struct tdb_used_record) + 30000);
180 ok1(tdb_check(tdb, NULL, NULL) == 0);
183 /* Coalescing many across many zones. */
184 layout = new_tdb_layout();
185 tdb_layout_add_hashtable(layout, 12, 0);
186 tdb_layout_add_freetable(layout, 8, 16, 12, 0);
188 for (i = 4; i < 16; i++) {
189 tdb_layout_add_free(layout, 1 << i);
190 total += sizeof(struct tdb_used_record) + (1 << i);
192 total -= sizeof(struct tdb_used_record);
193 tdb = tdb_layout_get(layout);
194 ok1(free_record_length(tdb, layout->elem[2].base.off) == 1 << 4);
195 ok1(tdb_check(tdb, NULL, NULL) == 0);
197 /* Figure out which list free entry is. */
198 list = size_to_bucket(tdb, 1 << 4);
199 /* Lock and coalesce. */
200 ok1(tdb_lock_list(tdb, 0, F_WRLCK, TDB_LOCK_WAIT) == 0);
201 ok1(tdb_lock_free_list(tdb, list, TDB_LOCK_WAIT) == 0);
202 ok1(coalesce(tdb, layout->elem[2].base.off, list, 1 << 4) == 1);
203 tdb_unlock_list(tdb, 0, F_WRLCK);
204 ok1(!tdb_has_locks(tdb));
205 ok1(free_record_length(tdb, layout->elem[2].base.off) == total);
206 ok1(tdb_check(tdb, NULL, NULL) == 0);
209 ok1(tap_log_messages == 0);
210 return exit_status();