1 #include "../common/tdb_private.h"
2 #include "lock-tracking.h"
3 static ssize_t
pwrite_check(int fd
, const void *buf
, size_t count
, off_t offset
);
4 static ssize_t
write_check(int fd
, const void *buf
, size_t count
);
5 static int ftruncate_check(int fd
, off_t length
);
7 #define pwrite pwrite_check
8 #define write write_check
9 #define fcntl fcntl_with_lockcheck
10 #define ftruncate ftruncate_check
12 #include "../common/io.c"
13 #include "../common/tdb.c"
14 #include "../common/lock.c"
15 #include "../common/freelist.c"
16 #include "../common/traverse.c"
17 #include "../common/transaction.c"
18 #include "../common/error.c"
19 #include "../common/open.c"
20 #include "../common/check.c"
21 #include "../common/hash.c"
22 #include "tap-interface.h"
27 #include "external-agent.h"
35 static bool in_transaction
;
36 static int target
, current
;
37 static jmp_buf jmpbuf
;
38 #define TEST_DBNAME "run-die-during-transaction.tdb"
39 #define KEY_STRING "helloworld"
41 static void maybe_die(int fd
)
43 if (in_transaction
&& current
++ == target
) {
48 static ssize_t
pwrite_check(int fd
,
49 const void *buf
, size_t count
, off_t offset
)
55 ret
= pwrite(fd
, buf
, count
, offset
);
63 static ssize_t
write_check(int fd
, const void *buf
, size_t count
)
69 ret
= write(fd
, buf
, count
);
77 static int ftruncate_check(int fd
, off_t length
)
83 ret
= ftruncate(fd
, length
);
89 static bool test_death(enum operation op
, struct agent
*agent
)
91 struct tdb_context
*tdb
= NULL
;
93 enum agent_return ret
;
94 int needed_recovery
= 0;
99 tdb
= tdb_open_ex(TEST_DBNAME
, 1024, TDB_NOMMAP
,
100 O_CREAT
|O_TRUNC
|O_RDWR
, 0600, &taplogctx
, NULL
);
102 if (setjmp(jmpbuf
) != 0) {
103 /* We're partway through. Simulate our death. */
106 in_transaction
= false;
108 ret
= external_agent_operation(agent
, NEEDS_RECOVERY
, "");
111 else if (ret
!= FAILED
) {
112 diag("Step %u agent NEEDS_RECOVERY = %s", current
,
113 agent_return_name(ret
));
117 ret
= external_agent_operation(agent
, op
, KEY_STRING
);
118 if (ret
!= SUCCESS
) {
119 diag("Step %u op %s failed = %s", current
,
121 agent_return_name(ret
));
125 ret
= external_agent_operation(agent
, NEEDS_RECOVERY
, "");
127 diag("Still needs recovery after step %u = %s",
128 current
, agent_return_name(ret
));
132 ret
= external_agent_operation(agent
, CHECK
, "");
133 if (ret
!= SUCCESS
) {
134 diag("Step %u check failed = %s", current
,
135 agent_return_name(ret
));
139 ret
= external_agent_operation(agent
, CLOSE
, "");
140 if (ret
!= SUCCESS
) {
141 diag("Step %u close failed = %s", current
,
142 agent_return_name(ret
));
146 /* Suppress logging as this tries to use closed fd. */
147 suppress_logging
= true;
148 suppress_lockcheck
= true;
150 suppress_logging
= false;
151 suppress_lockcheck
= false;
157 /* Put key for agent to fetch. */
158 key
.dsize
= strlen(KEY_STRING
);
159 key
.dptr
= discard_const_p(uint8_t, KEY_STRING
);
160 if (tdb_store(tdb
, key
, key
, TDB_INSERT
) != 0)
163 /* This is the key we insert in transaction. */
166 ret
= external_agent_operation(agent
, OPEN
, TEST_DBNAME
);
167 if (ret
!= SUCCESS
) {
168 fprintf(stderr
, "Agent failed to open: %s\n",
169 agent_return_name(ret
));
173 ret
= external_agent_operation(agent
, FETCH
, KEY_STRING
);
174 if (ret
!= SUCCESS
) {
175 fprintf(stderr
, "Agent failed find key: %s\n",
176 agent_return_name(ret
));
180 in_transaction
= true;
181 if (tdb_transaction_start(tdb
) != 0)
184 if (tdb_store(tdb
, key
, key
, TDB_INSERT
) != 0)
187 if (tdb_transaction_commit(tdb
) != 0)
190 in_transaction
= false;
193 diag("Completed %u runs", current
);
195 ret
= external_agent_operation(agent
, CLOSE
, "");
196 if (ret
!= SUCCESS
) {
197 diag("Step %u close failed = %s", current
,
198 agent_return_name(ret
));
202 #ifdef HAVE_INCOHERENT_MMAP
203 /* This means we always mmap, which makes this test a noop. */
206 ok1(needed_recovery
);
208 ok1(locking_errors
== 0);
209 ok1(forget_locking() == 0);
214 int main(int argc
, char *argv
[])
216 enum operation ops
[] = { FETCH
, STORE
, TRANSACTION_START
};
221 unlock_callback
= maybe_die
;
223 agent
= prepare_external_agent();
225 for (i
= 0; i
< sizeof(ops
)/sizeof(ops
[0]); i
++) {
226 diag("Testing %s after death", operation_name(ops
[i
]));
227 ok1(test_death(ops
[i
], agent
));
230 return exit_status();