tdb2: allow multiple chain locks.
[ccan] / ccan / tdb2 / test / run-82-lockattr.c
1 #include <ccan/tdb2/tdb.c>
2 #include <ccan/tdb2/open.c>
3 #include <ccan/tdb2/free.c>
4 #include <ccan/tdb2/lock.c>
5 #include <ccan/tdb2/io.c>
6 #include <ccan/tdb2/hash.c>
7 #include <ccan/tdb2/check.c>
8 #include <ccan/tdb2/transaction.c>
9 #include <ccan/tdb2/traverse.c>
10 #include <ccan/tap/tap.h>
11 #include "logging.h"
12
13 static int mylock(int fd, int rw, off_t off, off_t len, bool waitflag,
14                   void *_err)
15 {
16         int *lock_err = _err;
17         struct flock fl;
18         int ret;
19
20         if (*lock_err) {
21                 errno = *lock_err;
22                 return -1;
23         }
24
25         do {
26                 fl.l_type = rw;
27                 fl.l_whence = SEEK_SET;
28                 fl.l_start = off;
29                 fl.l_len = len;
30
31                 if (waitflag)
32                         ret = fcntl(fd, F_SETLKW, &fl);
33                 else
34                         ret = fcntl(fd, F_SETLK, &fl);
35         } while (ret != 0 && errno == EINTR);
36
37         return ret;
38 }
39
40 static int myunlock(int fd, int rw, off_t off, off_t len, void *_err)
41 {
42         int *lock_err = _err;
43         struct flock fl;
44         int ret;
45
46         if (*lock_err) {
47                 errno = *lock_err;
48                 return -1;
49         }
50
51         do {
52                 fl.l_type = F_UNLCK;
53                 fl.l_whence = SEEK_SET;
54                 fl.l_start = off;
55                 fl.l_len = len;
56
57                 ret = fcntl(fd, F_SETLKW, &fl);
58         } while (ret != 0 && errno == EINTR);
59
60         return ret;
61 }
62
63 static int trav_err;
64 static int trav(struct tdb_context *tdb, TDB_DATA k, TDB_DATA d, int *err)
65 {
66         *err = trav_err;
67         return 0;
68 }
69
70 int main(int argc, char *argv[])
71 {
72         unsigned int i;
73         struct tdb_context *tdb;
74         int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
75                         TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT };
76         union tdb_attribute lock_attr;
77         struct tdb_data key = tdb_mkdata("key", 3);
78         struct tdb_data data = tdb_mkdata("data", 4);
79         int lock_err;
80
81         lock_attr.base.attr = TDB_ATTRIBUTE_FLOCK;
82         lock_attr.base.next = &tap_log_attr;
83         lock_attr.flock.lock = mylock;
84         lock_attr.flock.unlock = myunlock;
85         lock_attr.flock.data = &lock_err;
86
87         plan_tests(sizeof(flags) / sizeof(flags[0]) * 80);
88
89         for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
90                 struct tdb_data d;
91
92                 /* Nonblocking open; expect no error message. */
93                 lock_err = EAGAIN;
94                 tdb = tdb_open("run-82-lockattr.tdb", flags[i],
95                                O_RDWR|O_CREAT|O_TRUNC, 0600, &lock_attr);
96                 ok(errno == lock_err, "Errno is %u", errno);
97                 ok1(!tdb);
98                 ok1(tap_log_messages == 0);
99
100                 lock_err = EINTR;
101                 tdb = tdb_open("run-82-lockattr.tdb", flags[i],
102                                O_RDWR|O_CREAT|O_TRUNC, 0600, &lock_attr);
103                 ok(errno == lock_err, "Errno is %u", errno);
104                 ok1(!tdb);
105                 ok1(tap_log_messages == 0);
106
107                 /* Forced fail open. */
108                 lock_err = ENOMEM;
109                 tdb = tdb_open("run-82-lockattr.tdb", flags[i],
110                                O_RDWR|O_CREAT|O_TRUNC, 0600, &lock_attr);
111                 ok1(errno == lock_err);
112                 ok1(!tdb);
113                 ok1(tap_log_messages == 1);
114                 tap_log_messages = 0;
115
116                 lock_err = 0;
117                 tdb = tdb_open("run-82-lockattr.tdb", flags[i],
118                                O_RDWR|O_CREAT|O_TRUNC, 0600, &lock_attr);
119                 if (!ok1(tdb))
120                         continue;
121                 ok1(tap_log_messages == 0);
122
123                 /* Nonblocking store. */
124                 lock_err = EAGAIN;
125                 ok1(tdb_store(tdb, key, data, TDB_REPLACE) == TDB_ERR_LOCK);
126                 ok1(tap_log_messages == 0);
127                 lock_err = EINTR;
128                 ok1(tdb_store(tdb, key, data, TDB_REPLACE) == TDB_ERR_LOCK);
129                 ok1(tap_log_messages == 0);
130                 lock_err = ENOMEM;
131                 ok1(tdb_store(tdb, key, data, TDB_REPLACE) == TDB_ERR_LOCK);
132                 ok1(tap_log_messages == 1);
133                 tap_log_messages = 0;
134
135                 /* Nonblocking fetch. */
136                 lock_err = EAGAIN;
137                 ok1(!tdb_exists(tdb, key));
138                 ok1(tap_log_messages == 0);
139                 lock_err = EINTR;
140                 ok1(!tdb_exists(tdb, key));
141                 ok1(tap_log_messages == 0);
142                 lock_err = ENOMEM;
143                 ok1(!tdb_exists(tdb, key));
144                 ok1(tap_log_messages == 1);
145                 tap_log_messages = 0;
146
147                 lock_err = EAGAIN;
148                 ok1(tdb_fetch(tdb, key, &d) == TDB_ERR_LOCK);
149                 ok1(tap_log_messages == 0);
150                 lock_err = EINTR;
151                 ok1(tdb_fetch(tdb, key, &d) == TDB_ERR_LOCK);
152                 ok1(tap_log_messages == 0);
153                 lock_err = ENOMEM;
154                 ok1(tdb_fetch(tdb, key, &d) == TDB_ERR_LOCK);
155                 ok1(tap_log_messages == 1);
156                 tap_log_messages = 0;
157
158                 /* Nonblocking delete. */
159                 lock_err = EAGAIN;
160                 ok1(tdb_delete(tdb, key) == TDB_ERR_LOCK);
161                 ok1(tap_log_messages == 0);
162                 lock_err = EINTR;
163                 ok1(tdb_delete(tdb, key) == TDB_ERR_LOCK);
164                 ok1(tap_log_messages == 0);
165                 lock_err = ENOMEM;
166                 ok1(tdb_delete(tdb, key) == TDB_ERR_LOCK);
167                 ok1(tap_log_messages == 1);
168                 tap_log_messages = 0;
169
170                 /* Nonblocking locks. */
171                 lock_err = EAGAIN;
172                 ok1(tdb_chainlock(tdb, key) == TDB_ERR_LOCK);
173                 ok1(tap_log_messages == 0);
174                 lock_err = EINTR;
175                 ok1(tdb_chainlock(tdb, key) == TDB_ERR_LOCK);
176                 ok1(tap_log_messages == 0);
177                 lock_err = ENOMEM;
178                 ok1(tdb_chainlock(tdb, key) == TDB_ERR_LOCK);
179                 ok1(tap_log_messages == 1);
180                 tap_log_messages = 0;
181
182                 lock_err = EAGAIN;
183                 ok1(tdb_chainlock_read(tdb, key) == TDB_ERR_LOCK);
184                 ok1(tap_log_messages == 0);
185                 lock_err = EINTR;
186                 ok1(tdb_chainlock_read(tdb, key) == TDB_ERR_LOCK);
187                 ok1(tap_log_messages == 0);
188                 lock_err = ENOMEM;
189                 ok1(tdb_chainlock_read(tdb, key) == TDB_ERR_LOCK);
190                 ok1(tap_log_messages == 1);
191                 tap_log_messages = 0;
192
193                 lock_err = EAGAIN;
194                 ok1(tdb_lockall(tdb) == TDB_ERR_LOCK);
195                 ok1(tap_log_messages == 0);
196                 lock_err = EINTR;
197                 ok1(tdb_lockall(tdb) == TDB_ERR_LOCK);
198                 ok1(tap_log_messages == 0);
199                 lock_err = ENOMEM;
200                 ok1(tdb_lockall(tdb) == TDB_ERR_LOCK);
201                 /* This actually does divide and conquer. */
202                 ok1(tap_log_messages > 0);
203                 tap_log_messages = 0;
204
205                 lock_err = EAGAIN;
206                 ok1(tdb_lockall_read(tdb) == TDB_ERR_LOCK);
207                 ok1(tap_log_messages == 0);
208                 lock_err = EINTR;
209                 ok1(tdb_lockall_read(tdb) == TDB_ERR_LOCK);
210                 ok1(tap_log_messages == 0);
211                 lock_err = ENOMEM;
212                 ok1(tdb_lockall_read(tdb) == TDB_ERR_LOCK);
213                 ok1(tap_log_messages > 0);
214                 tap_log_messages = 0;
215
216                 /* Nonblocking traverse; go nonblock partway through. */
217                 lock_err = 0;
218                 ok1(tdb_store(tdb, key, data, TDB_REPLACE) == 0);
219                 trav_err = EAGAIN;
220                 ok1(tdb_traverse(tdb, trav, &lock_err) == TDB_ERR_LOCK);
221                 ok1(tap_log_messages == 0);
222                 trav_err = EINTR;
223                 lock_err = 0;
224                 ok1(tdb_traverse(tdb, trav, &lock_err) == TDB_ERR_LOCK);
225                 ok1(tap_log_messages == 0);
226                 trav_err = ENOMEM;
227                 lock_err = 0;
228                 ok1(tdb_traverse(tdb, trav, &lock_err) == TDB_ERR_LOCK);
229                 ok1(tap_log_messages == 1);
230                 tap_log_messages = 0;
231
232                 /* Nonblocking transactions. */
233                 lock_err = EAGAIN;
234                 ok1(tdb_transaction_start(tdb) == TDB_ERR_LOCK);
235                 ok1(tap_log_messages == 0);
236                 lock_err = EINTR;
237                 ok1(tdb_transaction_start(tdb) == TDB_ERR_LOCK);
238                 ok1(tap_log_messages == 0);
239                 lock_err = ENOMEM;
240                 ok1(tdb_transaction_start(tdb) == TDB_ERR_LOCK);
241                 ok1(tap_log_messages == 1);
242                 tap_log_messages = 0;
243
244                 /* Nonblocking transaction prepare. */
245                 lock_err = 0;
246                 ok1(tdb_transaction_start(tdb) == 0);
247                 ok1(tdb_delete(tdb, key) == 0);
248
249                 lock_err = EAGAIN;
250                 ok1(tdb_transaction_prepare_commit(tdb) == TDB_ERR_LOCK);
251                 ok1(tap_log_messages == 0);
252
253                 lock_err = 0;
254                 ok1(tdb_transaction_prepare_commit(tdb) == 0);
255                 ok1(tdb_transaction_commit(tdb) == 0);
256
257                 /* And the transaction was committed, right? */
258                 ok1(!tdb_exists(tdb, key));
259                 tdb_close(tdb);
260                 ok1(tap_log_messages == 0);
261         }
262         return exit_status();
263 }