run-04-basichash.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. #include "ntdb-source.h"
  2. #include "tap-interface.h"
  3. #include "logging.h"
  4. #include "helprun-external-agent.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)
  7. {
  8. return *((const unsigned int *)key) << 20;
  9. }
  10. int main(int argc, char *argv[])
  11. {
  12. unsigned int i;
  13. struct ntdb_context *ntdb;
  14. unsigned int v;
  15. struct ntdb_used_record rec;
  16. NTDB_DATA key = { (unsigned char *)&v, sizeof(v) };
  17. NTDB_DATA dbuf = { (unsigned char *)&v, sizeof(v) };
  18. union ntdb_attribute hattr = { .hash = { .base = { NTDB_ATTRIBUTE_HASH },
  19. .fn = clash } };
  20. int flags[] = { NTDB_INTERNAL, NTDB_DEFAULT, NTDB_NOMMAP,
  21. NTDB_INTERNAL|NTDB_CONVERT, NTDB_CONVERT,
  22. NTDB_NOMMAP|NTDB_CONVERT,
  23. };
  24. hattr.base.next = &tap_log_attr;
  25. plan_tests(sizeof(flags) / sizeof(flags[0]) * 137 + 1);
  26. for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
  27. struct hash_info h;
  28. ntdb_off_t new_off, new_off2, off;
  29. ntdb = ntdb_open("run-04-basichash.ntdb", flags[i]|MAYBE_NOSYNC,
  30. O_RDWR|O_CREAT|O_TRUNC, 0600, &hattr);
  31. ok1(ntdb);
  32. if (!ntdb)
  33. continue;
  34. v = 0;
  35. /* Should not find it. */
  36. ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
  37. /* Should have created correct hash. */
  38. ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
  39. /* Should have located space in top table, bucket 0. */
  40. ok1(h.table == NTDB_HASH_OFFSET);
  41. ok1(h.table_size == (1 << ntdb->hash_bits));
  42. ok1(h.bucket == 0);
  43. ok1(h.old_val == 0);
  44. /* Should have lock on bucket 0 */
  45. ok1(h.h == 0);
  46. ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
  47. ok1((ntdb->flags & NTDB_NOLOCK)
  48. || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
  49. /* FIXME: Check lock length */
  50. /* Allocate a new record. */
  51. new_off = alloc(ntdb, key.dsize, dbuf.dsize,
  52. NTDB_USED_MAGIC, false);
  53. ok1(!NTDB_OFF_IS_ERR(new_off));
  54. /* We should be able to add it now. */
  55. ok1(add_to_hash(ntdb, &h, new_off) == 0);
  56. /* Make sure we fill it in for later finding. */
  57. off = new_off + sizeof(struct ntdb_used_record);
  58. ok1(!ntdb->io->twrite(ntdb, off, key.dptr, key.dsize));
  59. off += key.dsize;
  60. ok1(!ntdb->io->twrite(ntdb, off, dbuf.dptr, dbuf.dsize));
  61. /* We should be able to unlock that OK. */
  62. ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
  63. /* Database should be consistent. */
  64. ok1(ntdb_check(ntdb, NULL, NULL) == 0);
  65. /* Now, this should give a successful lookup. */
  66. ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off);
  67. /* Should have created correct hash. */
  68. ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
  69. /* Should have located it in top table, bucket 0. */
  70. ok1(h.table == NTDB_HASH_OFFSET);
  71. ok1(h.table_size == (1 << ntdb->hash_bits));
  72. ok1(h.bucket == 0);
  73. /* Should have lock on bucket 0 */
  74. ok1(h.h == 0);
  75. ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
  76. ok1((ntdb->flags & NTDB_NOLOCK)
  77. || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
  78. /* FIXME: Check lock length */
  79. ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
  80. /* Database should be consistent. */
  81. ok1(ntdb_check(ntdb, NULL, NULL) == 0);
  82. /* Test expansion. */
  83. v = 1;
  84. ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
  85. /* Should have created correct hash. */
  86. ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
  87. /* Should have located clash in toplevel bucket 0. */
  88. ok1(h.table == NTDB_HASH_OFFSET);
  89. ok1(h.table_size == (1 << ntdb->hash_bits));
  90. ok1(h.bucket == 0);
  91. ok1((h.old_val & NTDB_OFF_MASK) == new_off);
  92. /* Should have lock on bucket 0 */
  93. ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
  94. ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
  95. ok1((ntdb->flags & NTDB_NOLOCK)
  96. || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
  97. /* FIXME: Check lock length */
  98. new_off2 = alloc(ntdb, key.dsize, dbuf.dsize,
  99. NTDB_USED_MAGIC, false);
  100. ok1(!NTDB_OFF_IS_ERR(new_off2));
  101. off = new_off2 + sizeof(struct ntdb_used_record);
  102. ok1(!ntdb->io->twrite(ntdb, off, key.dptr, key.dsize));
  103. off += key.dsize;
  104. ok1(!ntdb->io->twrite(ntdb, off, dbuf.dptr, dbuf.dsize));
  105. /* We should be able to add it now. */
  106. ok1(add_to_hash(ntdb, &h, new_off2) == 0);
  107. ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
  108. /* Should be happy with expansion. */
  109. ok1(ntdb_check(ntdb, NULL, NULL) == 0);
  110. /* Should be able to find both. */
  111. v = 1;
  112. ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off2);
  113. /* Should have created correct hash. */
  114. ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
  115. /* Should have located space in chain. */
  116. ok1(h.table > NTDB_HASH_OFFSET);
  117. ok1(h.table_size == 2);
  118. ok1(h.bucket == 1);
  119. /* Should have lock on bucket 0 */
  120. ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
  121. ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
  122. ok1((ntdb->flags & NTDB_NOLOCK)
  123. || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
  124. ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
  125. v = 0;
  126. ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off);
  127. /* Should have created correct hash. */
  128. ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
  129. /* Should have located space in chain. */
  130. ok1(h.table > NTDB_HASH_OFFSET);
  131. ok1(h.table_size == 2);
  132. ok1(h.bucket == 0);
  133. /* Should have lock on bucket 0 */
  134. ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
  135. ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
  136. ok1((ntdb->flags & NTDB_NOLOCK)
  137. || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
  138. /* FIXME: Check lock length */
  139. /* Simple delete should work. */
  140. ok1(delete_from_hash(ntdb, &h) == 0);
  141. ok1(add_free_record(ntdb, new_off,
  142. sizeof(struct ntdb_used_record)
  143. + rec_key_length(&rec)
  144. + rec_data_length(&rec)
  145. + rec_extra_padding(&rec),
  146. NTDB_LOCK_NOWAIT, false) == 0);
  147. ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
  148. ok1(ntdb_check(ntdb, NULL, NULL) == 0);
  149. /* Should still be able to find other record. */
  150. v = 1;
  151. ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off2);
  152. /* Should have created correct hash. */
  153. ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
  154. /* Should have located space in chain. */
  155. ok1(h.table > NTDB_HASH_OFFSET);
  156. ok1(h.table_size == 2);
  157. ok1(h.bucket == 1);
  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. ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
  164. /* Now should find empty space. */
  165. v = 0;
  166. ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
  167. /* Should have created correct hash. */
  168. ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
  169. /* Should have located space in chain, bucket 0. */
  170. ok1(h.table > NTDB_HASH_OFFSET);
  171. ok1(h.table_size == 2);
  172. ok1(h.bucket == 0);
  173. ok1(h.old_val == 0);
  174. /* Adding another record should work. */
  175. v = 2;
  176. ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
  177. /* Should have created correct hash. */
  178. ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
  179. /* Should have located space in chain, bucket 0. */
  180. ok1(h.table > NTDB_HASH_OFFSET);
  181. ok1(h.table_size == 2);
  182. ok1(h.bucket == 0);
  183. ok1(h.old_val == 0);
  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. new_off = alloc(ntdb, key.dsize, dbuf.dsize,
  190. NTDB_USED_MAGIC, false);
  191. ok1(!NTDB_OFF_IS_ERR(new_off2));
  192. ok1(add_to_hash(ntdb, &h, new_off) == 0);
  193. ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
  194. off = new_off + sizeof(struct ntdb_used_record);
  195. ok1(!ntdb->io->twrite(ntdb, off, key.dptr, key.dsize));
  196. off += key.dsize;
  197. ok1(!ntdb->io->twrite(ntdb, off, dbuf.dptr, dbuf.dsize));
  198. /* Adding another record should cause expansion. */
  199. v = 3;
  200. ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
  201. /* Should have created correct hash. */
  202. ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
  203. /* Should not have located space in chain. */
  204. ok1(h.table > NTDB_HASH_OFFSET);
  205. ok1(h.table_size == 2);
  206. ok1(h.bucket == 2);
  207. ok1(h.old_val != 0);
  208. /* Should have lock on bucket 0 */
  209. ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
  210. ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
  211. ok1((ntdb->flags & NTDB_NOLOCK)
  212. || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
  213. new_off = alloc(ntdb, key.dsize, dbuf.dsize,
  214. NTDB_USED_MAGIC, false);
  215. ok1(!NTDB_OFF_IS_ERR(new_off2));
  216. off = new_off + sizeof(struct ntdb_used_record);
  217. ok1(!ntdb->io->twrite(ntdb, off, key.dptr, key.dsize));
  218. off += key.dsize;
  219. ok1(!ntdb->io->twrite(ntdb, off, dbuf.dptr, dbuf.dsize));
  220. ok1(add_to_hash(ntdb, &h, new_off) == 0);
  221. ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
  222. /* Retrieve it and check. */
  223. ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off);
  224. /* Should have created correct hash. */
  225. ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
  226. /* Should have appended to chain, bucket 2. */
  227. ok1(h.table > NTDB_HASH_OFFSET);
  228. ok1(h.table_size == 3);
  229. ok1(h.bucket == 2);
  230. /* Should have lock on bucket 0 */
  231. ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
  232. ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
  233. ok1((ntdb->flags & NTDB_NOLOCK)
  234. || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
  235. ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
  236. /* YA record: relocation. */
  237. v = 4;
  238. ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == 0);
  239. /* Should have created correct hash. */
  240. ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
  241. /* Should not have located space in chain. */
  242. ok1(h.table > NTDB_HASH_OFFSET);
  243. ok1(h.table_size == 3);
  244. ok1(h.bucket == 3);
  245. ok1(h.old_val != 0);
  246. /* Should have lock on bucket 0 */
  247. ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
  248. ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
  249. ok1((ntdb->flags & NTDB_NOLOCK)
  250. || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
  251. new_off = alloc(ntdb, key.dsize, dbuf.dsize,
  252. NTDB_USED_MAGIC, false);
  253. ok1(!NTDB_OFF_IS_ERR(new_off2));
  254. off = new_off + sizeof(struct ntdb_used_record);
  255. ok1(!ntdb->io->twrite(ntdb, off, key.dptr, key.dsize));
  256. off += key.dsize;
  257. ok1(!ntdb->io->twrite(ntdb, off, dbuf.dptr, dbuf.dsize));
  258. ok1(add_to_hash(ntdb, &h, new_off) == 0);
  259. ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
  260. /* Retrieve it and check. */
  261. ok1(find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL) == new_off);
  262. /* Should have created correct hash. */
  263. ok1(h.h == ntdb_hash(ntdb, key.dptr, key.dsize));
  264. /* Should have appended to chain, bucket 2. */
  265. ok1(h.table > NTDB_HASH_OFFSET);
  266. ok1(h.table_size == 4);
  267. ok1(h.bucket == 3);
  268. /* Should have lock on bucket 0 */
  269. ok1((h.h & ((1 << ntdb->hash_bits)-1)) == 0);
  270. ok1((ntdb->flags & NTDB_NOLOCK) || ntdb->file->num_lockrecs == 1);
  271. ok1((ntdb->flags & NTDB_NOLOCK)
  272. || ntdb->file->lockrecs[0].off == NTDB_HASH_LOCK_START);
  273. ok1(ntdb_unlock_hash(ntdb, h.h, F_WRLCK) == 0);
  274. ntdb_close(ntdb);
  275. }
  276. ok1(tap_log_messages == 0);
  277. return exit_status();
  278. }