VERSION: Bump version number up to 4.1.3...
[Samba.git] / lib / ntdb / test / run-04-basichash.c
blob9888f6e551db6511955b97cb6cc564afab73aa98
1 #include "ntdb-source.h"
2 #include "tap-interface.h"
3 #include "logging.h"
5 /* We rig the hash so all records clash. */
6 static uint32_t clash(const void *key, size_t len, uint32_t seed, void *priv)
8 return *((const unsigned int *)key) << 20;
11 int main(int argc, char *argv[])
13 unsigned int i;
14 struct ntdb_context *ntdb;
15 unsigned int v;
16 struct ntdb_used_record rec;
17 NTDB_DATA key = { (unsigned char *)&v, sizeof(v) };
18 NTDB_DATA dbuf = { (unsigned char *)&v, sizeof(v) };
19 union ntdb_attribute hattr = { .hash = { .base = { NTDB_ATTRIBUTE_HASH },
20 .fn = clash } };
21 int flags[] = { NTDB_INTERNAL, NTDB_DEFAULT, NTDB_NOMMAP,
22 NTDB_INTERNAL|NTDB_CONVERT, NTDB_CONVERT,
23 NTDB_NOMMAP|NTDB_CONVERT,
26 hattr.base.next = &tap_log_attr;
28 plan_tests(sizeof(flags) / sizeof(flags[0]) * 137 + 1);
29 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
30 struct hash_info h;
31 ntdb_off_t new_off, new_off2, off;
33 ntdb = ntdb_open("run-04-basichash.ntdb", flags[i]|MAYBE_NOSYNC,
34 O_RDWR|O_CREAT|O_TRUNC, 0600, &hattr);
35 ok1(ntdb);
36 if (!ntdb)
37 continue;
39 v = 0;
40 /* Should not find it. */
41 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
42 /* Should have created correct hash. */
43 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
44 /* Should have located space in top table, bucket 0. */
45 ok1(h.table == NTDB_HASH_OFFSET);
46 ok1(h.table_size == (1 << ntdb->hash_bits));
47 ok1(h.bucket == 0);
48 ok1(h.old_val == 0);
50 /* Should have lock on bucket 0 */
51 ok1(h.h == 0);
52 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
53 ok1((ntdb->flags & NTDB_NOLOCK)
54 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
55 /* FIXME: Check lock length */
57 /* Allocate a new record. */
58 new_off = alloc(ntdb, key.dsize, dbuf.dsize,
59 NTDB_USED_MAGIC, false);
60 ok1(!NTDB_OFF_IS_ERR(new_off));
62 /* We should be able to add it now. */
63 ok1(add_to_hash(ntdb, &h, new_off) == 0);
65 /* Make sure we fill it in for later finding. */
66 off = new_off + sizeof(struct ntdb_used_record);
67 ok1(!ntdb->io->twrite(ntdb, off, key.dptr, key.dsize));
68 off += key.dsize;
69 ok1(!ntdb->io->twrite(ntdb, off, dbuf.dptr, dbuf.dsize));
71 /* We should be able to unlock that OK. */
72 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
74 /* Database should be consistent. */
75 ok1(ntdb_check(ntdb, NULL, NULL) == 0);
77 /* Now, this should give a successful lookup. */
78 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off);
79 /* Should have created correct hash. */
80 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
81 /* Should have located it in top table, bucket 0. */
82 ok1(h.table == NTDB_HASH_OFFSET);
83 ok1(h.table_size == (1 << ntdb->hash_bits));
84 ok1(h.bucket == 0);
86 /* Should have lock on bucket 0 */
87 ok1(h.h == 0);
88 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
89 ok1((ntdb->flags & NTDB_NOLOCK)
90 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
91 /* FIXME: Check lock length */
93 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
95 /* Database should be consistent. */
96 ok1(ntdb_check(ntdb, NULL, NULL) == 0);
98 /* Test expansion. */
99 v = 1;
100 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
101 /* Should have created correct hash. */
102 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
103 /* Should have located clash in toplevel bucket 0. */
104 ok1(h.table == NTDB_HASH_OFFSET);
105 ok1(h.table_size == (1 << ntdb->hash_bits));
106 ok1(h.bucket == 0);
107 ok1((h.old_val & NTDB_OFF_MASK) == new_off);
109 /* Should have lock on bucket 0 */
110 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
111 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
112 ok1((ntdb->flags & NTDB_NOLOCK)
113 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
114 /* FIXME: Check lock length */
116 new_off2 = alloc(ntdb, key.dsize, dbuf.dsize,
117 NTDB_USED_MAGIC, false);
118 ok1(!NTDB_OFF_IS_ERR(new_off2));
120 off = new_off2 + sizeof(struct ntdb_used_record);
121 ok1(!ntdb->io->twrite(ntdb, off, key.dptr, key.dsize));
122 off += key.dsize;
123 ok1(!ntdb->io->twrite(ntdb, off, dbuf.dptr, dbuf.dsize));
125 /* We should be able to add it now. */
126 ok1(add_to_hash(ntdb, &h, new_off2) == 0);
127 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
129 /* Should be happy with expansion. */
130 ok1(ntdb_check(ntdb, NULL, NULL) == 0);
132 /* Should be able to find both. */
133 v = 1;
134 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off2);
135 /* Should have created correct hash. */
136 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
137 /* Should have located space in chain. */
138 ok1(h.table > NTDB_HASH_OFFSET);
139 ok1(h.table_size == 2);
140 ok1(h.bucket == 1);
141 /* Should have lock on bucket 0 */
142 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
143 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
144 ok1((ntdb->flags & NTDB_NOLOCK)
145 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
146 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
148 v = 0;
149 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off);
150 /* Should have created correct hash. */
151 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
152 /* Should have located space in chain. */
153 ok1(h.table > NTDB_HASH_OFFSET);
154 ok1(h.table_size == 2);
155 ok1(h.bucket == 0);
157 /* Should have lock on bucket 0 */
158 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
159 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
160 ok1((ntdb->flags & NTDB_NOLOCK)
161 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
162 /* FIXME: Check lock length */
164 /* Simple delete should work. */
165 ok1(delete_from_hash(ntdb, &h) == 0);
166 ok1(add_free_record(ntdb, new_off,
167 sizeof(struct ntdb_used_record)
168 + rec_key_length(&rec)
169 + rec_data_length(&rec)
170 + rec_extra_padding(&rec),
171 NTDB_LOCK_NOWAIT, false) == 0);
172 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
173 ok1(ntdb_check(ntdb, NULL, NULL) == 0);
175 /* Should still be able to find other record. */
176 v = 1;
177 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off2);
178 /* Should have created correct hash. */
179 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
180 /* Should have located space in chain. */
181 ok1(h.table > NTDB_HASH_OFFSET);
182 ok1(h.table_size == 2);
183 ok1(h.bucket == 1);
184 /* Should have lock on bucket 0 */
185 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
186 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
187 ok1((ntdb->flags & NTDB_NOLOCK)
188 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
189 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
191 /* Now should find empty space. */
192 v = 0;
193 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
194 /* Should have created correct hash. */
195 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
196 /* Should have located space in chain, bucket 0. */
197 ok1(h.table > NTDB_HASH_OFFSET);
198 ok1(h.table_size == 2);
199 ok1(h.bucket == 0);
200 ok1(h.old_val == 0);
202 /* Adding another record should work. */
203 v = 2;
204 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
205 /* Should have created correct hash. */
206 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
207 /* Should have located space in chain, bucket 0. */
208 ok1(h.table > NTDB_HASH_OFFSET);
209 ok1(h.table_size == 2);
210 ok1(h.bucket == 0);
211 ok1(h.old_val == 0);
213 /* Should have lock on bucket 0 */
214 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
215 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
216 ok1((ntdb->flags & NTDB_NOLOCK)
217 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
219 new_off = alloc(ntdb, key.dsize, dbuf.dsize,
220 NTDB_USED_MAGIC, false);
221 ok1(!NTDB_OFF_IS_ERR(new_off2));
222 ok1(add_to_hash(ntdb, &h, new_off) == 0);
223 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
225 off = new_off + sizeof(struct ntdb_used_record);
226 ok1(!ntdb->io->twrite(ntdb, off, key.dptr, key.dsize));
227 off += key.dsize;
228 ok1(!ntdb->io->twrite(ntdb, off, dbuf.dptr, dbuf.dsize));
230 /* Adding another record should cause expansion. */
231 v = 3;
232 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
233 /* Should have created correct hash. */
234 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
235 /* Should not have located space in chain. */
236 ok1(h.table > NTDB_HASH_OFFSET);
237 ok1(h.table_size == 2);
238 ok1(h.bucket == 2);
239 ok1(h.old_val != 0);
241 /* Should have lock on bucket 0 */
242 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
243 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
244 ok1((ntdb->flags & NTDB_NOLOCK)
245 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
247 new_off = alloc(ntdb, key.dsize, dbuf.dsize,
248 NTDB_USED_MAGIC, false);
249 ok1(!NTDB_OFF_IS_ERR(new_off2));
250 off = new_off + sizeof(struct ntdb_used_record);
251 ok1(!ntdb->io->twrite(ntdb, off, key.dptr, key.dsize));
252 off += key.dsize;
253 ok1(!ntdb->io->twrite(ntdb, off, dbuf.dptr, dbuf.dsize));
254 ok1(add_to_hash(ntdb, &h, new_off) == 0);
255 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
257 /* Retrieve it and check. */
258 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off);
259 /* Should have created correct hash. */
260 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
261 /* Should have appended to chain, bucket 2. */
262 ok1(h.table > NTDB_HASH_OFFSET);
263 ok1(h.table_size == 3);
264 ok1(h.bucket == 2);
266 /* Should have lock on bucket 0 */
267 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
268 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
269 ok1((ntdb->flags & NTDB_NOLOCK)
270 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
271 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
273 /* YA record: relocation. */
274 v = 4;
275 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
276 /* Should have created correct hash. */
277 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
278 /* Should not have located space in chain. */
279 ok1(h.table > NTDB_HASH_OFFSET);
280 ok1(h.table_size == 3);
281 ok1(h.bucket == 3);
282 ok1(h.old_val != 0);
284 /* Should have lock on bucket 0 */
285 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
286 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
287 ok1((ntdb->flags & NTDB_NOLOCK)
288 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
290 new_off = alloc(ntdb, key.dsize, dbuf.dsize,
291 NTDB_USED_MAGIC, false);
292 ok1(!NTDB_OFF_IS_ERR(new_off2));
293 off = new_off + sizeof(struct ntdb_used_record);
294 ok1(!ntdb->io->twrite(ntdb, off, key.dptr, key.dsize));
295 off += key.dsize;
296 ok1(!ntdb->io->twrite(ntdb, off, dbuf.dptr, dbuf.dsize));
297 ok1(add_to_hash(ntdb, &h, new_off) == 0);
298 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
300 /* Retrieve it and check. */
301 ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off);
302 /* Should have created correct hash. */
303 ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
304 /* Should have appended to chain, bucket 2. */
305 ok1(h.table > NTDB_HASH_OFFSET);
306 ok1(h.table_size == 4);
307 ok1(h.bucket == 3);
309 /* Should have lock on bucket 0 */
310 ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
311 ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
312 ok1((ntdb->flags & NTDB_NOLOCK)
313 || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
314 ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
316 ntdb_close(ntdb);
319 ok1(tap_log_messages == 0);
320 return exit_status();