1 #include <ccan/tdb2/tdb2.h>
2 #include <ccan/tap/tap.h>
9 #define NUM_RECORDS 1000
11 static bool store_records(struct tdb_context
*tdb
)
14 struct tdb_data key
= { (unsigned char *)&i
, sizeof(i
) };
15 struct tdb_data data
= { (unsigned char *)&i
, sizeof(i
) };
17 for (i
= 0; i
< NUM_RECORDS
; i
++)
18 if (tdb_store(tdb
, key
, data
, TDB_REPLACE
) != 0)
24 unsigned int records
[NUM_RECORDS
];
28 static int trav(struct tdb_context
*tdb
, TDB_DATA key
, TDB_DATA dbuf
, void *p
)
30 struct trav_data
*td
= p
;
33 memcpy(&val
, dbuf
.dptr
, dbuf
.dsize
);
34 td
->records
[td
->calls
++] = val
;
38 /* Since tdb_nextkey frees dptr, we need to clone it. */
39 static TDB_DATA
dup_key(TDB_DATA key
)
41 void *p
= malloc(key
.dsize
);
42 memcpy(p
, key
.dptr
, key
.dsize
);
47 int main(int argc
, char *argv
[])
53 struct tdb_context
*tdb
;
54 union tdb_attribute seed_attr
;
56 int flags
[] = { TDB_INTERNAL
, TDB_DEFAULT
, TDB_NOMMAP
,
57 TDB_INTERNAL
|TDB_CONVERT
, TDB_CONVERT
,
58 TDB_NOMMAP
|TDB_CONVERT
,
59 TDB_INTERNAL
|TDB_VERSION1
, TDB_VERSION1
,
60 TDB_NOMMAP
|TDB_VERSION1
,
61 TDB_INTERNAL
|TDB_CONVERT
|TDB_VERSION1
,
62 TDB_CONVERT
|TDB_VERSION1
,
63 TDB_NOMMAP
|TDB_CONVERT
|TDB_VERSION1
};
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,
74 flags
[i
] & TDB_VERSION1
? NULL
: &seed_attr
);
79 ok1(tdb_firstkey(tdb
, &k
) == TDB_ERR_NOEXIST
);
82 k
.dptr
= (unsigned char *)&num
;
83 k
.dsize
= sizeof(num
);
85 ok1(tdb_store(tdb
, k
, k
, TDB_INSERT
) == 0);
86 ok1(tdb_firstkey(tdb
, &k
) == TDB_SUCCESS
);
87 ok1(k
.dsize
== sizeof(num
));
88 ok1(memcmp(k
.dptr
, &num
, sizeof(num
)) == 0);
89 ok1(tdb_nextkey(tdb
, &k
) == TDB_ERR_NOEXIST
);
92 k
.dptr
= (unsigned char *)&num
;
93 k
.dsize
= sizeof(num
);
95 ok1(tdb_store(tdb
, k
, k
, TDB_INSERT
) == 0);
96 ok1(tdb_firstkey(tdb
, &k
) == TDB_SUCCESS
);
97 ok1(k
.dsize
== sizeof(num
));
98 memcpy(&num
, k
.dptr
, sizeof(num
));
99 ok1(num
== 0 || num
== 1);
100 ok1(tdb_nextkey(tdb
, &k
) == TDB_SUCCESS
);
101 ok1(k
.dsize
== sizeof(j
));
102 memcpy(&j
, k
.dptr
, sizeof(j
));
103 ok1(j
== 0 || j
== 1);
105 ok1(tdb_nextkey(tdb
, &k
) == TDB_ERR_NOEXIST
);
108 k
.dptr
= (unsigned char *)&num
;
109 k
.dsize
= sizeof(num
);
111 ok1(tdb_delete(tdb
, k
) == 0);
113 ok1(tdb_delete(tdb
, k
) == 0);
115 /* Now lots of records. */
116 ok1(store_records(tdb
));
119 num
= tdb_traverse(tdb
, trav
, &td
);
120 ok1(num
== NUM_RECORDS
);
121 ok1(td
.calls
== NUM_RECORDS
);
123 /* Simple loop should match tdb_traverse */
124 for (j
= 0, ecode
= tdb_firstkey(tdb
, &k
); j
< td
.calls
; j
++) {
127 ok1(ecode
== TDB_SUCCESS
);
128 ok1(k
.dsize
== sizeof(val
));
129 memcpy(&val
, k
.dptr
, k
.dsize
);
130 ok1(td
.records
[j
] == val
);
131 ecode
= tdb_nextkey(tdb
, &k
);
134 /* But arbitrary orderings should work too. */
135 for (j
= td
.calls
-1; j
> 0; j
--) {
136 k
.dptr
= (unsigned char *)&td
.records
[j
-1];
137 k
.dsize
= sizeof(td
.records
[j
-1]);
139 ok1(tdb_nextkey(tdb
, &k
) == TDB_SUCCESS
);
140 ok1(k
.dsize
== sizeof(td
.records
[j
]));
141 ok1(memcmp(k
.dptr
, &td
.records
[j
], k
.dsize
) == 0);
145 /* Even delete should work. */
146 for (j
= 0, ecode
= tdb_firstkey(tdb
, &k
);
147 ecode
!= TDB_ERR_NOEXIST
;
149 ok1(ecode
== TDB_SUCCESS
);
151 ok1(tdb_delete(tdb
, k
) == 0);
152 ecode
= tdb_nextkey(tdb
, &k
);
155 diag("delete using first/nextkey gave %u of %u records",
157 ok1(j
== NUM_RECORDS
);
161 ok1(tap_log_messages
== 0);
162 return exit_status();