]> git.ozlabs.org Git - ccan/blob - ccan/tdb2/test/api-fork-test.c
tdb2: test: convert (non-invasive) run tests to api tests.
[ccan] / ccan / tdb2 / test / api-fork-test.c
1 /* Test forking while holding lock.
2  *
3  * There are only five ways to do this currently:
4  * (1) grab a tdb_chainlock, then fork.
5  * (2) grab a tdb_lockall, then fork.
6  * (3) grab a tdb_lockall_read, then fork.
7  * (4) start a transaction, then fork.
8  * (5) fork from inside a tdb_parse() callback.
9  *
10  * Note that we don't hold a lock across tdb_traverse callbacks, so
11  * that doesn't matter.
12  */
13 #include <ccan/tdb2/tdb2.h>
14 #include <ccan/tap/tap.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include "logging.h"
23
24 static enum TDB_ERROR fork_in_parse(TDB_DATA key, TDB_DATA data,
25                                     struct tdb_context *tdb)
26 {
27         int status, extra_messages;
28
29         if (tdb_get_flags(tdb) & TDB_VERSION1) {
30                 extra_messages = 1;
31         } else {
32                 extra_messages = 0;
33         }
34
35         if (fork() == 0) {
36                 /* We expect this to fail. */
37                 if (tdb_store(tdb, key, data, TDB_REPLACE) != TDB_ERR_LOCK)
38                         exit(1);
39                 tap_log_messages -= extra_messages;
40
41                 if (tdb_fetch(tdb, key, &data) != TDB_ERR_LOCK)
42                         exit(1);
43
44                 tap_log_messages -= extra_messages;
45                 if (tap_log_messages != 2)
46                         exit(2);
47
48                 tdb_close(tdb);
49                 if (tap_log_messages != 2)
50                         exit(3);
51                 exit(0);
52         }
53         wait(&status);
54         ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
55         return TDB_SUCCESS;
56 }
57
58 int main(int argc, char *argv[])
59 {
60         unsigned int i;
61         struct tdb_context *tdb;
62         int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
63                         TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
64                         TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
65                         TDB_CONVERT|TDB_VERSION1,
66                         TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
67         struct tdb_data key = tdb_mkdata("key", 3);
68         struct tdb_data data = tdb_mkdata("data", 4);
69
70         plan_tests(sizeof(flags) / sizeof(flags[0]) * 14);
71         for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
72                 int status, extra_messages;
73
74                 if (flags[i] & TDB_VERSION1) {
75                         extra_messages = 1;
76                 } else {
77                         extra_messages = 0;
78                 }
79
80                 tap_log_messages = 0;
81
82                 tdb = tdb_open("run-fork-test.tdb", flags[i],
83                                O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
84                 if (!ok1(tdb))
85                         continue;
86
87                 /* Put a record in here. */
88                 ok1(tdb_store(tdb, key, data, TDB_REPLACE) == TDB_SUCCESS);
89
90                 ok1(tdb_chainlock(tdb, key) == TDB_SUCCESS);
91                 if (fork() == 0) {
92                         /* We expect this to fail. */
93                         if (tdb_store(tdb, key, data, TDB_REPLACE) != TDB_ERR_LOCK)
94                                 return 1;
95                         tap_log_messages -= extra_messages;
96
97                         if (tdb_fetch(tdb, key, &data) != TDB_ERR_LOCK)
98                                 return 1;
99                         tap_log_messages -= extra_messages;
100
101                         if (tap_log_messages != 2)
102                                 return 2;
103
104                         tdb_chainunlock(tdb, key);
105                         if (tap_log_messages != 3)
106                                 return 3;
107                         tdb_close(tdb);
108                         if (tap_log_messages != 3)
109                                 return 4;
110                         return 0;
111                 }
112                 wait(&status);
113                 ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
114                 tdb_chainunlock(tdb, key);
115
116                 ok1(tdb_lockall(tdb) == TDB_SUCCESS);
117                 if (fork() == 0) {
118                         /* We expect this to fail. */
119                         if (tdb_store(tdb, key, data, TDB_REPLACE) != TDB_ERR_LOCK)
120                                 return 1;
121                         tap_log_messages -= extra_messages;
122
123                         if (tdb_fetch(tdb, key, &data) != TDB_ERR_LOCK)
124                                 return 1;
125                         tap_log_messages -= extra_messages;
126
127                         if (tap_log_messages != 2)
128                                 return 2;
129
130                         tdb_unlockall(tdb);
131                         if (tap_log_messages != 2)
132                                 return 3;
133                         tdb_close(tdb);
134                         if (tap_log_messages != 2)
135                                 return 4;
136                         return 0;
137                 }
138                 wait(&status);
139                 ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
140                 tdb_unlockall(tdb);
141
142                 ok1(tdb_lockall_read(tdb) == TDB_SUCCESS);
143                 if (fork() == 0) {
144                         /* We expect this to fail. */
145                         /* This would always fail anyway... */
146                         if (tdb_store(tdb, key, data, TDB_REPLACE) != TDB_ERR_LOCK)
147                                 return 1;
148                         tap_log_messages -= extra_messages;
149
150                         if (tdb_fetch(tdb, key, &data) != TDB_ERR_LOCK)
151                                 return 1;
152                         tap_log_messages -= extra_messages;
153
154                         if (tap_log_messages != 2)
155                                 return 2;
156
157                         tdb_unlockall_read(tdb);
158                         if (tap_log_messages != 2)
159                                 return 3;
160                         tdb_close(tdb);
161                         if (tap_log_messages != 2)
162                                 return 4;
163                         return 0;
164                 }
165                 wait(&status);
166                 ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
167                 tdb_unlockall_read(tdb);
168
169                 ok1(tdb_transaction_start(tdb) == TDB_SUCCESS);
170                 /* If transactions is empty, noop "commit" succeeds. */
171                 ok1(tdb_delete(tdb, key) == TDB_SUCCESS);
172                 if (fork() == 0) {
173                         /* We expect this to fail. */
174                         if (tdb_store(tdb, key, data, TDB_REPLACE) != TDB_ERR_LOCK)
175                                 return 1;
176                         tap_log_messages -= extra_messages;
177
178                         if (tdb_fetch(tdb, key, &data) != TDB_ERR_LOCK)
179                                 return 1;
180                         tap_log_messages -= extra_messages;
181
182                         if (tap_log_messages != 2)
183                                 return 2;
184
185                         if (tdb_transaction_commit(tdb) != TDB_ERR_LOCK)
186                                 return 3;
187                         tap_log_messages -= extra_messages;
188
189                         tdb_close(tdb);
190                         if (tap_log_messages < 3)
191                                 return 4;
192                         return 0;
193                 }
194                 wait(&status);
195                 ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
196                 tdb_transaction_cancel(tdb);
197
198                 ok1(tdb_parse_record(tdb, key, fork_in_parse, tdb)
199                     == TDB_SUCCESS);
200                 tdb_close(tdb);
201                 ok1(tap_log_messages == 0);
202         }
203         return exit_status();
204 }