1 #include "../common/tdb_private.h"
2 #include "../common/io.c"
3 #include "../common/tdb.c"
4 #include "../common/lock.c"
5 #include "../common/freelist.c"
6 #include "../common/traverse.c"
7 #include "../common/transaction.c"
8 #include "../common/error.c"
9 #include "../common/open.c"
10 #include "../common/check.c"
11 #include "../common/hash.c"
12 #include "tap-interface.h"
17 static int tdb_expand_file_sparse(struct tdb_context
*tdb
,
21 if (tdb
->read_only
|| tdb
->traverse_read
) {
22 tdb
->ecode
= TDB_ERR_RDONLY
;
26 if (ftruncate(tdb
->fd
, size
+addition
) == -1) {
28 ssize_t written
= pwrite(tdb
->fd
, &b
, 1, (size
+addition
) - 1);
30 /* try once more, potentially revealing errno */
31 written
= pwrite(tdb
->fd
, &b
, 1, (size
+addition
) - 1);
34 /* again - give up, guessing errno */
38 TDB_LOG((tdb
, TDB_DEBUG_FATAL
, "expand_file to %d failed (%s)\n",
39 size
+addition
, strerror(errno
)));
47 static const struct tdb_methods large_io_methods
= {
52 tdb_expand_file_sparse
55 static int test_traverse(struct tdb_context
*tdb
, TDB_DATA key
, TDB_DATA data
,
58 TDB_DATA
*expect
= _data
;
59 ok1(key
.dsize
== strlen("hi"));
60 ok1(memcmp(key
.dptr
, "hi", strlen("hi")) == 0);
61 ok1(data
.dsize
== expect
->dsize
);
62 ok1(memcmp(data
.dptr
, expect
->dptr
, data
.dsize
) == 0);
66 int main(int argc
, char *argv
[])
68 struct tdb_context
*tdb
;
69 TDB_DATA key
, orig_data
, data
;
72 struct tdb_record rec
;
75 tdb
= tdb_open_ex("run-36-file.tdb", 1024, TDB_CLEAR_IF_FIRST
,
76 O_CREAT
|O_TRUNC
|O_RDWR
, 0600, &taplogctx
, NULL
);
79 tdb
->methods
= &large_io_methods
;
81 /* Enlarge the file (internally multiplies by 2). */
82 ok1(tdb_expand(tdb
, 1500000000) == 0);
84 /* Put an entry in, and check it. */
85 key
.dsize
= strlen("hi");
86 key
.dptr
= (void *)"hi";
87 orig_data
.dsize
= strlen("world");
88 orig_data
.dptr
= (void *)"world";
90 ok1(tdb_store(tdb
, key
, orig_data
, TDB_INSERT
) == 0);
92 data
= tdb_fetch(tdb
, key
);
93 ok1(data
.dsize
== strlen("world"));
94 ok1(memcmp(data
.dptr
, "world", strlen("world")) == 0);
97 /* That currently fills at the end, make sure that's true. */
98 hash
= tdb
->hash_fn(&key
);
99 rec_ptr
= tdb_find_lock_hash(tdb
, key
, hash
, F_RDLCK
, &rec
);
101 ok1(rec_ptr
> 2U*1024*1024*1024);
102 tdb_unlock(tdb
, BUCKET(rec
.full_hash
), F_RDLCK
);
104 /* Traverse must work. */
105 ok1(tdb_traverse(tdb
, test_traverse
, &orig_data
) == 1);
107 /* Delete should work. */
108 ok1(tdb_delete(tdb
, key
) == 0);
110 ok1(tdb_traverse(tdb
, test_traverse
, NULL
) == 0);
112 /* Transactions should work. */
113 ok1(tdb_transaction_start(tdb
) == 0);
114 ok1(tdb_store(tdb
, key
, orig_data
, TDB_INSERT
) == 0);
116 data
= tdb_fetch(tdb
, key
);
117 ok1(data
.dsize
== strlen("world"));
118 ok1(memcmp(data
.dptr
, "world", strlen("world")) == 0);
120 ok1(tdb_transaction_commit(tdb
) == 0);
122 ok1(tdb_traverse(tdb
, test_traverse
, &orig_data
) == 1);
125 return exit_status();