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"
16 static int tdb_expand_file_sparse(struct tdb_context
*tdb
,
20 if (tdb
->read_only
|| tdb
->traverse_read
) {
21 tdb
->ecode
= TDB_ERR_RDONLY
;
25 if (ftruncate(tdb
->fd
, size
+addition
) == -1) {
27 ssize_t written
= pwrite(tdb
->fd
, &b
, 1, (size
+addition
) - 1);
29 /* try once more, potentially revealing errno */
30 written
= pwrite(tdb
->fd
, &b
, 1, (size
+addition
) - 1);
33 /* again - give up, guessing errno */
37 TDB_LOG((tdb
, TDB_DEBUG_FATAL
, "expand_file to %d failed (%s)\n",
38 size
+addition
, strerror(errno
)));
46 static const struct tdb_methods large_io_methods
= {
51 tdb_expand_file_sparse
54 static int test_traverse(struct tdb_context
*tdb
, TDB_DATA key
, TDB_DATA data
,
57 TDB_DATA
*expect
= _data
;
58 ok1(key
.dsize
== strlen("hi"));
59 ok1(memcmp(key
.dptr
, "hi", strlen("hi")) == 0);
60 ok1(data
.dsize
== expect
->dsize
);
61 ok1(memcmp(data
.dptr
, expect
->dptr
, data
.dsize
) == 0);
65 int main(int argc
, char *argv
[])
67 struct tdb_context
*tdb
;
68 TDB_DATA key
, orig_data
, data
;
71 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 key
.dsize
= strlen("hi");
82 key
.dptr
= (void *)"hi";
83 orig_data
.dsize
= strlen("world");
84 orig_data
.dptr
= (void *)"world";
86 /* Enlarge the file (internally multiplies by 2). */
87 ret
= tdb_expand(tdb
, 1500000000);
88 #ifdef HAVE_INCOHERENT_MMAP
89 /* This can fail due to mmap failure on 32 bit systems. */
91 /* These should now fail. */
92 ok1(tdb_store(tdb
, key
, orig_data
, TDB_INSERT
) == -1);
93 data
= tdb_fetch(tdb
, key
);
94 ok1(data
.dptr
== NULL
);
95 ok1(tdb_traverse(tdb
, test_traverse
, &orig_data
) == -1);
96 ok1(tdb_delete(tdb
, key
) == -1);
97 ok1(tdb_traverse(tdb
, test_traverse
, NULL
) == -1);
98 /* Skip the rest... */
99 for (ret
= 0; ret
< 24 - 6; ret
++)
102 return exit_status();
107 /* Put an entry in, and check it. */
108 ok1(tdb_store(tdb
, key
, orig_data
, TDB_INSERT
) == 0);
110 data
= tdb_fetch(tdb
, key
);
111 ok1(data
.dsize
== strlen("world"));
112 ok1(memcmp(data
.dptr
, "world", strlen("world")) == 0);
115 /* That currently fills at the end, make sure that's true. */
116 hash
= tdb
->hash_fn(&key
);
117 rec_ptr
= tdb_find_lock_hash(tdb
, key
, hash
, F_RDLCK
, &rec
);
119 ok1(rec_ptr
> 2U*1024*1024*1024);
120 tdb_unlock(tdb
, BUCKET(rec
.full_hash
), F_RDLCK
);
122 /* Traverse must work. */
123 ok1(tdb_traverse(tdb
, test_traverse
, &orig_data
) == 1);
125 /* Delete should work. */
126 ok1(tdb_delete(tdb
, key
) == 0);
128 ok1(tdb_traverse(tdb
, test_traverse
, NULL
) == 0);
130 /* Transactions should work. */
131 ok1(tdb_transaction_start(tdb
) == 0);
132 ok1(tdb_store(tdb
, key
, orig_data
, TDB_INSERT
) == 0);
134 data
= tdb_fetch(tdb
, key
);
135 ok1(data
.dsize
== strlen("world"));
136 ok1(memcmp(data
.dptr
, "world", strlen("world")) == 0);
138 ok1(tdb_transaction_commit(tdb
) == 0);
140 ok1(tdb_traverse(tdb
, test_traverse
, &orig_data
) == 1);
143 return exit_status();