1#include <IO/ReadBufferAIO.h>
2#include <Core/Defines.h>
3#include <filesystem>
4#include <vector>
5#include <iostream>
6#include <fstream>
7#include <functional>
8#include <cstdlib>
9#include <port/unistd.h>
10
11
12namespace
13{
14
15void run();
16void prepare(std::string & filename, std::string & buf);
17void prepare2(std::string & filename, std::string & buf);
18void prepare3(std::string & filename, std::string & buf);
19void prepare4(std::string & filename, std::string & buf);
20std::string createTmpFile();
21[[noreturn]] void die(const std::string & msg);
22void runTest(unsigned int num, const std::function<bool()> & func);
23
24bool test1(const std::string & filename);
25bool test2(const std::string & filename, const std::string & buf);
26bool test3(const std::string & filename, const std::string & buf);
27bool test4(const std::string & filename, const std::string & buf);
28bool test5(const std::string & filename, const std::string & buf);
29bool test6(const std::string & filename, const std::string & buf);
30bool test7(const std::string & filename, const std::string & buf);
31bool test8(const std::string & filename, const std::string & buf);
32bool test9(const std::string & filename, const std::string & buf);
33bool test10(const std::string & filename, const std::string & buf);
34bool test11(const std::string & filename);
35bool test12(const std::string & filename, const std::string & buf);
36bool test13(const std::string & filename, const std::string & buf);
37bool test14(const std::string & filename, const std::string & buf);
38bool test15(const std::string & filename, const std::string & buf);
39bool test16(const std::string & filename, const std::string & buf);
40bool test17(const std::string & filename, const std::string & buf);
41bool test18(const std::string & filename, const std::string & buf);
42bool test19(const std::string & filename, const std::string & buf);
43bool test20(const std::string & filename, const std::string & buf);
44
45void run()
46{
47 namespace fs = std::filesystem;
48
49 std::string filename;
50 std::string buf;
51 prepare(filename, buf);
52
53 std::string filename2;
54 std::string buf2;
55 prepare(filename2, buf2);
56
57 std::string filename3;
58 std::string buf3;
59 prepare2(filename3, buf3);
60
61 std::string filename4;
62 std::string buf4;
63 prepare3(filename4, buf4);
64
65 std::string filename5;
66 std::string buf5;
67 prepare4(filename5, buf5);
68
69 const std::vector<std::function<bool()>> tests =
70 {
71 std::bind(test1, std::ref(filename)),
72 std::bind(test2, std::ref(filename), std::ref(buf)),
73 std::bind(test3, std::ref(filename), std::ref(buf)),
74 std::bind(test4, std::ref(filename), std::ref(buf)),
75 std::bind(test5, std::ref(filename), std::ref(buf)),
76 std::bind(test6, std::ref(filename), std::ref(buf)),
77 std::bind(test7, std::ref(filename), std::ref(buf)),
78 std::bind(test8, std::ref(filename), std::ref(buf)),
79 std::bind(test9, std::ref(filename), std::ref(buf)),
80 std::bind(test10, std::ref(filename), std::ref(buf)),
81 std::bind(test11, std::ref(filename)),
82 std::bind(test12, std::ref(filename), std::ref(buf)),
83 std::bind(test13, std::ref(filename2), std::ref(buf2)),
84 std::bind(test14, std::ref(filename), std::ref(buf)),
85 std::bind(test15, std::ref(filename3), std::ref(buf3)),
86 std::bind(test16, std::ref(filename3), std::ref(buf3)),
87 std::bind(test17, std::ref(filename4), std::ref(buf4)),
88 std::bind(test18, std::ref(filename5), std::ref(buf5)),
89 std::bind(test19, std::ref(filename), std::ref(buf)),
90 std::bind(test20, std::ref(filename), std::ref(buf))
91 };
92
93 unsigned int num = 0;
94 for (const auto & test : tests)
95 {
96 ++num;
97 runTest(num, test);
98 }
99
100 fs::remove_all(fs::path(filename).parent_path().string());
101 fs::remove_all(fs::path(filename2).parent_path().string());
102 fs::remove_all(fs::path(filename3).parent_path().string());
103 fs::remove_all(fs::path(filename4).parent_path().string());
104 fs::remove_all(fs::path(filename5).parent_path().string());
105}
106
107void prepare(std::string & filename, std::string & buf)
108{
109 static const std::string symbols = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
110
111 filename = createTmpFile();
112
113 size_t n = 10 * DEFAULT_AIO_FILE_BLOCK_SIZE;
114 buf.reserve(n);
115
116 for (size_t i = 0; i < n; ++i)
117 buf += symbols[i % symbols.length()];
118
119 std::ofstream out(filename.c_str());
120 if (!out.is_open())
121 die("Could not open file");
122
123 out << buf;
124}
125
126void prepare2(std::string & filename, std::string & buf)
127{
128 filename = createTmpFile();
129
130 buf = "122333444455555666666777777788888888999999999";
131
132 std::ofstream out(filename.c_str());
133 if (!out.is_open())
134 die("Could not open file");
135
136 out << buf;
137}
138
139void prepare3(std::string & filename, std::string & buf)
140{
141 filename = createTmpFile();
142
143 buf = "122333444455555666666777777788888888999999999";
144
145 std::ofstream out(filename.c_str());
146 if (!out.is_open())
147 die("Could not open file");
148
149 out.seekp(7, std::ios_base::beg);
150 out << buf;
151}
152
153void prepare4(std::string & filename, std::string & buf)
154{
155 static const std::string symbols = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
156
157 filename = createTmpFile();
158
159 std::ofstream out(filename.c_str());
160 if (!out.is_open())
161 die("Could not open file");
162
163 for (size_t i = 0; i < 1340; ++i)
164 buf += symbols[i % symbols.length()];
165
166 out.seekp(2984, std::ios_base::beg);
167 out << buf;
168}
169
170std::string createTmpFile()
171{
172 char pattern[] = "/tmp/fileXXXXXX";
173 char * dir = ::mkdtemp(pattern);
174 if (dir == nullptr)
175 die("Could not create directory");
176
177 return std::string(dir) + "/foo";
178}
179
180void die(const std::string & msg)
181{
182 std::cout << msg << "\n";
183 ::exit(EXIT_FAILURE);
184}
185
186void runTest(unsigned int num, const std::function<bool()> & func)
187{
188 bool ok;
189
190 try
191 {
192 ok = func();
193 }
194 catch (const DB::Exception & ex)
195 {
196 ok = false;
197 std::cout << "Caught exception " << ex.displayText() << "\n";
198 }
199 catch (const std::exception & ex)
200 {
201 ok = false;
202 std::cout << "Caught exception " << ex.what() << "\n";
203 }
204
205 if (ok)
206 std::cout << "Test " << num << " passed\n";
207 else
208 std::cout << "Test " << num << " failed\n";
209}
210
211bool test1(const std::string & filename)
212{
213 DB::ReadBufferAIO in(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
214 if (in.getFileName() != filename)
215 return false;
216 if (in.getFD() == -1)
217 return false;
218 return true;
219}
220
221bool test2(const std::string & filename, const std::string & buf)
222{
223 std::string newbuf;
224 newbuf.resize(buf.length());
225
226 DB::ReadBufferAIO in(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
227 size_t count = in.read(newbuf.data(), newbuf.length());
228 if (count != newbuf.length())
229 return false;
230
231 return (newbuf == buf);
232}
233
234bool test3(const std::string & filename, const std::string & buf)
235{
236 std::string newbuf;
237 newbuf.resize(buf.length());
238
239 size_t requested = 9 * DEFAULT_AIO_FILE_BLOCK_SIZE;
240
241 DB::ReadBufferAIO in(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
242 in.setMaxBytes(requested);
243 size_t count = in.read(newbuf.data(), newbuf.length());
244
245 newbuf.resize(count);
246 return (newbuf == buf.substr(0, requested));
247}
248
249bool test4(const std::string & filename, const std::string & buf)
250{
251 std::string newbuf;
252 newbuf.resize(buf.length());
253
254 DB::ReadBufferAIO in(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
255 in.setMaxBytes(0);
256 size_t n_read = in.read(newbuf.data(), newbuf.length());
257
258 return n_read == 0;
259}
260
261bool test5(const std::string & filename, const std::string & buf)
262{
263 std::string newbuf;
264 newbuf.resize(1 + (DEFAULT_AIO_FILE_BLOCK_SIZE >> 1));
265
266 DB::ReadBufferAIO in(filename, DEFAULT_AIO_FILE_BLOCK_SIZE);
267 in.setMaxBytes(1 + (DEFAULT_AIO_FILE_BLOCK_SIZE >> 1));
268
269 size_t count = in.read(newbuf.data(), newbuf.length());
270 if (count != newbuf.length())
271 return false;
272
273 if (newbuf != buf.substr(0, newbuf.length()))
274 return false;
275
276 return true;
277}
278
279bool test6(const std::string & filename, const std::string & buf)
280{
281 std::string newbuf;
282 newbuf.resize(buf.length());
283
284 DB::ReadBufferAIO in(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
285
286 if (in.getPositionInFile() != 0)
287 return false;
288
289 size_t count = in.read(newbuf.data(), newbuf.length());
290 if (count != newbuf.length())
291 return false;
292
293 if (static_cast<size_t>(in.getPositionInFile()) != buf.length())
294 return false;
295
296 return true;
297}
298
299bool test7(const std::string & filename, const std::string & buf)
300{
301 std::string newbuf;
302 newbuf.resize(buf.length() - DEFAULT_AIO_FILE_BLOCK_SIZE);
303
304 DB::ReadBufferAIO in(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
305 (void) in.seek(DEFAULT_AIO_FILE_BLOCK_SIZE, SEEK_SET);
306 size_t count = in.read(newbuf.data(), newbuf.length());
307 if (count != (9 * DEFAULT_AIO_FILE_BLOCK_SIZE))
308 return false;
309
310 return (newbuf == buf.substr(DEFAULT_AIO_FILE_BLOCK_SIZE));
311}
312
313bool test8(const std::string & filename, const std::string & buf)
314{
315 std::string newbuf;
316 newbuf.resize(DEFAULT_AIO_FILE_BLOCK_SIZE - 1);
317
318 DB::ReadBufferAIO in(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
319 (void) in.seek(DEFAULT_AIO_FILE_BLOCK_SIZE + 1, SEEK_CUR);
320 size_t count = in.read(newbuf.data(), newbuf.length());
321
322 if (count != newbuf.length())
323 return false;
324
325 if (newbuf != buf.substr(DEFAULT_AIO_FILE_BLOCK_SIZE + 1, newbuf.length()))
326 return false;
327
328 return true;
329}
330
331bool test9(const std::string & filename, const std::string & buf)
332{
333 bool ok = false;
334
335 try
336 {
337 std::string newbuf;
338 newbuf.resize(buf.length());
339
340 DB::ReadBufferAIO in(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
341 size_t count = in.read(newbuf.data(), newbuf.length());
342 if (count != newbuf.length())
343 return false;
344 in.setMaxBytes(9 * DEFAULT_AIO_FILE_BLOCK_SIZE);
345 }
346 catch (const DB::Exception &)
347 {
348 ok = true;
349 }
350
351 return ok;
352}
353
354bool test10(const std::string & filename, const std::string & buf)
355{
356 DB::ReadBufferAIO in(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
357
358 {
359 std::string newbuf;
360 newbuf.resize(4 * DEFAULT_AIO_FILE_BLOCK_SIZE);
361
362 size_t count1 = in.read(newbuf.data(), newbuf.length());
363 if (count1 != newbuf.length())
364 return false;
365
366 if (newbuf != buf.substr(0, 4 * DEFAULT_AIO_FILE_BLOCK_SIZE))
367 return false;
368 }
369
370 (void) in.seek(2 * DEFAULT_AIO_FILE_BLOCK_SIZE, SEEK_CUR);
371
372 {
373 std::string newbuf;
374 newbuf.resize(4 * DEFAULT_AIO_FILE_BLOCK_SIZE);
375
376 size_t count2 = in.read(newbuf.data(), newbuf.length());
377 if (count2 != newbuf.length())
378 return false;
379
380 if (newbuf != buf.substr(6 * DEFAULT_AIO_FILE_BLOCK_SIZE))
381 return false;
382 }
383
384 return true;
385}
386
387bool test11(const std::string & filename)
388{
389 bool ok = false;
390
391 try
392 {
393 DB::ReadBufferAIO in(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
394 (void) in.seek(-DEFAULT_AIO_FILE_BLOCK_SIZE, SEEK_SET);
395 }
396 catch (const DB::Exception &)
397 {
398 ok = true;
399 }
400
401 return ok;
402}
403
404bool test12(const std::string & filename, const std::string &)
405{
406 bool ok = false;
407
408 try
409 {
410 std::string newbuf;
411 newbuf.resize(4 * DEFAULT_AIO_FILE_BLOCK_SIZE);
412
413 DB::ReadBufferAIO in(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
414 size_t count = in.read(newbuf.data(), newbuf.length());
415 if (count != newbuf.length())
416 return false;
417
418 (void) in.seek(-(10 * DEFAULT_AIO_FILE_BLOCK_SIZE), SEEK_CUR);
419 }
420 catch (const DB::Exception &)
421 {
422 ok = true;
423 }
424
425 return ok;
426}
427
428bool test13(const std::string & filename, const std::string &)
429{
430 std::string newbuf;
431 newbuf.resize(2 * DEFAULT_AIO_FILE_BLOCK_SIZE - 3);
432
433 DB::ReadBufferAIO in(filename, DEFAULT_AIO_FILE_BLOCK_SIZE);
434 size_t count1 = in.read(newbuf.data(), newbuf.length());
435 if (count1 != newbuf.length())
436 return false;
437 return true;
438}
439
440bool test14(const std::string & filename, const std::string & buf)
441{
442 std::string newbuf;
443 newbuf.resize(1 + (DEFAULT_AIO_FILE_BLOCK_SIZE >> 1));
444
445 DB::ReadBufferAIO in(filename, DEFAULT_AIO_FILE_BLOCK_SIZE);
446 (void) in.seek(2, SEEK_SET);
447 in.setMaxBytes(3 + (DEFAULT_AIO_FILE_BLOCK_SIZE >> 1));
448
449 size_t count = in.read(newbuf.data(), newbuf.length());
450 if (count != newbuf.length())
451 return false;
452
453 if (newbuf != buf.substr(2, newbuf.length()))
454 return false;
455
456 return true;
457}
458
459bool test15(const std::string & filename, const std::string &)
460{
461 std::string newbuf;
462 newbuf.resize(1000);
463
464 DB::ReadBufferAIO in(filename, DEFAULT_AIO_FILE_BLOCK_SIZE);
465
466 size_t count = in.read(newbuf.data(), 1);
467 if (count != 1)
468 return false;
469 if (newbuf[0] != '1')
470 return false;
471 return true;
472}
473
474bool test16(const std::string & filename, const std::string &)
475{
476 DB::ReadBufferAIO in(filename, DEFAULT_AIO_FILE_BLOCK_SIZE);
477 size_t count;
478
479 {
480 std::string newbuf;
481 newbuf.resize(1);
482 count = in.read(newbuf.data(), 1);
483 if (count != 1)
484 return false;
485 if (newbuf[0] != '1')
486 return false;
487 }
488
489 in.seek(2, SEEK_CUR);
490
491 {
492 std::string newbuf;
493 newbuf.resize(3);
494 count = in.read(newbuf.data(), 3);
495 if (count != 3)
496 return false;
497 if (newbuf != "333")
498 return false;
499 }
500
501 in.seek(4, SEEK_CUR);
502
503 {
504 std::string newbuf;
505 newbuf.resize(5);
506 count = in.read(newbuf.data(), 5);
507 if (count != 5)
508 return false;
509 if (newbuf != "55555")
510 return false;
511 }
512
513 in.seek(6, SEEK_CUR);
514
515 {
516 std::string newbuf;
517 newbuf.resize(7);
518 count = in.read(newbuf.data(), 7);
519 if (count != 7)
520 return false;
521 if (newbuf != "7777777")
522 return false;
523 }
524
525 in.seek(8, SEEK_CUR);
526
527 {
528 std::string newbuf;
529 newbuf.resize(9);
530 count = in.read(newbuf.data(), 9);
531 if (count != 9)
532 return false;
533 if (newbuf != "999999999")
534 return false;
535 }
536
537 return true;
538}
539
540bool test17(const std::string & filename, const std::string & buf)
541{
542 DB::ReadBufferAIO in(filename, DEFAULT_AIO_FILE_BLOCK_SIZE);
543 size_t count;
544
545 {
546 std::string newbuf;
547 newbuf.resize(10);
548 count = in.read(newbuf.data(), 10);
549
550 if (count != 10)
551 return false;
552 if (newbuf.substr(0, 7) != std::string(7, '\0'))
553 return false;
554 if (newbuf.substr(7) != "122")
555 return false;
556 }
557
558 in.seek(7 + buf.length() - 2, SEEK_SET);
559
560 {
561 std::string newbuf;
562 newbuf.resize(160);
563 count = in.read(newbuf.data(), 160);
564
565 if (count != 2)
566 return false;
567 if (newbuf.substr(0, 2) != "99")
568 return false;
569 }
570
571 in.seek(7 + buf.length() + DEFAULT_AIO_FILE_BLOCK_SIZE, SEEK_SET);
572
573 {
574 std::string newbuf;
575 newbuf.resize(50);
576 count = in.read(newbuf.data(), 50);
577 if (count != 0)
578 return false;
579 }
580
581 return true;
582}
583
584bool test18(const std::string & filename, const std::string & buf)
585{
586 DB::ReadBufferAIO in(filename, DEFAULT_AIO_FILE_BLOCK_SIZE);
587
588 std::string newbuf;
589 newbuf.resize(1340);
590
591 in.seek(2984, SEEK_SET);
592 size_t count = in.read(newbuf.data(), 1340);
593
594 if (count != 1340)
595 return false;
596 if (newbuf != buf)
597 return false;
598
599 return true;
600}
601
602bool test19(const std::string & filename, const std::string & buf)
603{
604 DB::ReadBufferAIO in(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
605
606 {
607 std::string newbuf;
608 newbuf.resize(5 * DEFAULT_AIO_FILE_BLOCK_SIZE);
609
610 size_t count1 = in.read(newbuf.data(), newbuf.length());
611 if (count1 != newbuf.length())
612 return false;
613
614 if (newbuf != buf.substr(0, 5 * DEFAULT_AIO_FILE_BLOCK_SIZE))
615 return false;
616 }
617
618 {
619 std::string newbuf;
620 newbuf.resize(5 * DEFAULT_AIO_FILE_BLOCK_SIZE);
621
622 size_t count2 = in.read(newbuf.data(), newbuf.length());
623 if (count2 != newbuf.length())
624 return false;
625
626 if (newbuf != buf.substr(5 * DEFAULT_AIO_FILE_BLOCK_SIZE))
627 return false;
628 }
629
630 return true;
631}
632
633bool test20(const std::string & filename, const std::string & buf)
634{
635 DB::ReadBufferAIO in(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
636
637 {
638 std::string newbuf;
639 newbuf.resize(5 * DEFAULT_AIO_FILE_BLOCK_SIZE);
640
641 size_t count1 = in.read(newbuf.data(), newbuf.length());
642 if (count1 != newbuf.length())
643 return false;
644
645 if (newbuf != buf.substr(0, 5 * DEFAULT_AIO_FILE_BLOCK_SIZE))
646 return false;
647 }
648
649 (void) in.getPositionInFile();
650
651 {
652 std::string newbuf;
653 newbuf.resize(5 * DEFAULT_AIO_FILE_BLOCK_SIZE);
654
655 size_t count2 = in.read(newbuf.data(), newbuf.length());
656 if (count2 != newbuf.length())
657 return false;
658
659 if (newbuf != buf.substr(5 * DEFAULT_AIO_FILE_BLOCK_SIZE))
660 return false;
661 }
662
663 return true;
664}
665
666}
667
668int main()
669{
670 run();
671 return 0;
672}
673
674