]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2019 Red Hat Ltd | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include "gtest/gtest.h" | |
1e59de90 | 16 | #include "include/compat.h" |
92f5a8d4 TL |
17 | #include "include/cephfs/libcephfs.h" |
18 | #include "include/rados/librados.h" | |
19 | #include <errno.h> | |
20 | #include <fcntl.h> | |
21 | #include <unistd.h> | |
22 | #include <sys/types.h> | |
23 | #include <sys/stat.h> | |
24 | #include <dirent.h> | |
9f95a23c | 25 | #if defined(__linux__) |
92f5a8d4 | 26 | #include <sys/xattr.h> |
9f95a23c | 27 | #endif |
92f5a8d4 TL |
28 | |
29 | rados_t cluster; | |
30 | ||
31 | TEST(LibCephFS, LazyIOOneWriterMulipleReaders) { | |
32 | struct ceph_mount_info *ca, *cb; | |
33 | ASSERT_EQ(ceph_create(&ca, NULL), 0); | |
34 | ASSERT_EQ(ceph_conf_read_file(ca, NULL), 0); | |
35 | ASSERT_EQ(0, ceph_conf_parse_env(ca, NULL)); | |
36 | ASSERT_EQ(ceph_mount(ca, NULL), 0); | |
37 | ||
38 | ASSERT_EQ(ceph_create(&cb, NULL), 0); | |
39 | ASSERT_EQ(ceph_conf_read_file(cb, NULL), 0); | |
40 | ASSERT_EQ(0, ceph_conf_parse_env(cb, NULL)); | |
41 | ASSERT_EQ(ceph_mount(cb, NULL), 0); | |
42 | ||
43 | char name[20]; | |
44 | snprintf(name, sizeof(name), "foo.%d", getpid()); | |
45 | ||
46 | int fda = ceph_open(ca, name, O_CREAT|O_RDWR, 0644); | |
47 | ASSERT_LE(0, fda); | |
48 | ||
49 | int fdb = ceph_open(cb, name, O_RDONLY, 0644); | |
50 | ASSERT_LE(0, fdb); | |
51 | ||
52 | ASSERT_EQ(0, ceph_lazyio(ca, fda, 1)); | |
53 | ASSERT_EQ(0, ceph_lazyio(cb, fdb, 1)); | |
54 | ||
55 | char out_buf[] = "fooooooooo"; | |
56 | ||
57 | /* Client a issues a write and propagates/flushes the buffer */ | |
58 | ASSERT_EQ((int)sizeof(out_buf), ceph_write(ca, fda, out_buf, sizeof(out_buf), 0)); | |
59 | ASSERT_EQ(0, ceph_lazyio_propagate(ca, fda, 0, 0)); | |
60 | ||
61 | /* Client a issues a write and propagates/flushes the buffer */ | |
62 | ASSERT_EQ((int)sizeof(out_buf), ceph_write(ca, fda, out_buf, sizeof(out_buf), 10)); | |
63 | ASSERT_EQ(0, ceph_lazyio_propagate(ca, fda, 0, 0)); | |
64 | ||
65 | char in_buf[40]; | |
66 | /* Calling ceph_lazyio_synchronize here will invalidate client b's cache and hence enable client a to fetch the propagated write of client a in the subsequent read */ | |
67 | ASSERT_EQ(0, ceph_lazyio_synchronize(cb, fdb, 0, 0)); | |
68 | ASSERT_EQ(ceph_read(cb, fdb, in_buf, sizeof(in_buf), 0), 2*strlen(out_buf)+1); | |
69 | ASSERT_STREQ(in_buf, "fooooooooofooooooooo"); | |
70 | ||
71 | /* Client a does not need to call ceph_lazyio_synchronize here because it is the latest writer and fda holds the updated inode*/ | |
72 | ASSERT_EQ(ceph_read(ca, fda, in_buf, sizeof(in_buf), 0), 2*strlen(out_buf)+1); | |
73 | ASSERT_STREQ(in_buf, "fooooooooofooooooooo"); | |
74 | ||
75 | ceph_close(ca, fda); | |
76 | ceph_close(cb, fdb); | |
77 | ||
78 | ceph_shutdown(ca); | |
79 | ceph_shutdown(cb); | |
80 | } | |
81 | ||
82 | TEST(LibCephFS, LazyIOMultipleWritersMulipleReaders) { | |
83 | struct ceph_mount_info *ca, *cb; | |
84 | ASSERT_EQ(ceph_create(&ca, NULL), 0); | |
85 | ASSERT_EQ(ceph_conf_read_file(ca, NULL), 0); | |
86 | ASSERT_EQ(0, ceph_conf_parse_env(ca, NULL)); | |
87 | ASSERT_EQ(ceph_mount(ca, NULL), 0); | |
88 | ||
89 | ASSERT_EQ(ceph_create(&cb, NULL), 0); | |
90 | ASSERT_EQ(ceph_conf_read_file(cb, NULL), 0); | |
91 | ASSERT_EQ(0, ceph_conf_parse_env(cb, NULL)); | |
92 | ASSERT_EQ(ceph_mount(cb, NULL), 0); | |
93 | ||
94 | char name[20]; | |
95 | snprintf(name, sizeof(name), "foo2.%d", getpid()); | |
96 | ||
97 | int fda = ceph_open(ca, name, O_CREAT|O_RDWR, 0644); | |
98 | ASSERT_LE(0, fda); | |
99 | ||
100 | int fdb = ceph_open(cb, name, O_RDWR, 0644); | |
101 | ASSERT_LE(0, fdb); | |
102 | ||
103 | ASSERT_EQ(0, ceph_lazyio(ca, fda, 1)); | |
104 | ASSERT_EQ(0, ceph_lazyio(cb, fdb, 1)); | |
105 | ||
106 | char out_buf[] = "fooooooooo"; | |
107 | /* Client a issues a write and propagates/flushes the buffer */ | |
108 | ASSERT_EQ((int)sizeof(out_buf), ceph_write(ca, fda, out_buf, sizeof(out_buf), 0)); | |
109 | ASSERT_EQ(0, ceph_lazyio_propagate(ca, fda, 0, 0)); | |
110 | ||
111 | /* Client b issues a write and propagates/flushes the buffer*/ | |
112 | ASSERT_EQ((int)sizeof(out_buf), ceph_write(cb, fdb, out_buf, sizeof(out_buf), 10)); | |
113 | ASSERT_EQ(0, ceph_lazyio_propagate(cb, fdb, 0, 0)); | |
114 | ||
115 | char in_buf[40]; | |
116 | /* Calling ceph_lazyio_synchronize here will invalidate client a's cache and hence enable client a to fetch the propagated writes of client b in the subsequent read */ | |
117 | ASSERT_EQ(0, ceph_lazyio_synchronize(ca, fda, 0, 0)); | |
118 | ASSERT_EQ(ceph_read(ca, fda, in_buf, sizeof(in_buf), 0), 2*strlen(out_buf)+1); | |
119 | ASSERT_STREQ(in_buf, "fooooooooofooooooooo"); | |
120 | ||
121 | /* Client b does not need to call ceph_lazyio_synchronize here because it is the latest writer and the writes before it have already been propagated*/ | |
122 | ASSERT_EQ(ceph_read(cb, fdb, in_buf, sizeof(in_buf), 0), 2*strlen(out_buf)+1); | |
123 | ASSERT_STREQ(in_buf, "fooooooooofooooooooo"); | |
124 | ||
125 | /* Client a issues a write */ | |
126 | char wait_out_buf[] = "foobarbars"; | |
127 | ASSERT_EQ((int)sizeof(wait_out_buf), ceph_write(ca, fda, wait_out_buf, sizeof(wait_out_buf), 20)); | |
128 | ASSERT_EQ(0, ceph_lazyio_propagate(ca, fda, 0, 0)); | |
129 | ||
130 | /* Client a does not need to call ceph_lazyio_synchronize here because it is the latest writer and the writes before it have already been propagated*/ | |
131 | ASSERT_EQ(ceph_read(ca, fda, in_buf, sizeof(in_buf), 0), (2*(strlen(out_buf)))+strlen(wait_out_buf)+1); | |
132 | ASSERT_STREQ(in_buf, "fooooooooofooooooooofoobarbars"); | |
133 | ||
134 | /* Calling ceph_lazyio_synchronize here will invalidate client b's cache and hence enable client a to fetch the propagated write of client a in the subsequent read */ | |
135 | ASSERT_EQ(0, ceph_lazyio_synchronize(cb, fdb, 0, 0)); | |
136 | ASSERT_EQ(ceph_read(cb, fdb, in_buf, sizeof(in_buf), 0), (2*(strlen(out_buf)))+strlen(wait_out_buf)+1); | |
137 | ASSERT_STREQ(in_buf, "fooooooooofooooooooofoobarbars"); | |
138 | ||
139 | ceph_close(ca, fda); | |
140 | ceph_close(cb, fdb); | |
141 | ||
142 | ceph_shutdown(ca); | |
143 | ceph_shutdown(cb); | |
144 | } | |
145 | ||
146 | TEST(LibCephFS, LazyIOMultipleWritersOneReader) { | |
147 | struct ceph_mount_info *ca, *cb; | |
148 | ASSERT_EQ(ceph_create(&ca, NULL), 0); | |
149 | ASSERT_EQ(ceph_conf_read_file(ca, NULL), 0); | |
150 | ASSERT_EQ(0, ceph_conf_parse_env(ca, NULL)); | |
151 | ASSERT_EQ(ceph_mount(ca, NULL), 0); | |
152 | ||
153 | ASSERT_EQ(ceph_create(&cb, NULL), 0); | |
154 | ASSERT_EQ(ceph_conf_read_file(cb, NULL), 0); | |
155 | ASSERT_EQ(0, ceph_conf_parse_env(cb, NULL)); | |
156 | ASSERT_EQ(ceph_mount(cb, NULL), 0); | |
157 | ||
158 | char name[20]; | |
159 | snprintf(name, sizeof(name), "foo3.%d", getpid()); | |
160 | ||
161 | int fda = ceph_open(ca, name, O_CREAT|O_RDWR, 0644); | |
162 | ASSERT_LE(0, fda); | |
163 | ||
164 | int fdb = ceph_open(cb, name, O_RDWR, 0644); | |
165 | ASSERT_LE(0, fdb); | |
166 | ||
167 | ASSERT_EQ(0, ceph_lazyio(ca, fda, 1)); | |
168 | ASSERT_EQ(0, ceph_lazyio(cb, fdb, 1)); | |
169 | ||
170 | char out_buf[] = "fooooooooo"; | |
171 | /* Client a issues a write and propagates/flushes the buffer */ | |
172 | ASSERT_EQ((int)sizeof(out_buf), ceph_write(ca, fda, out_buf, sizeof(out_buf), 0)); | |
173 | ASSERT_EQ(0, ceph_lazyio_propagate(ca, fda, 0, 0)); | |
174 | ||
175 | /* Client b issues a write and propagates/flushes the buffer*/ | |
176 | ASSERT_EQ((int)sizeof(out_buf), ceph_write(cb, fdb, out_buf, sizeof(out_buf), 10)); | |
177 | ASSERT_EQ(0, ceph_lazyio_propagate(cb, fdb, 0, 0)); | |
178 | ||
179 | char in_buf[40]; | |
180 | /* Client a reads the file and verifies that it only reads it's propagated writes and not Client b's*/ | |
181 | ASSERT_EQ(ceph_read(ca, fda, in_buf, sizeof(in_buf), 0), strlen(out_buf)+1); | |
182 | ASSERT_STREQ(in_buf, "fooooooooo"); | |
183 | ||
184 | /* Client a reads the file again, this time with a lazyio_synchronize to check if the cache gets invalidated and data is refetched i.e all the propagated writes are being read*/ | |
185 | ASSERT_EQ(0, ceph_lazyio_synchronize(ca, fda, 0, 0)); | |
186 | ASSERT_EQ(ceph_read(ca, fda, in_buf, sizeof(in_buf), 0), 2*strlen(out_buf)+1); | |
187 | ASSERT_STREQ(in_buf, "fooooooooofooooooooo"); | |
188 | ||
189 | ceph_close(ca, fda); | |
190 | ceph_close(cb, fdb); | |
191 | ||
192 | ceph_shutdown(ca); | |
193 | ceph_shutdown(cb); | |
194 | } | |
195 | ||
196 | TEST(LibCephFS, LazyIOSynchronizeFlush) { | |
197 | /* Test to make sure lazyio_synchronize flushes dirty buffers */ | |
198 | struct ceph_mount_info *ca, *cb; | |
199 | ASSERT_EQ(ceph_create(&ca, NULL), 0); | |
200 | ASSERT_EQ(ceph_conf_read_file(ca, NULL), 0); | |
201 | ASSERT_EQ(0, ceph_conf_parse_env(ca, NULL)); | |
202 | ASSERT_EQ(ceph_mount(ca, NULL), 0); | |
203 | ||
204 | ASSERT_EQ(ceph_create(&cb, NULL), 0); | |
205 | ASSERT_EQ(ceph_conf_read_file(cb, NULL), 0); | |
206 | ASSERT_EQ(0, ceph_conf_parse_env(cb, NULL)); | |
207 | ASSERT_EQ(ceph_mount(cb, NULL), 0); | |
208 | ||
209 | char name[20]; | |
210 | snprintf(name, sizeof(name), "foo4.%d", getpid()); | |
211 | ||
212 | int fda = ceph_open(ca, name, O_CREAT|O_RDWR, 0644); | |
213 | ASSERT_LE(0, fda); | |
214 | ||
215 | int fdb = ceph_open(cb, name, O_RDWR, 0644); | |
216 | ASSERT_LE(0, fdb); | |
217 | ||
218 | ASSERT_EQ(0, ceph_lazyio(ca, fda, 1)); | |
219 | ASSERT_EQ(0, ceph_lazyio(cb, fdb, 1)); | |
220 | ||
221 | char out_buf[] = "fooooooooo"; | |
222 | ||
223 | /* Client a issues a write and propagates it*/ | |
224 | ASSERT_EQ((int)sizeof(out_buf), ceph_write(ca, fda, out_buf, sizeof(out_buf), 0)); | |
225 | ASSERT_EQ(0, ceph_lazyio_propagate(ca, fda, 0, 0)); | |
226 | ||
227 | /* Client b issues writes and without lazyio_propagate*/ | |
228 | ASSERT_EQ((int)sizeof(out_buf), ceph_write(cb, fdb, out_buf, sizeof(out_buf), 10)); | |
229 | ASSERT_EQ((int)sizeof(out_buf), ceph_write(cb, fdb, out_buf, sizeof(out_buf), 20)); | |
230 | ||
231 | char in_buf[40]; | |
232 | /* Calling ceph_lazyio_synchronize here will first flush the possibly pending buffered write of client b and invalidate client b's cache and hence enable client b to fetch all the propagated writes */ | |
233 | ASSERT_EQ(0, ceph_lazyio_synchronize(cb, fdb, 0, 0)); | |
234 | ASSERT_EQ(ceph_read(cb, fdb, in_buf, sizeof(in_buf), 0), 3*strlen(out_buf)+1); | |
235 | ASSERT_STREQ(in_buf, "fooooooooofooooooooofooooooooo"); | |
236 | ||
237 | /* Required to call ceph_lazyio_synchronize here since client b is the latest writer and client a is out of sync with updated file*/ | |
238 | ASSERT_EQ(0, ceph_lazyio_synchronize(ca, fda, 0, 0)); | |
239 | ASSERT_EQ(ceph_read(ca, fda, in_buf, sizeof(in_buf), 0), 3*strlen(out_buf)+1); | |
240 | ASSERT_STREQ(in_buf, "fooooooooofooooooooofooooooooo"); | |
241 | ||
242 | ceph_close(ca, fda); | |
243 | ceph_close(cb, fdb); | |
244 | ||
245 | ceph_shutdown(ca); | |
246 | ceph_shutdown(cb); | |
247 | } | |
248 | ||
249 | TEST(LibCephFS, WithoutandWithLazyIO) { | |
250 | struct ceph_mount_info *ca, *cb; | |
251 | ASSERT_EQ(ceph_create(&ca, NULL), 0); | |
252 | ASSERT_EQ(ceph_conf_read_file(ca, NULL), 0); | |
253 | ASSERT_EQ(0, ceph_conf_parse_env(ca, NULL)); | |
254 | ASSERT_EQ(ceph_mount(ca, NULL), 0); | |
255 | ||
256 | ASSERT_EQ(ceph_create(&cb, NULL), 0); | |
257 | ASSERT_EQ(ceph_conf_read_file(cb, NULL), 0); | |
258 | ASSERT_EQ(0, ceph_conf_parse_env(cb, NULL)); | |
259 | ASSERT_EQ(ceph_mount(cb, NULL), 0); | |
260 | ||
261 | char name[20]; | |
262 | snprintf(name, sizeof(name), "foo5.%d", getpid()); | |
263 | ||
264 | int fda = ceph_open(ca, name, O_CREAT|O_RDWR, 0644); | |
265 | ASSERT_LE(0, fda); | |
266 | ||
267 | int fdb = ceph_open(cb, name, O_RDWR, 0644); | |
268 | ASSERT_LE(0, fdb); | |
269 | ||
270 | char out_buf_w[] = "1234567890"; | |
271 | /* Doing some non lazyio writes and read*/ | |
272 | ASSERT_EQ((int)sizeof(out_buf_w), ceph_write(ca, fda, out_buf_w, sizeof(out_buf_w), 0)); | |
273 | ||
274 | ASSERT_EQ((int)sizeof(out_buf_w), ceph_write(cb, fdb, out_buf_w, sizeof(out_buf_w), 10)); | |
275 | ||
276 | char in_buf_w[30]; | |
277 | ASSERT_EQ(ceph_read(ca, fda, in_buf_w, sizeof(in_buf_w), 0), 2*strlen(out_buf_w)+1); | |
278 | ||
279 | /* Enable lazyio*/ | |
280 | ASSERT_EQ(0, ceph_lazyio(ca, fda, 1)); | |
281 | ASSERT_EQ(0, ceph_lazyio(cb, fdb, 1)); | |
282 | ||
283 | char out_buf[] = "fooooooooo"; | |
284 | ||
285 | /* Client a issues a write and propagates/flushes the buffer*/ | |
286 | ASSERT_EQ((int)sizeof(out_buf), ceph_write(ca, fda, out_buf, sizeof(out_buf), 20)); | |
287 | ASSERT_EQ(0, ceph_lazyio_propagate(ca, fda, 0, 0)); | |
288 | ||
289 | /* Client b issues a write and propagates/flushes the buffer*/ | |
290 | ASSERT_EQ((int)sizeof(out_buf), ceph_write(cb, fdb, out_buf, sizeof(out_buf), 30)); | |
291 | ASSERT_EQ(0, ceph_lazyio_propagate(cb, fdb, 0, 0)); | |
292 | ||
293 | char in_buf[50]; | |
294 | /* Calling ceph_lazyio_synchronize here will invalidate client a's cache and hence enable client a to fetch the propagated writes of client b in the subsequent read */ | |
295 | ASSERT_EQ(0, ceph_lazyio_synchronize(ca, fda, 0, 0)); | |
296 | ASSERT_EQ(ceph_read(ca, fda, in_buf, sizeof(in_buf), 0), (2*(strlen(out_buf)))+(2*(strlen(out_buf_w)))+1); | |
297 | ASSERT_STREQ(in_buf, "12345678901234567890fooooooooofooooooooo"); | |
298 | ||
299 | /* Client b does not need to call ceph_lazyio_synchronize here because it is the latest writer and the writes before it have already been propagated*/ | |
300 | ASSERT_EQ(ceph_read(cb, fdb, in_buf, sizeof(in_buf), 0), (2*(strlen(out_buf)))+(2*(strlen(out_buf_w)))+1); | |
301 | ASSERT_STREQ(in_buf, "12345678901234567890fooooooooofooooooooo"); | |
302 | ||
303 | ceph_close(ca, fda); | |
304 | ceph_close(cb, fdb); | |
305 | ||
306 | ceph_shutdown(ca); | |
307 | ceph_shutdown(cb); | |
308 | } | |
309 | ||
310 | static int update_root_mode() | |
311 | { | |
312 | struct ceph_mount_info *admin; | |
313 | int r = ceph_create(&admin, NULL); | |
314 | if (r < 0) | |
315 | return r; | |
316 | ceph_conf_read_file(admin, NULL); | |
317 | ceph_conf_parse_env(admin, NULL); | |
318 | ceph_conf_set(admin, "client_permissions", "false"); | |
319 | r = ceph_mount(admin, "/"); | |
320 | if (r < 0) | |
321 | goto out; | |
322 | r = ceph_chmod(admin, "/", 0777); | |
323 | out: | |
324 | ceph_shutdown(admin); | |
325 | return r; | |
326 | } | |
327 | ||
328 | int main(int argc, char **argv) | |
329 | { | |
330 | int r = update_root_mode(); | |
331 | if (r < 0) | |
332 | exit(1); | |
333 | ||
334 | ::testing::InitGoogleTest(&argc, argv); | |
335 | ||
336 | srand(getpid()); | |
337 | ||
338 | r = rados_create(&cluster, NULL); | |
339 | if (r < 0) | |
340 | exit(1); | |
341 | ||
342 | r = rados_conf_read_file(cluster, NULL); | |
343 | if (r < 0) | |
344 | exit(1); | |
345 | ||
346 | rados_conf_parse_env(cluster, NULL); | |
347 | r = rados_connect(cluster); | |
348 | if (r < 0) | |
349 | exit(1); | |
350 | ||
351 | r = RUN_ALL_TESTS(); | |
352 | ||
353 | rados_shutdown(cluster); | |
354 | ||
355 | return r; | |
356 | } |