s3:registry: do not use regdb functions during db upgrade
[Samba/gebeck_regimport.git] / lib / tdb2 / test / run-04-basichash.c
blob3bf66c720f5914d6523e60e5e3994fa6b3dad966
1 #include "tdb2-source.h"
2 #include <ccan/tap/tap.h>
3 #include "logging.h"
5 /* We rig the hash so adjacent-numbered records always clash. */
6 static uint64_t clash(const void *key, size_t len, uint64_t seed, void *priv)
8 return ((uint64_t)*(const unsigned int *)key)
9 << (64 - TDB_TOPLEVEL_HASH_BITS - 1);
12 int main(int argc, char *argv[])
14 unsigned int i, j;
15 struct tdb_context *tdb;
16 unsigned int v;
17 struct tdb_used_record rec;
18 struct tdb_data key = { (unsigned char *)&v, sizeof(v) };
19 struct tdb_data dbuf = { (unsigned char *)&v, sizeof(v) };
20 union tdb_attribute hattr = { .hash = { .base = { TDB_ATTRIBUTE_HASH },
21 .fn = clash } };
22 int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
23 TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
24 TDB_NOMMAP|TDB_CONVERT,
27 hattr.base.next = &tap_log_attr;
29 plan_tests(sizeof(flags) / sizeof(flags[0])
30 * (91 + (2 * ((1 << TDB_HASH_GROUP_BITS) - 1))) + 1);
31 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
32 struct hash_info h;
33 tdb_off_t new_off, off, subhash;
35 tdb = tdb_open("run-04-basichash.tdb", flags[i],
36 O_RDWR|O_CREAT|O_TRUNC, 0600, &hattr);
37 ok1(tdb);
38 if (!tdb)
39 continue;
41 v = 0;
42 /* Should not find it. */
43 ok1(find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL) == 0);
44 /* Should have created correct hash. */
45 ok1(h.h == tdb_hash(tdb, key.dptr, key.dsize));
46 /* Should have located space in group 0, bucket 0. */
47 ok1(h.group_start == offsetof(struct tdb_header, hashtable));
48 ok1(h.home_bucket == 0);
49 ok1(h.found_bucket == 0);
50 ok1(h.hash_used == TDB_TOPLEVEL_HASH_BITS);
52 /* Should have lock on bucket 0 */
53 ok1(h.hlock_start == 0);
54 ok1(h.hlock_range ==
55 1ULL << (64-(TDB_TOPLEVEL_HASH_BITS-TDB_HASH_GROUP_BITS)));
56 ok1((tdb->flags & TDB_NOLOCK) || tdb->file->num_lockrecs == 1);
57 ok1((tdb->flags & TDB_NOLOCK)
58 || tdb->file->lockrecs[0].off == TDB_HASH_LOCK_START);
59 /* FIXME: Check lock length */
61 /* Allocate a new record. */
62 new_off = alloc(tdb, key.dsize, dbuf.dsize, h.h,
63 TDB_USED_MAGIC, false);
64 ok1(!TDB_OFF_IS_ERR(new_off));
66 /* We should be able to add it now. */
67 ok1(add_to_hash(tdb, &h, new_off) == 0);
69 /* Make sure we fill it in for later finding. */
70 off = new_off + sizeof(struct tdb_used_record);
71 ok1(!tdb->tdb2.io->twrite(tdb, off, key.dptr, key.dsize));
72 off += key.dsize;
73 ok1(!tdb->tdb2.io->twrite(tdb, off, dbuf.dptr, dbuf.dsize));
75 /* We should be able to unlock that OK. */
76 ok1(tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range,
77 F_WRLCK) == 0);
79 /* Database should be consistent. */
80 ok1(tdb_check(tdb, NULL, NULL) == 0);
82 /* Now, this should give a successful lookup. */
83 ok1(find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL)
84 == new_off);
85 /* Should have created correct hash. */
86 ok1(h.h == tdb_hash(tdb, key.dptr, key.dsize));
87 /* Should have located space in group 0, bucket 0. */
88 ok1(h.group_start == offsetof(struct tdb_header, hashtable));
89 ok1(h.home_bucket == 0);
90 ok1(h.found_bucket == 0);
91 ok1(h.hash_used == TDB_TOPLEVEL_HASH_BITS);
93 /* Should have lock on bucket 0 */
94 ok1(h.hlock_start == 0);
95 ok1(h.hlock_range ==
96 1ULL << (64-(TDB_TOPLEVEL_HASH_BITS-TDB_HASH_GROUP_BITS)));
97 ok1((tdb->flags & TDB_NOLOCK) || tdb->file->num_lockrecs == 1);
98 ok1((tdb->flags & TDB_NOLOCK)
99 || tdb->file->lockrecs[0].off == TDB_HASH_LOCK_START);
100 /* FIXME: Check lock length */
102 ok1(tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range,
103 F_WRLCK) == 0);
105 /* Database should be consistent. */
106 ok1(tdb_check(tdb, NULL, NULL) == 0);
108 /* Test expansion. */
109 v = 1;
110 ok1(find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL) == 0);
111 /* Should have created correct hash. */
112 ok1(h.h == tdb_hash(tdb, key.dptr, key.dsize));
113 /* Should have located space in group 0, bucket 1. */
114 ok1(h.group_start == offsetof(struct tdb_header, hashtable));
115 ok1(h.home_bucket == 0);
116 ok1(h.found_bucket == 1);
117 ok1(h.hash_used == TDB_TOPLEVEL_HASH_BITS);
119 /* Should have lock on bucket 0 */
120 ok1(h.hlock_start == 0);
121 ok1(h.hlock_range ==
122 1ULL << (64-(TDB_TOPLEVEL_HASH_BITS-TDB_HASH_GROUP_BITS)));
123 ok1((tdb->flags & TDB_NOLOCK) || tdb->file->num_lockrecs == 1);
124 ok1((tdb->flags & TDB_NOLOCK)
125 || tdb->file->lockrecs[0].off == TDB_HASH_LOCK_START);
126 /* FIXME: Check lock length */
128 /* Make it expand 0'th bucket. */
129 ok1(expand_group(tdb, &h) == 0);
130 /* First one should be subhash, next should be empty. */
131 ok1(is_subhash(h.group[0]));
132 subhash = (h.group[0] & TDB_OFF_MASK);
133 for (j = 1; j < (1 << TDB_HASH_GROUP_BITS); j++)
134 ok1(h.group[j] == 0);
136 ok1(tdb_write_convert(tdb, h.group_start,
137 h.group, sizeof(h.group)) == 0);
138 ok1(tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range,
139 F_WRLCK) == 0);
141 /* Should be happy with expansion. */
142 ok1(tdb_check(tdb, NULL, NULL) == 0);
144 /* Should be able to find it. */
145 v = 0;
146 ok1(find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL)
147 == new_off);
148 /* Should have created correct hash. */
149 ok1(h.h == tdb_hash(tdb, key.dptr, key.dsize));
150 /* Should have located space in expanded group 0, bucket 0. */
151 ok1(h.group_start == subhash + sizeof(struct tdb_used_record));
152 ok1(h.home_bucket == 0);
153 ok1(h.found_bucket == 0);
154 ok1(h.hash_used == TDB_TOPLEVEL_HASH_BITS
155 + TDB_SUBLEVEL_HASH_BITS);
157 /* Should have lock on bucket 0 */
158 ok1(h.hlock_start == 0);
159 ok1(h.hlock_range ==
160 1ULL << (64-(TDB_TOPLEVEL_HASH_BITS-TDB_HASH_GROUP_BITS)));
161 ok1((tdb->flags & TDB_NOLOCK) || tdb->file->num_lockrecs == 1);
162 ok1((tdb->flags & TDB_NOLOCK)
163 || tdb->file->lockrecs[0].off == TDB_HASH_LOCK_START);
164 /* FIXME: Check lock length */
166 /* Simple delete should work. */
167 ok1(delete_from_hash(tdb, &h) == 0);
168 ok1(add_free_record(tdb, new_off,
169 sizeof(struct tdb_used_record)
170 + rec_key_length(&rec)
171 + rec_data_length(&rec)
172 + rec_extra_padding(&rec),
173 TDB_LOCK_NOWAIT, false) == 0);
174 ok1(tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range,
175 F_WRLCK) == 0);
176 ok1(tdb_check(tdb, NULL, NULL) == 0);
178 /* Test second-level expansion: should expand 0th bucket. */
179 v = 0;
180 ok1(find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL) == 0);
181 /* Should have created correct hash. */
182 ok1(h.h == tdb_hash(tdb, key.dptr, key.dsize));
183 /* Should have located space in group 0, bucket 0. */
184 ok1(h.group_start == subhash + sizeof(struct tdb_used_record));
185 ok1(h.home_bucket == 0);
186 ok1(h.found_bucket == 0);
187 ok1(h.hash_used == TDB_TOPLEVEL_HASH_BITS+TDB_SUBLEVEL_HASH_BITS);
189 /* Should have lock on bucket 0 */
190 ok1(h.hlock_start == 0);
191 ok1(h.hlock_range ==
192 1ULL << (64-(TDB_TOPLEVEL_HASH_BITS-TDB_HASH_GROUP_BITS)));
193 ok1((tdb->flags & TDB_NOLOCK) || tdb->file->num_lockrecs == 1);
194 ok1((tdb->flags & TDB_NOLOCK)
195 || tdb->file->lockrecs[0].off == TDB_HASH_LOCK_START);
196 /* FIXME: Check lock length */
198 ok1(expand_group(tdb, &h) == 0);
199 /* First one should be subhash, next should be empty. */
200 ok1(is_subhash(h.group[0]));
201 subhash = (h.group[0] & TDB_OFF_MASK);
202 for (j = 1; j < (1 << TDB_HASH_GROUP_BITS); j++)
203 ok1(h.group[j] == 0);
204 ok1(tdb_write_convert(tdb, h.group_start,
205 h.group, sizeof(h.group)) == 0);
206 ok1(tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range,
207 F_WRLCK) == 0);
209 /* Should be happy with expansion. */
210 ok1(tdb_check(tdb, NULL, NULL) == 0);
212 ok1(find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL) == 0);
213 /* Should have created correct hash. */
214 ok1(h.h == tdb_hash(tdb, key.dptr, key.dsize));
215 /* Should have located space in group 0, bucket 0. */
216 ok1(h.group_start == subhash + sizeof(struct tdb_used_record));
217 ok1(h.home_bucket == 0);
218 ok1(h.found_bucket == 0);
219 ok1(h.hash_used == TDB_TOPLEVEL_HASH_BITS
220 + TDB_SUBLEVEL_HASH_BITS * 2);
222 /* We should be able to add it now. */
223 /* Allocate a new record. */
224 new_off = alloc(tdb, key.dsize, dbuf.dsize, h.h,
225 TDB_USED_MAGIC, false);
226 ok1(!TDB_OFF_IS_ERR(new_off));
227 ok1(add_to_hash(tdb, &h, new_off) == 0);
229 /* Make sure we fill it in for later finding. */
230 off = new_off + sizeof(struct tdb_used_record);
231 ok1(!tdb->tdb2.io->twrite(tdb, off, key.dptr, key.dsize));
232 off += key.dsize;
233 ok1(!tdb->tdb2.io->twrite(tdb, off, dbuf.dptr, dbuf.dsize));
235 /* We should be able to unlock that OK. */
236 ok1(tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range,
237 F_WRLCK) == 0);
239 /* Database should be consistent. */
240 ok1(tdb_check(tdb, NULL, NULL) == 0);
242 /* Should be able to find it. */
243 v = 0;
244 ok1(find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL)
245 == new_off);
246 /* Should have created correct hash. */
247 ok1(h.h == tdb_hash(tdb, key.dptr, key.dsize));
248 /* Should have located space in expanded group 0, bucket 0. */
249 ok1(h.group_start == subhash + sizeof(struct tdb_used_record));
250 ok1(h.home_bucket == 0);
251 ok1(h.found_bucket == 0);
252 ok1(h.hash_used == TDB_TOPLEVEL_HASH_BITS
253 + TDB_SUBLEVEL_HASH_BITS * 2);
255 tdb_close(tdb);
258 ok1(tap_log_messages == 0);
259 return exit_status();