1 #include "ntdb-source.h"
2 #include "tap-interface.h"
5 #define NUM_RECORDS 1000
7 /* We use the same seed which we saw a failure on. */
8 static uint32_t fixedhash(const void *key
, size_t len
, uint32_t seed
, void *p
)
10 return hash64_stable((const unsigned char *)key
, len
,
14 static bool store_records(struct ntdb_context
*ntdb
)
17 NTDB_DATA key
= { (unsigned char *)&i
, sizeof(i
) };
18 NTDB_DATA data
= { (unsigned char *)&i
, sizeof(i
) };
20 for (i
= 0; i
< NUM_RECORDS
; i
++)
21 if (ntdb_store(ntdb
, key
, data
, NTDB_REPLACE
) != 0)
27 unsigned int calls
, call_limit
;
31 enum NTDB_ERROR delete_error
;
34 static int trav(struct ntdb_context
*ntdb
, NTDB_DATA key
, NTDB_DATA dbuf
,
40 if (key
.dsize
!= sizeof(val
) || dbuf
.dsize
!= sizeof(val
)
41 || memcmp(key
.dptr
, dbuf
.dptr
, key
.dsize
) != 0) {
45 memcpy(&val
, dbuf
.dptr
, dbuf
.dsize
);
52 td
->delete_error
= ntdb_delete(ntdb
, key
);
53 if (td
->delete_error
!= NTDB_SUCCESS
) {
58 if (td
->calls
== td
->call_limit
)
63 struct trav_grow_data
{
65 unsigned int num_large
;
67 enum NTDB_ERROR error
;
70 static int trav_grow(struct ntdb_context
*ntdb
, NTDB_DATA key
, NTDB_DATA dbuf
,
71 struct trav_grow_data
*tgd
)
74 unsigned char buffer
[128] = { 0 };
77 if (key
.dsize
!= sizeof(val
) || dbuf
.dsize
< sizeof(val
)
78 || memcmp(key
.dptr
, dbuf
.dptr
, key
.dsize
) != 0) {
83 if (dbuf
.dsize
> sizeof(val
))
84 /* We must have seen this before! */
87 /* Make a big difference to the database. */
89 dbuf
.dsize
= sizeof(buffer
);
90 tgd
->error
= ntdb_append(ntdb
, key
, dbuf
);
91 if (tgd
->error
!= NTDB_SUCCESS
) {
97 int main(int argc
, char *argv
[])
102 struct trav_grow_data tgd
;
103 struct ntdb_context
*ntdb
;
104 uint64_t seed
= 16014841315512641303ULL;
105 int flags
[] = { NTDB_INTERNAL
, NTDB_DEFAULT
, NTDB_NOMMAP
,
106 NTDB_INTERNAL
|NTDB_CONVERT
, NTDB_CONVERT
,
107 NTDB_NOMMAP
|NTDB_CONVERT
};
108 union ntdb_attribute hattr
= { .hash
= { .base
= { NTDB_ATTRIBUTE_HASH
},
112 hattr
.base
.next
= &tap_log_attr
;
114 plan_tests(sizeof(flags
) / sizeof(flags
[0]) * 32 + 1);
115 for (i
= 0; i
< sizeof(flags
) / sizeof(flags
[0]); i
++) {
116 ntdb
= ntdb_open("run-traverse.ntdb", flags
[i
]|MAYBE_NOSYNC
,
117 O_RDWR
|O_CREAT
|O_TRUNC
, 0600, &hattr
);
122 ok1(ntdb_traverse(ntdb
, NULL
, NULL
) == 0);
124 ok1(store_records(ntdb
));
125 num
= ntdb_traverse(ntdb
, NULL
, NULL
);
126 ok1(num
== NUM_RECORDS
);
130 td
.call_limit
= UINT_MAX
;
136 num
= ntdb_traverse(ntdb
, trav
, &td
);
137 ok1(num
== NUM_RECORDS
);
139 ok1(td
.calls
== NUM_RECORDS
);
141 ok1(td
.high
== NUM_RECORDS
-1);
143 /* Short traverse. */
145 td
.call_limit
= NUM_RECORDS
/ 2;
151 num
= ntdb_traverse(ntdb
, trav
, &td
);
152 ok1(num
== NUM_RECORDS
/ 2);
154 ok1(td
.calls
== NUM_RECORDS
/ 2);
155 ok1(td
.low
<= NUM_RECORDS
/ 2);
156 ok1(td
.high
> NUM_RECORDS
/ 2);
157 ok1(ntdb_check(ntdb
, NULL
, NULL
) == 0);
158 ok1(tap_log_messages
== 0);
160 /* Deleting traverse (delete everything). */
162 td
.call_limit
= UINT_MAX
;
167 td
.delete_error
= NTDB_SUCCESS
;
168 num
= ntdb_traverse(ntdb
, trav
, &td
);
169 ok1(num
== NUM_RECORDS
);
170 ok1(td
.delete_error
== NTDB_SUCCESS
);
172 ok1(td
.calls
== NUM_RECORDS
);
174 ok1(td
.high
== NUM_RECORDS
- 1);
175 ok1(ntdb_check(ntdb
, NULL
, NULL
) == 0);
177 /* Now it's empty! */
178 ok1(ntdb_traverse(ntdb
, NULL
, NULL
) == 0);
181 ok1(store_records(ntdb
));
182 ok1(ntdb_traverse(ntdb
, NULL
, NULL
) == NUM_RECORDS
);
183 ok1(ntdb_check(ntdb
, NULL
, NULL
) == 0);
185 /* Grow. This will cause us to be reshuffled. */
188 tgd
.mismatch
= false;
189 tgd
.error
= NTDB_SUCCESS
;
190 ok1(ntdb_traverse(ntdb
, trav_grow
, &tgd
) > 1);
193 ok1(ntdb_check(ntdb
, NULL
, NULL
) == 0);
194 ok1(tgd
.num_large
< tgd
.calls
);
195 diag("growing db: %u calls, %u repeats",
196 tgd
.calls
, tgd
.num_large
);
201 ok1(tap_log_messages
== 0);
202 return exit_status();