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 "../common/mutex.c"
13 #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 (tdb_ftruncate(tdb
, size
+addition
) == -1) {
28 ssize_t written
= tdb_pwrite(tdb
, &b
, 1, (size
+addition
) - 1);
30 /* try once more, potentially revealing errno */
31 written
= tdb_pwrite(tdb
, &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
;
76 tdb
= tdb_open_ex("run-36-file.tdb", 1024, TDB_CLEAR_IF_FIRST
,
77 O_CREAT
|O_TRUNC
|O_RDWR
, 0600, &taplogctx
, NULL
);
80 tdb
->methods
= &large_io_methods
;
82 key
.dsize
= strlen("hi");
83 key
.dptr
= discard_const_p(uint8_t, "hi");
84 orig_data
.dsize
= strlen("world");
85 orig_data
.dptr
= discard_const_p(uint8_t, "world");
87 /* Enlarge the file (internally multiplies by 2). */
88 ret
= tdb_expand(tdb
, 1500000000);
89 #ifdef HAVE_INCOHERENT_MMAP
90 /* This can fail due to mmap failure on 32 bit systems. */
92 /* These should now fail. */
93 ok1(tdb_store(tdb
, key
, orig_data
, TDB_INSERT
) == -1);
94 data
= tdb_fetch(tdb
, key
);
95 ok1(data
.dptr
== NULL
);
96 ok1(tdb_traverse(tdb
, test_traverse
, &orig_data
) == -1);
97 ok1(tdb_delete(tdb
, key
) == -1);
98 ok1(tdb_traverse(tdb
, test_traverse
, NULL
) == -1);
99 /* Skip the rest... */
100 for (ret
= 0; ret
< 24 - 6; ret
++)
103 return exit_status();
108 /* Put an entry in, and check it. */
109 ok1(tdb_store(tdb
, key
, orig_data
, TDB_INSERT
) == 0);
111 data
= tdb_fetch(tdb
, key
);
112 ok1(data
.dsize
== strlen("world"));
113 ok1(memcmp(data
.dptr
, "world", strlen("world")) == 0);
116 /* That currently fills at the end, make sure that's true. */
117 hashval
= tdb
->hash_fn(&key
);
118 rec_ptr
= tdb_find_lock_hash(tdb
, key
, hashval
, F_RDLCK
, &rec
);
120 ok1(rec_ptr
> 2U*1024*1024*1024);
121 tdb_unlock(tdb
, BUCKET(rec
.full_hash
), F_RDLCK
);
123 /* Traverse must work. */
124 ok1(tdb_traverse(tdb
, test_traverse
, &orig_data
) == 1);
126 /* Delete should work. */
127 ok1(tdb_delete(tdb
, key
) == 0);
129 ok1(tdb_traverse(tdb
, test_traverse
, NULL
) == 0);
131 /* Transactions should work. */
132 ok1(tdb_transaction_start(tdb
) == 0);
133 ok1(tdb_store(tdb
, key
, orig_data
, TDB_INSERT
) == 0);
135 data
= tdb_fetch(tdb
, key
);
136 ok1(data
.dsize
== strlen("world"));
137 ok1(memcmp(data
.dptr
, "world", strlen("world")) == 0);
139 ok1(tdb_transaction_commit(tdb
) == 0);
141 ok1(tdb_traverse(tdb
, test_traverse
, &orig_data
) == 1);
144 return exit_status();