1 #include <ccan/tdb2/tdb.c>
2 #include <ccan/tdb2/open.c>
3 #include <ccan/tdb2/free.c>
4 #include <ccan/tdb2/lock.c>
5 #include <ccan/tdb2/io.c>
6 #include <ccan/tdb2/hash.c>
7 #include <ccan/tdb2/check.c>
8 #include <ccan/tdb2/traverse.c>
9 #include <ccan/tdb2/transaction.c>
10 #include <ccan/tap/tap.h>
13 #define NUM_RECORDS 1000
15 static bool store_records(struct tdb_context
*tdb
)
18 struct tdb_data key
= { (unsigned char *)&i
, sizeof(i
) };
19 struct tdb_data data
= { (unsigned char *)&i
, sizeof(i
) };
21 for (i
= 0; i
< NUM_RECORDS
; i
++)
22 if (tdb_store(tdb
, key
, data
, TDB_REPLACE
) != 0)
28 unsigned int records
[NUM_RECORDS
];
32 static int trav(struct tdb_context
*tdb
, TDB_DATA key
, TDB_DATA dbuf
, void *p
)
34 struct trav_data
*td
= p
;
37 memcpy(&val
, dbuf
.dptr
, dbuf
.dsize
);
38 td
->records
[td
->calls
++] = val
;
42 /* Since tdb_nextkey frees dptr, we need to clone it. */
43 static TDB_DATA
dup_key(TDB_DATA key
)
45 void *p
= malloc(key
.dsize
);
46 memcpy(p
, key
.dptr
, key
.dsize
);
51 int main(int argc
, char *argv
[])
57 struct tdb_context
*tdb
;
58 union tdb_attribute seed_attr
;
61 int flags
[] = { TDB_INTERNAL
, TDB_DEFAULT
, TDB_NOMMAP
,
62 TDB_INTERNAL
|TDB_CONVERT
, TDB_CONVERT
,
63 TDB_NOMMAP
|TDB_CONVERT
};
65 seed_attr
.base
.attr
= TDB_ATTRIBUTE_SEED
;
66 seed_attr
.base
.next
= &tap_log_attr
;
67 seed_attr
.seed
.seed
= 6334326220117065685ULL;
69 plan_tests(sizeof(flags
) / sizeof(flags
[0])
70 * (NUM_RECORDS
*6 + (NUM_RECORDS
-1)*3 + 22) + 1);
71 for (i
= 0; i
< sizeof(flags
) / sizeof(flags
[0]); i
++) {
72 tdb
= tdb_open("run-traverse.tdb", flags
[i
],
73 O_RDWR
|O_CREAT
|O_TRUNC
, 0600, &seed_attr
);
78 ok1(tdb_firstkey(tdb
, &k
) == TDB_ERR_NOEXIST
);
81 k
.dptr
= (unsigned char *)&num
;
82 k
.dsize
= sizeof(num
);
84 ok1(tdb_store(tdb
, k
, k
, TDB_INSERT
) == 0);
85 ok1(tdb_firstkey(tdb
, &k
) == TDB_SUCCESS
);
86 ok1(k
.dsize
== sizeof(num
));
87 ok1(memcmp(k
.dptr
, &num
, sizeof(num
)) == 0);
88 ok1(tdb_nextkey(tdb
, &k
) == TDB_ERR_NOEXIST
);
91 k
.dptr
= (unsigned char *)&num
;
92 k
.dsize
= sizeof(num
);
94 ok1(tdb_store(tdb
, k
, k
, TDB_INSERT
) == 0);
95 ok1(tdb_firstkey(tdb
, &k
) == TDB_SUCCESS
);
96 ok1(k
.dsize
== sizeof(num
));
97 memcpy(&num
, k
.dptr
, sizeof(num
));
98 ok1(num
== 0 || num
== 1);
99 ok1(tdb_nextkey(tdb
, &k
) == TDB_SUCCESS
);
100 ok1(k
.dsize
== sizeof(j
));
101 memcpy(&j
, k
.dptr
, sizeof(j
));
102 ok1(j
== 0 || j
== 1);
104 ok1(tdb_nextkey(tdb
, &k
) == TDB_ERR_NOEXIST
);
107 k
.dptr
= (unsigned char *)&num
;
108 k
.dsize
= sizeof(num
);
110 ok1(tdb_delete(tdb
, k
) == 0);
112 ok1(tdb_delete(tdb
, k
) == 0);
114 /* Now lots of records. */
115 ok1(store_records(tdb
));
118 num
= tdb_traverse(tdb
, trav
, &td
);
119 ok1(num
== NUM_RECORDS
);
120 ok1(td
.calls
== NUM_RECORDS
);
122 /* Simple loop should match tdb_traverse */
123 for (j
= 0, ecode
= tdb_firstkey(tdb
, &k
); j
< td
.calls
; j
++) {
126 ok1(ecode
== TDB_SUCCESS
);
127 ok1(k
.dsize
== sizeof(val
));
128 memcpy(&val
, k
.dptr
, k
.dsize
);
129 ok1(td
.records
[j
] == val
);
130 ecode
= tdb_nextkey(tdb
, &k
);
133 /* But arbitrary orderings should work too. */
134 for (j
= td
.calls
-1; j
> 0; j
--) {
135 k
.dptr
= (unsigned char *)&td
.records
[j
-1];
136 k
.dsize
= sizeof(td
.records
[j
-1]);
138 ok1(tdb_nextkey(tdb
, &k
) == TDB_SUCCESS
);
139 ok1(k
.dsize
== sizeof(td
.records
[j
]));
140 ok1(memcmp(k
.dptr
, &td
.records
[j
], k
.dsize
) == 0);
144 /* Even delete should work. */
145 for (j
= 0, ecode
= tdb_firstkey(tdb
, &k
);
146 ecode
!= TDB_ERR_NOEXIST
;
148 ok1(ecode
== TDB_SUCCESS
);
150 ok1(tdb_delete(tdb
, k
) == 0);
151 ecode
= tdb_nextkey(tdb
, &k
);
154 diag("delete using first/nextkey gave %u of %u records",
156 ok1(j
== NUM_RECORDS
);
160 ok1(tap_log_messages
== 0);
161 return exit_status();