1/* Copyright (C) 2006-2008 MySQL AB
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
15
16/*
17 TODO: use pthread_join instead of wait_for_thread_count_to_be_zero, like in
18 my_atomic-t.c (see BUG#22320).
19 Use diag() instead of fprintf(stderr).
20*/
21#include <tap.h>
22#include <my_sys.h>
23#include <m_string.h>
24#include "test_file.h"
25#include <tap.h>
26
27#define PCACHE_SIZE (TEST_PAGE_SIZE*1024*10)
28
29#ifndef DBUG_OFF
30static const char* default_dbug_option;
31#endif
32
33#ifndef BIG
34#undef SKIP_BIG_TESTS
35#define SKIP_BIG_TESTS(X) /* no-op */
36#endif
37
38static const char *base_file1_name= "page_cache_test_file_1";
39static const char *base_file2_name= "page_cache_test_file_2";
40static char file1_name[FN_REFLEN], file2_name[FN_REFLEN];
41static PAGECACHE_FILE file1;
42static pthread_cond_t COND_thread_count;
43static pthread_mutex_t LOCK_thread_count;
44static uint thread_count;
45static PAGECACHE pagecache;
46
47/*
48 File contance descriptors
49*/
50static struct file_desc simple_read_write_test_file[]=
51{
52 { TEST_PAGE_SIZE, '\1'},
53 {0, 0}
54};
55static struct file_desc simple_read_change_write_read_test_file[]=
56{
57 { TEST_PAGE_SIZE/2, '\65'},
58 { TEST_PAGE_SIZE/2, '\1'},
59 {0, 0}
60};
61static struct file_desc simple_pin_test_file1[]=
62{
63 { TEST_PAGE_SIZE*2, '\1'},
64 {0, 0}
65};
66static struct file_desc simple_pin_test_file2[]=
67{
68 { TEST_PAGE_SIZE/2, '\1'},
69 { TEST_PAGE_SIZE/2, (unsigned char)129},
70 { TEST_PAGE_SIZE, '\1'},
71 {0, 0}
72};
73static struct file_desc simple_pin_no_lock_test_file1[]=
74{
75 { TEST_PAGE_SIZE, '\4'},
76 {0, 0}
77};
78static struct file_desc simple_pin_no_lock_test_file2[]=
79{
80 { TEST_PAGE_SIZE, '\5'},
81 {0, 0}
82};
83static struct file_desc simple_pin_no_lock_test_file3[]=
84{
85 { TEST_PAGE_SIZE, '\6'},
86 {0, 0}
87};
88static struct file_desc simple_delete_forget_test_file[]=
89{
90 { TEST_PAGE_SIZE, '\1'},
91 {0, 0}
92};
93static struct file_desc simple_delete_flush_test_file[]=
94{
95 { TEST_PAGE_SIZE, '\2'},
96 {0, 0}
97};
98
99
100/*
101 Recreate and reopen a file for test
102
103 SYNOPSIS
104 reset_file()
105 file File to reset
106 file_name Path (and name) of file which should be reset
107*/
108
109void reset_file(PAGECACHE_FILE *file, const char *file_name)
110{
111 flush_pagecache_blocks(&pagecache, file, FLUSH_RELEASE);
112 if (my_close(file->file, MYF(MY_WME)))
113 exit(1);
114 my_delete(file_name, MYF(MY_WME));
115 if ((file->file= my_open(file_name,
116 O_CREAT | O_TRUNC | O_RDWR, MYF(0))) == -1)
117 {
118 diag("Got error during %s creation from open() (errno: %d)\n",
119 file_name, my_errno);
120 exit(1);
121 }
122}
123
124/*
125 Write then read page, check file on disk
126*/
127
128int simple_read_write_test()
129{
130 unsigned char *buffw= malloc(TEST_PAGE_SIZE);
131 unsigned char *buffr= malloc(TEST_PAGE_SIZE);
132 int res;
133 DBUG_ENTER("simple_read_write_test");
134 bfill(buffw, TEST_PAGE_SIZE, '\1');
135 pagecache_write(&pagecache, &file1, 0, 3, buffw,
136 PAGECACHE_PLAIN_PAGE,
137 PAGECACHE_LOCK_LEFT_UNLOCKED,
138 PAGECACHE_PIN_LEFT_UNPINNED,
139 PAGECACHE_WRITE_DELAY,
140 0, LSN_IMPOSSIBLE);
141 pagecache_read(&pagecache, &file1, 0, 3, buffr,
142 PAGECACHE_PLAIN_PAGE,
143 PAGECACHE_LOCK_LEFT_UNLOCKED,
144 0);
145 ok((res= MY_TEST(memcmp(buffr, buffw, TEST_PAGE_SIZE) == 0)),
146 "Simple write-read page ");
147 if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
148 {
149 diag("Got error during flushing pagecache\n");
150 exit(1);
151 }
152 ok((res&= MY_TEST(test_file(file1, file1_name, TEST_PAGE_SIZE, TEST_PAGE_SIZE,
153 simple_read_write_test_file))),
154 "Simple write-read page file");
155 if (res)
156 reset_file(&file1, file1_name);
157 free(buffw);
158 free(buffr);
159 DBUG_RETURN(res);
160}
161
162
163/*
164 Prepare page, then read (and lock), change (write new value and unlock),
165 then check the page in the cache and on the disk
166*/
167int simple_read_change_write_read_test()
168{
169 unsigned char *buffw= malloc(TEST_PAGE_SIZE);
170 unsigned char *buffr= malloc(TEST_PAGE_SIZE);
171 int res, res2;
172 DBUG_ENTER("simple_read_change_write_read_test");
173
174 /* prepare the file */
175 bfill(buffw, TEST_PAGE_SIZE, '\1');
176 pagecache_write(&pagecache, &file1, 0, 3, buffw,
177 PAGECACHE_PLAIN_PAGE,
178 PAGECACHE_LOCK_LEFT_UNLOCKED,
179 PAGECACHE_PIN_LEFT_UNPINNED,
180 PAGECACHE_WRITE_DELAY,
181 0, LSN_IMPOSSIBLE);
182 if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
183 {
184 diag("Got error during flushing pagecache\n");
185 exit(1);
186 }
187 /* test */
188 pagecache_read(&pagecache, &file1, 0, 3, buffw,
189 PAGECACHE_PLAIN_PAGE,
190 PAGECACHE_LOCK_WRITE,
191 0);
192 bfill(buffw, TEST_PAGE_SIZE/2, '\65');
193 pagecache_write(&pagecache, &file1, 0, 3, buffw,
194 PAGECACHE_PLAIN_PAGE,
195 PAGECACHE_LOCK_WRITE_UNLOCK,
196 PAGECACHE_UNPIN,
197 PAGECACHE_WRITE_DELAY,
198 0, LSN_IMPOSSIBLE);
199
200 pagecache_read(&pagecache, &file1, 0, 3, buffr,
201 PAGECACHE_PLAIN_PAGE,
202 PAGECACHE_LOCK_LEFT_UNLOCKED,
203 0);
204 ok((res= MY_TEST(memcmp(buffr, buffw, TEST_PAGE_SIZE) == 0)),
205 "Simple read-change-write-read page ");
206 DBUG_ASSERT(pagecache.blocks_changed == 1);
207 if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
208 {
209 diag("Got error during flushing pagecache\n");
210 exit(1);
211 }
212 DBUG_ASSERT(pagecache.blocks_changed == 0);
213 ok((res2= MY_TEST(test_file(file1, file1_name, TEST_PAGE_SIZE, TEST_PAGE_SIZE,
214 simple_read_change_write_read_test_file))),
215 "Simple read-change-write-read page file");
216 if (res && res2)
217 reset_file(&file1, file1_name);
218 free(buffw);
219 free(buffr);
220 DBUG_RETURN(res && res2);
221}
222
223
224/*
225 Prepare page, read page 0 (and pin) then write page 1 and page 0.
226 Flush the file (should flush only page 1 and return 1 (page 0 is
227 still pinned).
228 Check file on the disk.
229 Unpin and flush.
230 Check file on the disk.
231*/
232int simple_pin_test()
233{
234 unsigned char *buffw= malloc(TEST_PAGE_SIZE);
235 int res;
236 DBUG_ENTER("simple_pin_test");
237 /* prepare the file */
238 bfill(buffw, TEST_PAGE_SIZE, '\1');
239 pagecache_write(&pagecache, &file1, 0, 3, buffw,
240 PAGECACHE_PLAIN_PAGE,
241 PAGECACHE_LOCK_LEFT_UNLOCKED,
242 PAGECACHE_PIN_LEFT_UNPINNED,
243 PAGECACHE_WRITE_DELAY,
244 0, LSN_IMPOSSIBLE);
245 /* test */
246 if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
247 {
248 diag("Got error during flushing pagecache\n");
249 exit(1);
250 }
251 pagecache_read(&pagecache, &file1, 0, 3, buffw,
252 PAGECACHE_PLAIN_PAGE,
253 PAGECACHE_LOCK_WRITE,
254 0);
255 pagecache_write(&pagecache, &file1, 1, 3, buffw,
256 PAGECACHE_PLAIN_PAGE,
257 PAGECACHE_LOCK_LEFT_UNLOCKED,
258 PAGECACHE_PIN_LEFT_UNPINNED,
259 PAGECACHE_WRITE_DELAY,
260 0, LSN_IMPOSSIBLE);
261 bfill(buffw + TEST_PAGE_SIZE/2, TEST_PAGE_SIZE/2, ((unsigned char) 129));
262 pagecache_write(&pagecache, &file1, 0, 3, buffw,
263 PAGECACHE_PLAIN_PAGE,
264 PAGECACHE_LOCK_LEFT_WRITELOCKED,
265 PAGECACHE_PIN_LEFT_PINNED,
266 PAGECACHE_WRITE_DELAY,
267 0, LSN_IMPOSSIBLE);
268 /*
269 We have to get error because one page of the file is pinned,
270 other page should be flushed
271 */
272 if (!flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
273 {
274 diag("Did not get error in flush_pagecache_blocks\n");
275 res= 0;
276 goto err;
277 }
278 ok((res= MY_TEST(test_file(file1, file1_name, TEST_PAGE_SIZE * 2,
279 TEST_PAGE_SIZE * 2, simple_pin_test_file1))),
280 "Simple pin page file with pin");
281 pagecache_unlock(&pagecache,
282 &file1,
283 0,
284 PAGECACHE_LOCK_WRITE_UNLOCK,
285 PAGECACHE_UNPIN,
286 0, 0, 0);
287 if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
288 {
289 diag("Got error in flush_pagecache_blocks\n");
290 res= 0;
291 goto err;
292 }
293 ok((res&= MY_TEST(test_file(file1, file1_name, TEST_PAGE_SIZE * 2,
294 TEST_PAGE_SIZE, simple_pin_test_file2))),
295 "Simple pin page result file");
296 if (res)
297 reset_file(&file1, file1_name);
298err:
299 free(buffw);
300 DBUG_RETURN(res);
301}
302
303/*
304 Prepare page, read page 0 (and pin) then write page 1 and page 0.
305 Flush the file (should flush only page 1 and return 1 (page 0 is
306 still pinned).
307 Check file on the disk.
308 Unpin and flush.
309 Check file on the disk.
310*/
311int simple_pin_test2()
312{
313 unsigned char *buffw= malloc(TEST_PAGE_SIZE);
314 int res;
315 DBUG_ENTER("simple_pin_test2");
316 /* prepare the file */
317 bfill(buffw, TEST_PAGE_SIZE, '\1');
318 pagecache_write(&pagecache, &file1, 0, 3, buffw,
319 PAGECACHE_PLAIN_PAGE,
320 PAGECACHE_LOCK_LEFT_UNLOCKED,
321 PAGECACHE_PIN_LEFT_UNPINNED,
322 PAGECACHE_WRITE_DELAY,
323 0, LSN_IMPOSSIBLE);
324 /* test */
325 if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
326 {
327 diag("Got error during flushing pagecache\n");
328 exit(1);
329 }
330 pagecache_read(&pagecache, &file1, 0, 3, buffw,
331 PAGECACHE_PLAIN_PAGE,
332 PAGECACHE_LOCK_WRITE,
333 0);
334 pagecache_write(&pagecache, &file1, 1, 3, buffw,
335 PAGECACHE_PLAIN_PAGE,
336 PAGECACHE_LOCK_LEFT_UNLOCKED,
337 PAGECACHE_PIN_LEFT_UNPINNED,
338 PAGECACHE_WRITE_DELAY,
339 0, LSN_IMPOSSIBLE);
340 bfill(buffw + TEST_PAGE_SIZE/2, TEST_PAGE_SIZE/2, ((unsigned char) 129));
341 pagecache_write(&pagecache, &file1, 0, 3, buffw,
342 PAGECACHE_PLAIN_PAGE,
343 PAGECACHE_LOCK_WRITE_TO_READ,
344 PAGECACHE_PIN_LEFT_PINNED,
345 PAGECACHE_WRITE_DELAY,
346 0, LSN_IMPOSSIBLE);
347 /*
348 We have to get error because one page of the file is pinned,
349 other page should be flushed
350 */
351 if (!flush_pagecache_blocks(&pagecache, &file1, FLUSH_KEEP_LAZY))
352 {
353 diag("Did not get error in flush_pagecache_blocks 2\n");
354 res= 0;
355 goto err;
356 }
357 ok((res= MY_TEST(test_file(file1, file1_name, TEST_PAGE_SIZE * 2,
358 TEST_PAGE_SIZE * 2, simple_pin_test_file1))),
359 "Simple pin page file with pin 2");
360
361 /* Test that a normal flush goes through */
362 if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
363 {
364 diag("Got error in flush_pagecache_blocks 3\n");
365 res= 0;
366 goto err;
367 }
368 pagecache_unlock(&pagecache,
369 &file1,
370 0,
371 PAGECACHE_LOCK_READ_UNLOCK,
372 PAGECACHE_UNPIN,
373 0, 0, 0);
374 if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
375 {
376 diag("Got error in flush_pagecache_blocks 4\n");
377 res= 0;
378 goto err;
379 }
380 ok((res&= MY_TEST(test_file(file1, file1_name, TEST_PAGE_SIZE * 2,
381 TEST_PAGE_SIZE, simple_pin_test_file2))),
382 "Simple pin page result file 2");
383 if (res)
384 reset_file(&file1, file1_name);
385err:
386 free(buffw);
387 DBUG_RETURN(res);
388}
389
390/*
391 Checks pins without lock.
392*/
393int simple_pin_no_lock_test()
394{
395 unsigned char *buffw= malloc(TEST_PAGE_SIZE);
396 PAGECACHE_BLOCK_LINK *link;
397 int res;
398 DBUG_ENTER("simple_pin_no_lock_test");
399 /* prepare the file */
400 bfill(buffw, TEST_PAGE_SIZE, '\4');
401 pagecache_write(&pagecache, &file1, 0, 3, buffw,
402 PAGECACHE_PLAIN_PAGE,
403 PAGECACHE_LOCK_LEFT_UNLOCKED,
404 PAGECACHE_PIN_LEFT_UNPINNED,
405 PAGECACHE_WRITE_DELAY,
406 0, LSN_IMPOSSIBLE);
407 /* test */
408 if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
409 {
410 diag("Got error during flushing pagecache 2\n");
411 exit(1);
412 }
413 bfill(buffw, TEST_PAGE_SIZE, '\5');
414 pagecache_write(&pagecache, &file1, 0, 3, buffw,
415 PAGECACHE_PLAIN_PAGE,
416 PAGECACHE_LOCK_LEFT_UNLOCKED,
417 PAGECACHE_PIN,
418 PAGECACHE_WRITE_DELAY,
419 0, LSN_IMPOSSIBLE);
420 /*
421 We have to get error because one page of the file is pinned,
422 other page should be flushed
423 */
424 if (!flush_pagecache_blocks(&pagecache, &file1, FLUSH_KEEP_LAZY))
425 {
426 diag("Did not get error in flush_pagecache_blocks 2\n");
427 res= 0;
428 goto err;
429 }
430 ok((res= MY_TEST(test_file(file1, file1_name, TEST_PAGE_SIZE, TEST_PAGE_SIZE,
431 simple_pin_no_lock_test_file1))),
432 "Simple pin (no lock) page file with pin 2");
433 pagecache_unlock(&pagecache,
434 &file1,
435 0,
436 PAGECACHE_LOCK_LEFT_UNLOCKED,
437 PAGECACHE_UNPIN,
438 0, 0, 0);
439 if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
440 {
441 diag("Got error in flush_pagecache_blocks 2\n");
442 res= 0;
443 goto err;
444 }
445 ok((res&= MY_TEST(test_file(file1, file1_name, TEST_PAGE_SIZE, TEST_PAGE_SIZE,
446 simple_pin_no_lock_test_file2))),
447 "Simple pin (no lock) page result file 2");
448
449 bfill(buffw, TEST_PAGE_SIZE, '\6');
450 pagecache_write(&pagecache, &file1, 0, 3, buffw,
451 PAGECACHE_PLAIN_PAGE,
452 PAGECACHE_LOCK_WRITE,
453 PAGECACHE_PIN,
454 PAGECACHE_WRITE_DELAY,
455 &link, LSN_IMPOSSIBLE);
456 pagecache_unlock_by_link(&pagecache, link,
457 PAGECACHE_LOCK_WRITE_UNLOCK,
458 PAGECACHE_PIN_LEFT_PINNED, 0, 0, 1, FALSE);
459 if (!flush_pagecache_blocks(&pagecache, &file1, FLUSH_KEEP_LAZY))
460 {
461 diag("Did not get error in flush_pagecache_blocks 3\n");
462 res= 0;
463 goto err;
464 }
465 ok((res= MY_TEST(test_file(file1, file1_name, TEST_PAGE_SIZE, TEST_PAGE_SIZE,
466 simple_pin_no_lock_test_file2))),
467 "Simple pin (no lock) page file with pin 3");
468 pagecache_unpin_by_link(&pagecache, link, 0);
469 if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
470 {
471 diag("Got error in flush_pagecache_blocks 3\n");
472 res= 0;
473 goto err;
474 }
475 ok((res&= MY_TEST(test_file(file1, file1_name, TEST_PAGE_SIZE, TEST_PAGE_SIZE,
476 simple_pin_no_lock_test_file3))),
477 "Simple pin (no lock) page result file 3");
478 if (res)
479 reset_file(&file1, file1_name);
480err:
481 free(buffw);
482 DBUG_RETURN(res);
483}
484/*
485 Prepare page, write new value, then delete page from cache without flush,
486 on the disk should be page with old content written during preparation
487*/
488
489int simple_delete_forget_test()
490{
491 unsigned char *buffw= malloc(TEST_PAGE_SIZE);
492 unsigned char *buffr= malloc(TEST_PAGE_SIZE);
493 int res;
494 DBUG_ENTER("simple_delete_forget_test");
495 /* prepare the file */
496 bfill(buffw, TEST_PAGE_SIZE, '\1');
497 pagecache_write(&pagecache, &file1, 0, 3, buffw,
498 PAGECACHE_PLAIN_PAGE,
499 PAGECACHE_LOCK_LEFT_UNLOCKED,
500 PAGECACHE_PIN_LEFT_UNPINNED,
501 PAGECACHE_WRITE_DELAY,
502 0, LSN_IMPOSSIBLE);
503 flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE);
504 /* test */
505 bfill(buffw, TEST_PAGE_SIZE, '\2');
506 pagecache_write(&pagecache, &file1, 0, 3, buffw,
507 PAGECACHE_PLAIN_PAGE,
508 PAGECACHE_LOCK_LEFT_UNLOCKED,
509 PAGECACHE_PIN_LEFT_UNPINNED,
510 PAGECACHE_WRITE_DELAY,
511 0, LSN_IMPOSSIBLE);
512 pagecache_delete(&pagecache, &file1, 0,
513 PAGECACHE_LOCK_WRITE, 0);
514 flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE);
515 ok((res= MY_TEST(test_file(file1, file1_name, TEST_PAGE_SIZE, TEST_PAGE_SIZE,
516 simple_delete_forget_test_file))),
517 "Simple delete-forget page file");
518 if (res)
519 reset_file(&file1, file1_name);
520 free(buffw);
521 free(buffr);
522 DBUG_RETURN(res);
523}
524
525/*
526 Prepare page with locking, write new content to the page,
527 delete page with flush and on existing lock,
528 check that page on disk contain new value.
529*/
530
531int simple_delete_flush_test()
532{
533 unsigned char *buffw= malloc(TEST_PAGE_SIZE);
534 unsigned char *buffr= malloc(TEST_PAGE_SIZE);
535 PAGECACHE_BLOCK_LINK *link;
536 int res;
537 DBUG_ENTER("simple_delete_flush_test");
538 /* prepare the file */
539 bfill(buffw, TEST_PAGE_SIZE, '\1');
540 pagecache_write(&pagecache, &file1, 0, 3, buffw,
541 PAGECACHE_PLAIN_PAGE,
542 PAGECACHE_LOCK_WRITE,
543 PAGECACHE_PIN,
544 PAGECACHE_WRITE_DELAY,
545 &link, LSN_IMPOSSIBLE);
546 flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE);
547 /* test */
548 bfill(buffw, TEST_PAGE_SIZE, '\2');
549 pagecache_write(&pagecache, &file1, 0, 3, buffw,
550 PAGECACHE_PLAIN_PAGE,
551 PAGECACHE_LOCK_LEFT_WRITELOCKED,
552 PAGECACHE_PIN_LEFT_PINNED,
553 PAGECACHE_WRITE_DELAY,
554 0, LSN_IMPOSSIBLE);
555 if (pagecache_delete_by_link(&pagecache, link,
556 PAGECACHE_LOCK_LEFT_WRITELOCKED, 1))
557 {
558 diag("simple_delete_flush_test: error during delete");
559 exit(1);
560 }
561 flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE);
562 ok((res= MY_TEST(test_file(file1, file1_name, TEST_PAGE_SIZE, TEST_PAGE_SIZE,
563 simple_delete_flush_test_file))),
564 "Simple delete flush (link) page file");
565 if (res)
566 reset_file(&file1, file1_name);
567 free(buffw);
568 free(buffr);
569 DBUG_RETURN(res);
570}
571
572
573/*
574 write then read file bigger then cache
575*/
576
577int simple_big_test()
578{
579 unsigned char *buffw= (unsigned char *) my_malloc(TEST_PAGE_SIZE, MYF(MY_WME));
580 unsigned char *buffr= (unsigned char *) my_malloc(TEST_PAGE_SIZE, MYF(MY_WME));
581 struct file_desc *desc= ((struct file_desc *)
582 my_malloc((PCACHE_SIZE/(TEST_PAGE_SIZE/2) + 1) *
583 sizeof(struct file_desc), MYF(MY_WME)));
584 int res, i;
585 DBUG_ENTER("simple_big_test");
586
587 /* prepare the file twice larger then cache */
588 for (i= 0; i < PCACHE_SIZE/(TEST_PAGE_SIZE/2); i++)
589 {
590 bfill(buffw, TEST_PAGE_SIZE, (unsigned char) (i & 0xff));
591 desc[i].length= TEST_PAGE_SIZE;
592 desc[i].content= (i & 0xff);
593 pagecache_write(&pagecache, &file1, i, 3, buffw,
594 PAGECACHE_PLAIN_PAGE,
595 PAGECACHE_LOCK_LEFT_UNLOCKED,
596 PAGECACHE_PIN_LEFT_UNPINNED,
597 PAGECACHE_WRITE_DELAY,
598 0, LSN_IMPOSSIBLE);
599 }
600 desc[i].length= 0;
601 desc[i].content= '\0';
602 ok(1, "Simple big file write");
603 /* check written pages sequentally read */
604 for (i= 0; i < PCACHE_SIZE/(TEST_PAGE_SIZE/2); i++)
605 {
606 int j;
607 pagecache_read(&pagecache, &file1, i, 3, buffr,
608 PAGECACHE_PLAIN_PAGE,
609 PAGECACHE_LOCK_LEFT_UNLOCKED,
610 0);
611 for(j= 0; j < TEST_PAGE_SIZE; j++)
612 {
613 if (buffr[j] != (i & 0xff))
614 {
615 diag("simple_big_test seq: page %u byte %u mismatch\n", i, j);
616 res= 0;
617 goto err;
618 }
619 }
620 }
621 ok(1, "Simple big file sequential read");
622 /* chack random reads */
623 for (i= 0; i < PCACHE_SIZE/(TEST_PAGE_SIZE); i++)
624 {
625 int j, page;
626 page= rand() % (PCACHE_SIZE/(TEST_PAGE_SIZE/2));
627 pagecache_read(&pagecache, &file1, page, 3, buffr,
628 PAGECACHE_PLAIN_PAGE,
629 PAGECACHE_LOCK_LEFT_UNLOCKED,
630 0);
631 for(j= 0; j < TEST_PAGE_SIZE; j++)
632 {
633 if (buffr[j] != (page & 0xff))
634 {
635 diag("simple_big_test rnd: page %u byte %u mismatch\n", page, j);
636 res= 0;
637 goto err;
638 }
639 }
640 }
641 ok(1, "Simple big file random read");
642 flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE);
643
644 ok((res= MY_TEST(test_file(file1, file1_name, PCACHE_SIZE * 2, TEST_PAGE_SIZE,
645 desc))),
646 "Simple big file");
647 if (res)
648 reset_file(&file1, file1_name);
649
650err:
651 my_free(buffw);
652 my_free(buffr);
653 my_free(desc);
654 DBUG_RETURN(res);
655}
656
657
658/*
659 Thread function
660*/
661
662static void *test_thread(void *arg)
663{
664#ifndef DBUG_OFF
665 int param= *((int*) arg);
666#endif
667
668 my_thread_init();
669 {
670 DBUG_ENTER("test_thread");
671 DBUG_PRINT("enter", ("param: %d", param));
672
673 if (!simple_read_write_test() ||
674 !simple_read_change_write_read_test() ||
675 !simple_pin_test() ||
676 !simple_pin_test2() ||
677 !simple_pin_no_lock_test() ||
678 !simple_delete_forget_test() ||
679 !simple_delete_flush_test())
680 exit(1);
681
682 SKIP_BIG_TESTS(4)
683 {
684 if (!simple_big_test())
685 exit(1);
686 }
687
688 DBUG_PRINT("info", ("Thread %s ended\n", my_thread_name()));
689 pthread_mutex_lock(&LOCK_thread_count);
690 thread_count--;
691 pthread_cond_signal(&COND_thread_count); /* Tell main we are ready */
692 pthread_mutex_unlock(&LOCK_thread_count);
693 free((uchar*) arg);
694 my_thread_end();
695 DBUG_RETURN(0);
696 }
697}
698
699
700static char *create_tmpdir(const char *progname)
701{
702 static char test_dirname[FN_REFLEN];
703 char tmp_name[FN_REFLEN];
704 size_t length;
705
706 /* Create a temporary directory of name TMP-'executable', but without the -t extension */
707 fn_format(tmp_name, progname, "", "", MY_REPLACE_DIR | MY_REPLACE_EXT);
708 length= strlen(tmp_name);
709 if (length > 2 && tmp_name[length-2] == '-' && tmp_name[length-1] == 't')
710 tmp_name[length-2]= 0;
711 strxmov(test_dirname, "TMP-", tmp_name, NullS);
712
713 /*
714 Don't give an error if we can't create dir, as it may already exist from a previously aborted
715 run
716 */
717 (void) my_mkdir(test_dirname, 0777, MYF(0));
718 return test_dirname;
719}
720
721
722int main(int argc __attribute__((unused)),
723 char **argv __attribute__((unused)))
724{
725 pthread_t tid;
726 pthread_attr_t thr_attr;
727 int *param, error;
728 size_t pagen;
729 File tmp_file;
730 MY_INIT(argv[0]);
731
732#ifndef DBUG_OFF
733#if defined(__WIN__)
734 default_dbug_option= "d:t:i:O,\\test_pagecache_single.trace";
735#else
736 default_dbug_option= "d:t:i:o,/tmp/test_pagecache_single.trace";
737#endif
738 if (argc > 1)
739 {
740 DBUG_SET(default_dbug_option);
741 DBUG_SET_INITIAL(default_dbug_option);
742 }
743#endif
744 {
745 DBUG_ENTER("main");
746 DBUG_PRINT("info", ("Main thread: %s\n", my_thread_name()));
747
748 plan(18);
749 SKIP_BIG_TESTS(18)
750 {
751 char *test_dirname= create_tmpdir(argv[0]);
752 fn_format(file1_name, base_file1_name, test_dirname, "", MYF(0));
753 fn_format(file2_name, base_file2_name, test_dirname, "", MYF(0));
754
755 if ((tmp_file= my_open(file2_name, O_CREAT | O_TRUNC | O_RDWR,
756 MYF(MY_WME))) < 0)
757 exit(1);
758
759 if ((file1.file= my_open(file1_name,
760 O_CREAT | O_TRUNC | O_RDWR, MYF(0))) == -1)
761 {
762 fprintf(stderr, "Got error during file1 creation from open() (errno: %d)\n",
763 errno);
764 exit(1);
765 }
766 pagecache_file_set_null_hooks(&file1);
767 my_close(tmp_file, MYF(0));
768 my_delete(file2_name, MYF(0));
769
770 DBUG_PRINT("info", ("file1: %d", file1.file));
771 if (my_chmod(file1_name, 0777, MYF(MY_WME)))
772 exit(1);
773 my_pwrite(file1.file, (const uchar*)"test file", 9, 0, MYF(MY_WME));
774
775 if ((error= pthread_cond_init(&COND_thread_count, NULL)))
776 {
777 fprintf(stderr, "Got error: %d from pthread_cond_init (errno: %d)\n",
778 error, errno);
779 exit(1);
780 }
781 if ((error= pthread_mutex_init(&LOCK_thread_count, MY_MUTEX_INIT_FAST)))
782 {
783 fprintf(stderr, "Got error: %d from pthread_cond_init (errno: %d)\n",
784 error, errno);
785 exit(1);
786 }
787
788 if ((error= pthread_attr_init(&thr_attr)))
789 {
790 fprintf(stderr,"Got error: %d from pthread_attr_init (errno: %d)\n",
791 error,errno);
792 exit(1);
793 }
794 if ((error= pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED)))
795 {
796 fprintf(stderr,
797 "Got error: %d from pthread_attr_setdetachstate (errno: %d)\n",
798 error,errno);
799 exit(1);
800 }
801
802#ifdef HAVE_THR_SETCONCURRENCY
803 thr_setconcurrency(2);
804#endif
805
806 if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
807 TEST_PAGE_SIZE, 0, MYF(MY_WME))) == 0)
808 {
809 fprintf(stderr,"Got error: init_pagecache() (errno: %d)\n",
810 errno);
811 exit(1);
812 }
813 DBUG_PRINT("info", ("Page cache %zd pages", pagen));
814
815 pthread_mutex_lock(&LOCK_thread_count);
816 param=(int*) malloc(sizeof(int));
817 *param= 1;
818 if ((error= pthread_create(&tid, &thr_attr, test_thread, (void*) param)))
819 {
820 fprintf(stderr,"Got error: %d from pthread_create (errno: %d)\n",
821 error,errno);
822 exit(1);
823 }
824 thread_count++;
825 DBUG_PRINT("info", ("Thread started"));
826 pthread_mutex_unlock(&LOCK_thread_count);
827
828 pthread_attr_destroy(&thr_attr);
829
830 pthread_mutex_lock(&LOCK_thread_count);
831 while (thread_count)
832 {
833 if ((error= pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)))
834 fprintf(stderr,"Got error: %d from pthread_cond_wait\n",error);
835 }
836 pthread_mutex_unlock(&LOCK_thread_count);
837 DBUG_PRINT("info", ("thread ended"));
838
839 end_pagecache(&pagecache, 1);
840 DBUG_PRINT("info", ("Page cache ended"));
841
842 if (my_close(file1.file, MYF(MY_WME)))
843 exit(1);
844
845 my_delete(file1_name, MYF(0));
846 rmdir(test_dirname);
847
848 } /* SKIP_BIG_TESTS */
849 DBUG_PRINT("info", ("file1 (%d) closed", file1.file));
850 DBUG_PRINT("info", ("Program end"));
851
852 my_end(0);
853 }
854 return exit_status();
855}
856
857#include "../ma_check_standalone.h"
858