LTP GCOV extension - code coverage report
Current view: directory - storage/maria/unittest - ma_pagecache_consist.c
Test: mtr_and_unit.info
Date: 2009-03-05 Instrumented lines: 183
Code covered: 75.4 % Executed lines: 138

       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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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                 : */
      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*8)
      28                 : 
      29                 : #ifndef DBUG_OFF
      30                 : static const char* default_dbug_option;
      31                 : #endif
      32                 : 
      33                 : static char *file1_name= (char*)"page_cache_test_file_1";
      34                 : static PAGECACHE_FILE file1;
      35                 : static pthread_cond_t COND_thread_count;
      36                 : static pthread_mutex_t LOCK_thread_count;
      37                 : static uint thread_count;
      38                 : static PAGECACHE pagecache;
      39                 : 
      40                 : #ifdef TEST_HIGH_CONCURENCY
      41                 : static uint number_of_readers= 10;
      42                 : static uint number_of_writers= 20;
      43                 : static uint number_of_tests= 30000;
      44                 : static uint record_length_limit= TEST_PAGE_SIZE/200;
      45                 : static uint number_of_pages= 20;
      46                 : static uint flush_divider= 1000;
      47                 : #else /*TEST_HIGH_CONCURENCY*/
      48                 : #ifdef TEST_READERS
      49                 : static uint number_of_readers= 10;
      50                 : static uint number_of_writers= 1;
      51                 : static uint number_of_tests= 30000;
      52                 : static uint record_length_limit= TEST_PAGE_SIZE/200;
      53                 : static uint number_of_pages= 20;
      54                 : static uint flush_divider= 1000;
      55                 : #undef SKIP_BIG_TESTS
      56                 : #define SKIP_BIG_TESTS(X) /* no-op */
      57                 : #else /*TEST_READERS*/
      58                 : #ifdef TEST_WRITERS
      59                 : static uint number_of_readers= 0;
      60                 : static uint number_of_writers= 10;
      61                 : static uint number_of_tests= 30000;
      62                 : static uint record_length_limit= TEST_PAGE_SIZE/200;
      63                 : static uint number_of_pages= 20;
      64                 : static uint flush_divider= 1000;
      65                 : #undef SKIP_BIG_TESTS
      66                 : #define SKIP_BIG_TESTS(X) /* no-op */
      67                 : #else /*TEST_WRITERS*/
      68                 : static uint number_of_readers= 10;
      69                 : static uint number_of_writers= 10;
      70                 : static uint number_of_tests= 50000;
      71                 : static uint record_length_limit= TEST_PAGE_SIZE/200;
      72                 : static uint number_of_pages= 20000;
      73                 : static uint flush_divider= 1000;
      74                 : #endif /*TEST_WRITERS*/
      75                 : #endif /*TEST_READERS*/
      76                 : #endif /*TEST_HIGH_CONCURENCY*/
      77                 : 
      78                 : 
      79                 : /**
      80                 :   @brief Dummy pagecache callback.
      81                 : */
      82                 : 
      83                 : static my_bool
      84                 : dummy_callback(uchar *page __attribute__((unused)),
      85                 :                pgcache_page_no_t page_no __attribute__((unused)),
      86                 :                uchar* data_ptr __attribute__((unused)))
      87           18834 : {
      88           18834 :   return 0;
      89                 : }
      90                 : 
      91                 : 
      92                 : /**
      93                 :   @brief Dummy pagecache callback.
      94                 : */
      95                 : 
      96                 : static void
      97                 : dummy_fail_callback(uchar* data_ptr __attribute__((unused)))
      98               0 : {
      99                 :   return;
     100                 : }
     101                 : 
     102                 : 
     103                 : /*
     104                 :   Get pseudo-random length of the field in (0;limit)
     105                 : 
     106                 :   SYNOPSYS
     107                 :     get_len()
     108                 :     limit                limit for generated value
     109                 : 
     110                 :   RETURN
     111                 :     length where length >= 0 & length < limit
     112                 : */
     113                 : 
     114                 : static uint get_len(uint limit)
     115         1919999 : {
     116         1919999 :   return (uint)((ulonglong)rand()*(limit-1)/RAND_MAX);
     117                 : }
     118                 : 
     119                 : 
     120                 : /*
     121                 :   Check page's consistency: layout is
     122                 :   4 bytes: number 'num' of records in this page, then num occurences of
     123                 :   { 4 bytes: record's length 'len'; then 4 bytes unchecked ('tag') then
     124                 :   'len' bytes each equal to the record's sequential number in this page,
     125                 :   modulo 256 }, then zeroes.
     126                 :  */
     127                 : uint check_page(uchar *buff, ulong offset, int page_locked, int page_no,
     128                 :                 int tag)
     129         1260000 : {
     130         1260000 :   uint end= sizeof(uint);
     131         1260000 :   uint num= uint4korr(buff);
     132                 :   uint i;
     133         1260000 :   DBUG_ENTER("check_page");
     134                 : 
     135       297353036 :   for (i= 0; i < num; i++)
     136                 :   {
     137       278022089 :     uint len= uint4korr(buff + end);
     138                 :     uint j;
     139       278022089 :     end+= 4 + 4;
     140       278022089 :     if (len + end > TEST_PAGE_SIZE)
     141                 :     {
     142              51 :       diag("incorrect field header #%u by offset %lu\n", i, offset + end);
     143               0 :       goto err;
     144                 :     }
     145              -1 :     for(j= 0; j < len; j++)
     146                 :     {
     147              -1 :       if (buff[end + j] != (uchar)((i+1) % 256))
     148                 :       {
     149              -1 :         diag("incorrect %lu byte\n", offset + end + j);
     150               0 :         goto err;
     151                 :       }
     152                 :     }
     153       278055846 :     end+= len;
     154                 :   }
     155              -1 :   for(i= end; i < TEST_PAGE_SIZE; i++)
     156                 :   {
     157              -1 :     if (buff[i] != 0)
     158                 :     {
     159                 :       int h;
     160        19370579 :       DBUG_PRINT("err",
     161                 :                  ("byte %lu (%lu + %u), page %u (%s, end: %u, recs: %u, tag: %d) should be 0\n",
     162                 :                   offset + i, offset, i, page_no,
     163                 :                   (page_locked ? "locked" : "unlocked"),
     164                 :                   end, num, tag));
     165               0 :       diag("byte %lu (%lu + %u), page %u (%s, end: %u, recs: %u, tag: %d) should be 0\n",
     166                 :            offset + i, offset, i, page_no,
     167                 :            (page_locked ? "locked" : "unlocked"),
     168                 :            end, num, tag);
     169               0 :       h= my_open("wrong_page", O_CREAT | O_TRUNC | O_RDWR, MYF(0));
     170               0 :       my_pwrite(h, (uchar*) buff, TEST_PAGE_SIZE, 0, MYF(0));
     171               0 :       my_close(h, MYF(0));
     172               0 :       goto err;
     173                 :     }
     174                 :   }
     175         1260000 :   DBUG_RETURN(end);
     176               0 : err:
     177               0 :   DBUG_PRINT("err", ("try to flush"));
     178               0 :   if (page_locked)
     179                 :   {
     180               0 :     pagecache_delete(&pagecache, &file1, page_no,
     181                 :                      PAGECACHE_LOCK_LEFT_WRITELOCKED, 1);
     182                 :   }
     183                 :   else
     184                 :   {
     185               0 :     flush_pagecache_blocks(&pagecache, &file1, FLUSH_RELEASE);
     186                 :   }
     187               0 :   exit(1);
     188                 : }
     189                 : 
     190                 : void put_rec(uchar *buff, uint end, uint len, uint tag)
     191          660000 : {
     192                 :   uint i;
     193                 :   uint num;
     194          660000 :   num= uint4korr(buff);
     195          660000 :   if (!len)
     196           83723 :     len= 1;
     197          660000 :   if (end + 4*2 + len > TEST_PAGE_SIZE)
     198           18658 :     return;
     199           18658 :   int4store(buff + end, len);
     200           18658 :   end+=  4;
     201           18658 :   int4store(buff + end, tag);
     202           18658 :   end+=  4;
     203           18658 :   num++;
     204           18658 :   int4store(buff, num);
     205         2397966 :   for (i= end; i < (len + end); i++)
     206                 :   {
     207         2379308 :     buff[i]= (uchar) num % 256;
     208                 :   }
     209                 : }
     210                 : 
     211                 : /*
     212                 :   Recreate and reopen a file for test
     213                 : 
     214                 :   SYNOPSIS
     215                 :     reset_file()
     216                 :     file                 File to reset
     217                 :     file_name            Path (and name) of file which should be reset
     218                 : */
     219                 : 
     220                 : void reset_file(PAGECACHE_FILE file, char *file_name)
     221               0 : {
     222               0 :   flush_pagecache_blocks(&pagecache, &file1, FLUSH_RELEASE);
     223               0 :   if (my_close(file1.file, MYF(0)) != 0)
     224                 :   {
     225               0 :     diag("Got error during %s closing from close() (errno: %d)\n",
     226                 :          file_name, errno);
     227               0 :     exit(1);
     228                 :   }
     229               0 :   my_delete(file_name, MYF(0));
     230               0 :   if ((file.file= my_open(file_name,
     231                 :                           O_CREAT | O_TRUNC | O_RDWR, MYF(0))) == -1)
     232                 :   {
     233               0 :     diag("Got error during %s creation from open() (errno: %d)\n",
     234                 :          file_name, errno);
     235               0 :     exit(1);
     236                 :   }
     237                 : }
     238                 : 
     239                 : 
     240                 : void reader(int num)
     241              20 : {
     242              20 :   unsigned char *buffr= malloc(TEST_PAGE_SIZE);
     243                 :   uint i;
     244                 : 
     245          600019 :   for (i= 0; i < number_of_tests; i++)
     246                 :   {
     247          599999 :     uint page= get_len(number_of_pages);
     248          600000 :     pagecache_read(&pagecache, &file1, page, 3, buffr,
     249                 :                    PAGECACHE_PLAIN_PAGE,
     250                 :                    PAGECACHE_LOCK_LEFT_UNLOCKED,
     251                 :                    0);
     252          600000 :     check_page(buffr, page * TEST_PAGE_SIZE, 0, page, -num);
     253                 : 
     254                 :   }
     255              20 :   free(buffr);
     256                 : }
     257                 : 
     258                 : 
     259                 : void writer(int num)
     260              22 : {
     261              22 :   unsigned char *buffr= malloc(TEST_PAGE_SIZE);
     262                 :   uint i;
     263                 : 
     264          660022 :   for (i= 0; i < number_of_tests; i++)
     265                 :   {
     266                 :     uint end;
     267          660000 :     uint page= get_len(number_of_pages);
     268          660000 :     pagecache_read(&pagecache, &file1, page, 3, buffr,
     269                 :                    PAGECACHE_PLAIN_PAGE,
     270                 :                    PAGECACHE_LOCK_WRITE,
     271                 :                    0);
     272          660000 :     end= check_page(buffr, page * TEST_PAGE_SIZE, 1, page, num);
     273          660000 :     put_rec(buffr, end, get_len(record_length_limit), num);
     274          660000 :     pagecache_write(&pagecache, &file1, page, 3, buffr,
     275                 :                     PAGECACHE_PLAIN_PAGE,
     276                 :                     PAGECACHE_LOCK_WRITE_UNLOCK,
     277                 :                     PAGECACHE_UNPIN,
     278                 :                     PAGECACHE_WRITE_DELAY,
     279                 :                     0, LSN_IMPOSSIBLE);
     280                 : 
     281          660000 :     if (i % flush_divider == 0)
     282             660 :       flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE);
     283                 :   }
     284              22 :   free(buffr);
     285                 : }
     286                 : 
     287                 : 
     288                 : static void *test_thread_reader(void *arg)
     289              20 : {
     290              20 :   int param=*((int*) arg);
     291              20 :   my_thread_init();
     292                 :   {
     293              20 :     DBUG_ENTER("test_reader");
     294              20 :     DBUG_PRINT("enter", ("param: %d", param));
     295                 : 
     296              20 :     reader(param);
     297                 : 
     298              20 :     DBUG_PRINT("info", ("Thread %s ended", my_thread_name()));
     299              20 :     pthread_mutex_lock(&LOCK_thread_count);
     300              20 :     ok(1, "reader%d: done", param);
     301              20 :     thread_count--;
     302              20 :     VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
     303              20 :     pthread_mutex_unlock(&LOCK_thread_count);
     304              20 :     free((uchar*) arg);
     305              20 :     my_thread_end();
     306                 :   }
     307              20 :   return 0;
     308                 : }
     309                 : 
     310                 : 
     311                 : static void *test_thread_writer(void *arg)
     312              22 : {
     313              22 :   int param=*((int*) arg);
     314              22 :   my_thread_init();
     315                 :   {
     316              22 :     DBUG_ENTER("test_writer");
     317              22 :     DBUG_PRINT("enter", ("param: %d", param));
     318                 : 
     319              22 :     writer(param);
     320                 : 
     321              22 :     DBUG_PRINT("info", ("Thread %s ended", my_thread_name()));
     322              22 :     pthread_mutex_lock(&LOCK_thread_count);
     323              22 :     ok(1, "writer%d: done", param);
     324              22 :     thread_count--;
     325              22 :     VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
     326              22 :     pthread_mutex_unlock(&LOCK_thread_count);
     327              22 :     free((uchar*) arg);
     328              22 :     my_thread_end();
     329                 :   }
     330              22 :   return 0;
     331                 : }
     332                 : 
     333                 : 
     334                 : int main(int argc __attribute__((unused)),
     335                 :          char **argv __attribute__((unused)))
     336               8 : {
     337                 :   pthread_t tid;
     338                 :   pthread_attr_t thr_attr;
     339                 :   int *param, error, pagen;
     340                 : 
     341               8 :   MY_INIT(argv[0]);
     342                 : 
     343                 : #ifndef DBUG_OFF
     344                 : #if defined(__WIN__)
     345                 :   default_dbug_option= "d:t:i:O,\\test_pagecache_consist.trace";
     346                 : #else
     347               8 :   default_dbug_option= "d:t:i:o,/tmp/test_pagecache_consist.trace";
     348                 : #endif
     349               8 :   if (argc > 1)
     350                 :   {
     351               0 :     DBUG_SET(default_dbug_option);
     352               0 :     DBUG_SET_INITIAL(default_dbug_option);
     353                 :   }
     354                 : #endif
     355                 : 
     356                 :   {
     357               8 :   DBUG_ENTER("main");
     358               8 :   DBUG_PRINT("info", ("Main thread: %s\n", my_thread_name()));
     359               8 :   plan(number_of_writers + number_of_readers);
     360               4 :   SKIP_BIG_TESTS(number_of_writers + number_of_readers)
     361                 :   {
     362                 : 
     363               4 :   if ((file1.file= my_open(file1_name,
     364                 :                            O_CREAT | O_TRUNC | O_RDWR, MYF(0))) == -1)
     365                 :   {
     366               0 :     diag( "Got error during file1 creation from open() (errno: %d)\n",
     367                 :             errno);
     368               0 :     exit(1);
     369                 :   }
     370               4 :   pagecache_file_init(file1, &dummy_callback, &dummy_callback,
     371                 :                       &dummy_fail_callback, &dummy_callback, NULL);
     372               4 :   DBUG_PRINT("info", ("file1: %d", file1.file));
     373               4 :   if (my_chmod(file1_name, S_IRWXU | S_IRWXG | S_IRWXO, MYF(MY_WME)))
     374               0 :     exit(1);
     375               4 :   my_pwrite(file1.file, (const uchar *)"test file", 9, 0, MYF(0));
     376                 : 
     377               4 :   if ((error= pthread_cond_init(&COND_thread_count, NULL)))
     378                 :   {
     379               0 :     diag( "COND_thread_count: %d from pthread_cond_init (errno: %d)\n",
     380                 :             error, errno);
     381               0 :     exit(1);
     382                 :   }
     383               4 :   if ((error= pthread_mutex_init(&LOCK_thread_count, MY_MUTEX_INIT_FAST)))
     384                 :   {
     385               0 :     diag( "LOCK_thread_count: %d from pthread_cond_init (errno: %d)\n",
     386                 :             error, errno);
     387               0 :     exit(1);
     388                 :   }
     389                 : 
     390               4 :   if ((error= pthread_attr_init(&thr_attr)))
     391                 :   {
     392               0 :     diag("Got error: %d from pthread_attr_init (errno: %d)\n",
     393                 :             error,errno);
     394               0 :     exit(1);
     395                 :   }
     396               4 :   if ((error= pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED)))
     397                 :   {
     398               0 :     diag(
     399                 :             "Got error: %d from pthread_attr_setdetachstate (errno: %d)\n",
     400                 :             error,errno);
     401               0 :     exit(1);
     402                 :   }
     403                 : 
     404                 : #ifdef HAVE_THR_SETCONCURRENCY
     405                 :   VOID(thr_setconcurrency(2));
     406                 : #endif
     407                 : 
     408               4 :   if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
     409                 :                              TEST_PAGE_SIZE, 0)) == 0)
     410                 :   {
     411               0 :     diag("Got error: init_pagecache() (errno: %d)\n",
     412                 :             errno);
     413               0 :     exit(1);
     414                 :   }
     415               4 :   DBUG_PRINT("info", ("Page cache %d pages", pagen));
     416                 :   {
     417               4 :     unsigned char *buffr= malloc(TEST_PAGE_SIZE);
     418                 :     uint i;
     419               4 :     memset(buffr, '\0', TEST_PAGE_SIZE);
     420              84 :     for (i= 0; i < number_of_pages; i++)
     421                 :     {
     422              80 :       pagecache_write(&pagecache, &file1, i, 3, buffr,
     423                 :                       PAGECACHE_PLAIN_PAGE,
     424                 :                       PAGECACHE_LOCK_LEFT_UNLOCKED,
     425                 :                       PAGECACHE_PIN_LEFT_UNPINNED,
     426                 :                       PAGECACHE_WRITE_DELAY,
     427                 :                       0, LSN_IMPOSSIBLE);
     428                 :     }
     429               4 :     flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE);
     430               4 :     free(buffr);
     431                 :   }
     432               4 :   pthread_mutex_lock(&LOCK_thread_count);
     433              48 :   while (number_of_readers != 0 || number_of_writers != 0)
     434                 :   {
     435              40 :     if (number_of_readers != 0)
     436                 :     {
     437              20 :       param=(int*) malloc(sizeof(int));
     438              20 :       *param= number_of_readers;
     439              20 :       if ((error= pthread_create(&tid, &thr_attr, test_thread_reader,
     440                 :                                  (void*) param)))
     441                 :       {
     442               0 :         diag("Got error: %d from pthread_create (errno: %d)\n",
     443                 :                 error,errno);
     444               0 :         exit(1);
     445                 :       }
     446              20 :       thread_count++;
     447              20 :       number_of_readers--;
     448                 :     }
     449              40 :     if (number_of_writers != 0)
     450                 :     {
     451              22 :       param=(int*) malloc(sizeof(int));
     452              22 :       *param= number_of_writers;
     453              22 :       if ((error= pthread_create(&tid, &thr_attr, test_thread_writer,
     454                 :                                  (void*) param)))
     455                 :       {
     456               0 :         diag("Got error: %d from pthread_create (errno: %d)\n",
     457                 :                 error,errno);
     458               0 :         exit(1);
     459                 :       }
     460              22 :       thread_count++;
     461              22 :       number_of_writers--;
     462                 :     }
     463                 :   }
     464               4 :   DBUG_PRINT("info", ("Thread started"));
     465               4 :   pthread_mutex_unlock(&LOCK_thread_count);
     466                 : 
     467               4 :   pthread_attr_destroy(&thr_attr);
     468                 : 
     469                 :   /* wait finishing */
     470               4 :   pthread_mutex_lock(&LOCK_thread_count);
     471              50 :   while (thread_count)
     472                 :   {
     473              42 :     if ((error= pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)))
     474               0 :       diag("COND_thread_count: %d from pthread_cond_wait\n",error);
     475                 :   }
     476               4 :   pthread_mutex_unlock(&LOCK_thread_count);
     477               4 :   DBUG_PRINT("info", ("thread ended"));
     478                 : 
     479               4 :   end_pagecache(&pagecache, 1);
     480               4 :   DBUG_PRINT("info", ("Page cache ended"));
     481                 : 
     482               4 :   if (my_close(file1.file, MYF(0)) != 0)
     483                 :   {
     484               0 :     diag( "Got error during file1 closing from close() (errno: %d)\n",
     485                 :             errno);
     486               0 :     exit(1);
     487                 :   }
     488               4 :   my_delete(file1_name, MYF(0));
     489                 : 
     490               4 :   DBUG_PRINT("info", ("file1 (%d) closed", file1.file));
     491               4 :   DBUG_PRINT("info", ("Program end"));
     492                 : 
     493                 :   } /* SKIP_BIG_TESTS */
     494               8 :   my_end(0);
     495                 : 
     496               8 :   return exit_status();
     497                 :   }
     498                 : }

Generated by: LTP GCOV extension version 1.4