1 #include "ntdb-source.h"
2 #include "tap-interface.h"
4 #include "helprun-external-agent.h"
6 /* We rig the hash so all records clash. */
7 static uint32_t clash(const void *key, size_t len, uint32_t seed, void *priv)
9 return *((const unsigned int *)key) << 20;
12 int main(int argc, char *argv[])
15 struct ntdb_context *ntdb;
17 struct ntdb_used_record rec;
18 NTDB_DATA key = { (unsigned char *)&v, sizeof(v) };
19 NTDB_DATA dbuf = { (unsigned char *)&v, sizeof(v) };
20 union ntdb_attribute hattr = { .hash = { .base = { NTDB_ATTRIBUTE_HASH },
22 int flags[] = { NTDB_INTERNAL, NTDB_DEFAULT, NTDB_NOMMAP,
23 NTDB_INTERNAL|NTDB_CONVERT, NTDB_CONVERT,
24 NTDB_NOMMAP|NTDB_CONVERT,
27 hattr.base.next = &tap_log_attr;
29 plan_tests(sizeof(flags) / sizeof(flags[0]) * 137 + 1);
30 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
32 ntdb_off_t new_off, new_off2, off;
34 ntdb = ntdb_open("run-04-basichash.ntdb", flags[i]|MAYBE_NOSYNC,
35 O_RDWR|O_CREAT|O_TRUNC, 0600, &hattr);
41 /* Should not find it. */
42 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
43 /* Should have created correct hash. */
44 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
45 /* Should have located space in top table, bucket 0. */
46 ok1(h.table == NTDB_HASH_OFFSET);
47 ok1(h.table_size == (1 << ntdb->hash_bits));
51 /* Should have lock on bucket 0 */
53 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
54 ok1((ntdb->flags & NTDB_NOLOCK)
55 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
56 /* FIXME: Check lock length */
58 /* Allocate a new record. */
59 new_off = alloc(ntdb, key.dsize, dbuf.dsize,
60 NTDB_USED_MAGIC, false);
61 ok1(!NTDB_OFF_IS_ERR(new_off));
63 /* We should be able to add it now. */
64 ok1(add_to_hash(ntdb, &h, new_off) == 0);
66 /* Make sure we fill it in for later finding. */
67 off = new_off + sizeof(struct ntdb_used_record);
68 ok1(!ntdb->io->twrite(ntdb, off, key.dptr, key.dsize));
70 ok1(!ntdb->io->twrite(ntdb, off, dbuf.dptr, dbuf.dsize));
72 /* We should be able to unlock that OK. */
73 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
75 /* Database should be consistent. */
76 ok1(ntdb_check(ntdb, NULL, NULL) == 0);
78 /* Now, this should give a successful lookup. */
79 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off);
80 /* Should have created correct hash. */
81 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
82 /* Should have located it in top table, bucket 0. */
83 ok1(h.table == NTDB_HASH_OFFSET);
84 ok1(h.table_size == (1 << ntdb->hash_bits));
87 /* Should have lock on bucket 0 */
89 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
90 ok1((ntdb->flags & NTDB_NOLOCK)
91 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
92 /* FIXME: Check lock length */
94 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
96 /* Database should be consistent. */
97 ok1(ntdb_check(ntdb, NULL, NULL) == 0);
101 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
102 /* Should have created correct hash. */
103 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
104 /* Should have located clash in toplevel bucket 0. */
105 ok1(h.table == NTDB_HASH_OFFSET);
106 ok1(h.table_size == (1 << ntdb->hash_bits));
108 ok1((h.old_val & NTDB_OFF_MASK) == new_off);
110 /* Should have lock on bucket 0 */
111 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
112 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
113 ok1((ntdb->flags & NTDB_NOLOCK)
114 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
115 /* FIXME: Check lock length */
117 new_off2 = alloc(ntdb, key.dsize, dbuf.dsize,
118 NTDB_USED_MAGIC, false);
119 ok1(!NTDB_OFF_IS_ERR(new_off2));
121 off = new_off2 + sizeof(struct ntdb_used_record);
122 ok1(!ntdb->io->twrite(ntdb, off, key.dptr, key.dsize));
124 ok1(!ntdb->io->twrite(ntdb, off, dbuf.dptr, dbuf.dsize));
126 /* We should be able to add it now. */
127 ok1(add_to_hash(ntdb, &h, new_off2) == 0);
128 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
130 /* Should be happy with expansion. */
131 ok1(ntdb_check(ntdb, NULL, NULL) == 0);
133 /* Should be able to find both. */
135 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off2);
136 /* Should have created correct hash. */
137 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
138 /* Should have located space in chain. */
139 ok1(h.table > NTDB_HASH_OFFSET);
140 ok1(h.table_size == 2);
142 /* Should have lock on bucket 0 */
143 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
144 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
145 ok1((ntdb->flags & NTDB_NOLOCK)
146 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
147 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
150 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off);
151 /* Should have created correct hash. */
152 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
153 /* Should have located space in chain. */
154 ok1(h.table > NTDB_HASH_OFFSET);
155 ok1(h.table_size == 2);
158 /* Should have lock on bucket 0 */
159 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
160 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
161 ok1((ntdb->flags & NTDB_NOLOCK)
162 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
163 /* FIXME: Check lock length */
165 /* Simple delete should work. */
166 ok1(delete_from_hash(ntdb, &h) == 0);
167 ok1(add_free_record(ntdb, new_off,
168 sizeof(struct ntdb_used_record)
169 + rec_key_length(&rec)
170 + rec_data_length(&rec)
171 + rec_extra_padding(&rec),
172 NTDB_LOCK_NOWAIT, false) == 0);
173 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
174 ok1(ntdb_check(ntdb, NULL, NULL) == 0);
176 /* Should still be able to find other record. */
178 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off2);
179 /* Should have created correct hash. */
180 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
181 /* Should have located space in chain. */
182 ok1(h.table > NTDB_HASH_OFFSET);
183 ok1(h.table_size == 2);
185 /* Should have lock on bucket 0 */
186 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
187 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
188 ok1((ntdb->flags & NTDB_NOLOCK)
189 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
190 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
192 /* Now should find empty space. */
194 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
195 /* Should have created correct hash. */
196 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
197 /* Should have located space in chain, bucket 0. */
198 ok1(h.table > NTDB_HASH_OFFSET);
199 ok1(h.table_size == 2);
203 /* Adding another record should work. */
205 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
206 /* Should have created correct hash. */
207 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
208 /* Should have located space in chain, bucket 0. */
209 ok1(h.table > NTDB_HASH_OFFSET);
210 ok1(h.table_size == 2);
214 /* Should have lock on bucket 0 */
215 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
216 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
217 ok1((ntdb->flags & NTDB_NOLOCK)
218 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
220 new_off = alloc(ntdb, key.dsize, dbuf.dsize,
221 NTDB_USED_MAGIC, false);
222 ok1(!NTDB_OFF_IS_ERR(new_off2));
223 ok1(add_to_hash(ntdb, &h, new_off) == 0);
224 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
226 off = new_off + sizeof(struct ntdb_used_record);
227 ok1(!ntdb->io->twrite(ntdb, off, key.dptr, key.dsize));
229 ok1(!ntdb->io->twrite(ntdb, off, dbuf.dptr, dbuf.dsize));
231 /* Adding another record should cause expansion. */
233 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
234 /* Should have created correct hash. */
235 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
236 /* Should not have located space in chain. */
237 ok1(h.table > NTDB_HASH_OFFSET);
238 ok1(h.table_size == 2);
242 /* Should have lock on bucket 0 */
243 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
244 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
245 ok1((ntdb->flags & NTDB_NOLOCK)
246 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
248 new_off = alloc(ntdb, key.dsize, dbuf.dsize,
249 NTDB_USED_MAGIC, false);
250 ok1(!NTDB_OFF_IS_ERR(new_off2));
251 off = new_off + sizeof(struct ntdb_used_record);
252 ok1(!ntdb->io->twrite(ntdb, off, key.dptr, key.dsize));
254 ok1(!ntdb->io->twrite(ntdb, off, dbuf.dptr, dbuf.dsize));
255 ok1(add_to_hash(ntdb, &h, new_off) == 0);
256 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
258 /* Retrieve it and check. */
259 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off);
260 /* Should have created correct hash. */
261 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
262 /* Should have appended to chain, bucket 2. */
263 ok1(h.table > NTDB_HASH_OFFSET);
264 ok1(h.table_size == 3);
267 /* Should have lock on bucket 0 */
268 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
269 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
270 ok1((ntdb->flags & NTDB_NOLOCK)
271 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
272 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
274 /* YA record: relocation. */
276 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
277 /* Should have created correct hash. */
278 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
279 /* Should not have located space in chain. */
280 ok1(h.table > NTDB_HASH_OFFSET);
281 ok1(h.table_size == 3);
285 /* Should have lock on bucket 0 */
286 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
287 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
288 ok1((ntdb->flags & NTDB_NOLOCK)
289 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
291 new_off = alloc(ntdb, key.dsize, dbuf.dsize,
292 NTDB_USED_MAGIC, false);
293 ok1(!NTDB_OFF_IS_ERR(new_off2));
294 off = new_off + sizeof(struct ntdb_used_record);
295 ok1(!ntdb->io->twrite(ntdb, off, key.dptr, key.dsize));
297 ok1(!ntdb->io->twrite(ntdb, off, dbuf.dptr, dbuf.dsize));
298 ok1(add_to_hash(ntdb, &h, new_off) == 0);
299 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
301 /* Retrieve it and check. */
302 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off);
303 /* Should have created correct hash. */
304 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
305 /* Should have appended to chain, bucket 2. */
306 ok1(h.table > NTDB_HASH_OFFSET);
307 ok1(h.table_size == 4);
310 /* Should have lock on bucket 0 */
311 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
312 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
313 ok1((ntdb->flags & NTDB_NOLOCK)
314 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
315 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
320 ok1(tap_log_messages == 0);
321 return exit_status();