1 /* We need this otherwise fcntl locking fails. */
2 #define _FILE_OFFSET_BITS 64
3 #include "tdb2-source.h"
4 #include <ccan/tap/tap.h>
9 static int tdb1_expand_file_sparse(struct tdb_context
*tdb
,
13 if ((tdb
->flags
& TDB_RDONLY
) || tdb
->tdb1
.traverse_read
) {
14 tdb
->last_error
= TDB_ERR_RDONLY
;
18 if (ftruncate(tdb
->file
->fd
, size
+addition
) == -1) {
20 ssize_t written
= pwrite(tdb
->file
->fd
, &b
, 1, (size
+addition
) - 1);
22 /* try once more, potentially revealing errno */
23 written
= pwrite(tdb
->file
->fd
, &b
, 1, (size
+addition
) - 1);
26 /* again - give up, guessing errno */
30 tdb
->last_error
= tdb_logerr(tdb
, TDB_ERR_IO
, TDB_LOG_ERROR
,
31 "expand_file to %d failed (%s)",
41 static const struct tdb1_methods large_io_methods
= {
46 tdb1_expand_file_sparse
49 static int test_traverse(struct tdb_context
*tdb
, TDB_DATA key
, TDB_DATA data
,
52 TDB_DATA
*expect
= _data
;
53 ok1(key
.dsize
== strlen("hi"));
54 ok1(memcmp(key
.dptr
, "hi", strlen("hi")) == 0);
55 ok1(data
.dsize
== expect
->dsize
);
56 ok1(memcmp(data
.dptr
, expect
->dptr
, data
.dsize
) == 0);
60 int main(int argc
, char *argv
[])
62 struct tdb_context
*tdb
;
63 TDB_DATA key
, orig_data
, data
;
66 struct tdb1_record rec
;
67 union tdb_attribute hsize
;
69 hsize
.base
.attr
= TDB_ATTRIBUTE_TDB1_HASHSIZE
;
70 hsize
.base
.next
= &tap_log_attr
;
71 hsize
.tdb1_hashsize
.hsize
= 1024;
74 tdb
= tdb_open("run-36-file.tdb1", TDB_VERSION1
,
75 O_CREAT
|O_TRUNC
|O_RDWR
, 0600, &hsize
);
78 tdb
->tdb1
.io
= &large_io_methods
;
80 /* Enlarge the file (internally multiplies by 2). */
81 ok1(tdb1_expand(tdb
, 1500000000) == 0);
83 /* Put an entry in, and check it. */
84 key
.dsize
= strlen("hi");
85 key
.dptr
= (void *)"hi";
86 orig_data
.dsize
= strlen("world");
87 orig_data
.dptr
= (void *)"world";
89 ok1(tdb_store(tdb
, key
, orig_data
, TDB_INSERT
) == TDB_SUCCESS
);
91 ok1(tdb_fetch(tdb
, key
, &data
) == TDB_SUCCESS
);
92 ok1(data
.dsize
== strlen("world"));
93 ok1(memcmp(data
.dptr
, "world", strlen("world")) == 0);
96 /* That currently fills at the end, make sure that's true. */
97 hash
= tdb_hash(tdb
, key
.dptr
, key
.dsize
);
98 rec_ptr
= tdb1_find_lock_hash(tdb
, key
, hash
, F_RDLCK
, &rec
);
100 ok1(rec_ptr
> 2U*1024*1024*1024);
101 tdb1_unlock(tdb
, TDB1_BUCKET(rec
.full_hash
), F_RDLCK
);
103 /* Traverse must work. */
104 ok1(tdb_traverse(tdb
, test_traverse
, &orig_data
) == 1);
106 /* Delete should work. */
107 ok1(tdb_delete(tdb
, key
) == TDB_SUCCESS
);
109 ok1(tdb_traverse(tdb
, test_traverse
, NULL
) == 0);
111 /* Transactions should work. */
112 ok1(tdb_transaction_start(tdb
) == TDB_SUCCESS
);
113 ok1(tdb_store(tdb
, key
, orig_data
, TDB_INSERT
) == TDB_SUCCESS
);
115 ok1(tdb_fetch(tdb
, key
, &data
) == TDB_SUCCESS
);
116 ok1(data
.dsize
== strlen("world"));
117 ok1(memcmp(data
.dptr
, "world", strlen("world")) == 0);
119 ok1(tdb_transaction_commit(tdb
) == TDB_SUCCESS
);
121 ok1(tdb_traverse(tdb
, test_traverse
, &orig_data
) == 1);
124 return exit_status();