Commit 8dca9ea2 authored by unknown's avatar unknown

Fixed ability to read without read lock acquiring. (BUG#39665 related)

storage/maria/ma_pagecache.c:
  Fixed ability to read without read lock acquiring.
storage/maria/unittest/CMakeLists.txt:
  New unit test which tests simple read and prolonged writes consistency added.
storage/maria/unittest/Makefile.am:
  New unit test which tests simple read and prolonged writes consistency added.
storage/maria/unittest/ma_pagecache_rwconsist2.c:
  New unit test which tests simple read and prolonged writes consistency added.
parent dc1607c2
......@@ -2775,7 +2775,7 @@ void pagecache_unlock(PAGECACHE *pagecache,
inc_counter_for_resize_op(pagecache);
/* See NOTE for pagecache_unlock about registering requests */
block= find_block(pagecache, file, pageno, 0, 0,
test(pin == PAGECACHE_PIN_LEFT_UNPINNED), &page_st);
pin == PAGECACHE_PIN_LEFT_UNPINNED, &page_st);
PCBLOCK_INFO(block);
DBUG_ASSERT(block != 0 && page_st == PAGE_READ);
if (first_REDO_LSN_for_page)
......@@ -3080,6 +3080,146 @@ void pagecache_unpin_by_link(PAGECACHE *pagecache,
DBUG_VOID_RETURN;
}
/* description of how to change lock before and after read/write */
struct rw_lock_change
{
my_bool need_lock_change; /* need changing of lock at the end */
enum pagecache_page_lock new_lock; /* lock at the beginning */
enum pagecache_page_lock unlock_lock; /* lock at the end */
};
/* description of how to change pin before and after read/write */
struct rw_pin_change
{
enum pagecache_page_pin new_pin; /* pin status at the beginning */
enum pagecache_page_pin unlock_pin; /* pin status at the end */
};
/**
Depending on the lock which the user wants in pagecache_read(), we
need to acquire a first type of lock at start of pagecache_read(), and
downgrade it to a second type of lock at end. For example, if user
asked for no lock (PAGECACHE_LOCK_LEFT_UNLOCKED) this translates into
taking first a read lock PAGECACHE_LOCK_READ (to rightfully block on
existing write locks) then read then unlock the lock i.e. change lock
to PAGECACHE_LOCK_READ_UNLOCK (the "1" below tells that a change is
needed).
*/
static struct rw_lock_change lock_to_read[8]=
{
{ /*PAGECACHE_LOCK_LEFT_UNLOCKED*/
1,
PAGECACHE_LOCK_READ, PAGECACHE_LOCK_READ_UNLOCK
},
{ /*PAGECACHE_LOCK_LEFT_READLOCKED*/
0,
PAGECACHE_LOCK_LEFT_READLOCKED, PAGECACHE_LOCK_LEFT_READLOCKED
},
{ /*PAGECACHE_LOCK_LEFT_WRITELOCKED*/
0,
PAGECACHE_LOCK_LEFT_WRITELOCKED, PAGECACHE_LOCK_LEFT_WRITELOCKED
},
{ /*PAGECACHE_LOCK_READ*/
1,
PAGECACHE_LOCK_READ, PAGECACHE_LOCK_LEFT_READLOCKED
},
{ /*PAGECACHE_LOCK_WRITE*/
1,
PAGECACHE_LOCK_WRITE, PAGECACHE_LOCK_LEFT_WRITELOCKED
},
{ /*PAGECACHE_LOCK_READ_UNLOCK*/
1,
PAGECACHE_LOCK_LEFT_READLOCKED, PAGECACHE_LOCK_READ_UNLOCK
},
{ /*PAGECACHE_LOCK_WRITE_UNLOCK*/
1,
PAGECACHE_LOCK_LEFT_WRITELOCKED, PAGECACHE_LOCK_WRITE_UNLOCK
},
{ /*PAGECACHE_LOCK_WRITE_TO_READ*/
1,
PAGECACHE_LOCK_LEFT_WRITELOCKED, PAGECACHE_LOCK_WRITE_TO_READ
}
};
/**
Two sets of pin modes (every as for lock upper but for pinning). The
difference between sets if whether we are going to provide caller with
reference on the block or not
*/
static struct rw_pin_change lock_to_pin[2][8]=
{
{
{ /*PAGECACHE_LOCK_LEFT_UNLOCKED*/
PAGECACHE_PIN_LEFT_UNPINNED,
PAGECACHE_PIN_LEFT_UNPINNED
},
{ /*PAGECACHE_LOCK_LEFT_READLOCKED*/
PAGECACHE_PIN_LEFT_UNPINNED,
PAGECACHE_PIN_LEFT_UNPINNED,
},
{ /*PAGECACHE_LOCK_LEFT_WRITELOCKED*/
PAGECACHE_PIN_LEFT_PINNED,
PAGECACHE_PIN_LEFT_PINNED
},
{ /*PAGECACHE_LOCK_READ*/
PAGECACHE_PIN_LEFT_UNPINNED,
PAGECACHE_PIN_LEFT_UNPINNED
},
{ /*PAGECACHE_LOCK_WRITE*/
PAGECACHE_PIN,
PAGECACHE_PIN_LEFT_PINNED
},
{ /*PAGECACHE_LOCK_READ_UNLOCK*/
PAGECACHE_PIN_LEFT_UNPINNED,
PAGECACHE_PIN_LEFT_UNPINNED
},
{ /*PAGECACHE_LOCK_WRITE_UNLOCK*/
PAGECACHE_PIN_LEFT_PINNED,
PAGECACHE_UNPIN
},
{ /*PAGECACHE_LOCK_WRITE_TO_READ*/
PAGECACHE_PIN_LEFT_PINNED,
PAGECACHE_UNPIN
}
},
{
{ /*PAGECACHE_LOCK_LEFT_UNLOCKED*/
PAGECACHE_PIN_LEFT_UNPINNED,
PAGECACHE_PIN_LEFT_UNPINNED
},
{ /*PAGECACHE_LOCK_LEFT_READLOCKED*/
PAGECACHE_PIN_LEFT_UNPINNED,
PAGECACHE_PIN_LEFT_UNPINNED,
},
{ /*PAGECACHE_LOCK_LEFT_WRITELOCKED*/
PAGECACHE_PIN_LEFT_PINNED,
PAGECACHE_PIN_LEFT_PINNED
},
{ /*PAGECACHE_LOCK_READ*/
PAGECACHE_PIN,
PAGECACHE_PIN_LEFT_PINNED
},
{ /*PAGECACHE_LOCK_WRITE*/
PAGECACHE_PIN,
PAGECACHE_PIN_LEFT_PINNED
},
{ /*PAGECACHE_LOCK_READ_UNLOCK*/
PAGECACHE_PIN_LEFT_UNPINNED,
PAGECACHE_PIN_LEFT_UNPINNED
},
{ /*PAGECACHE_LOCK_WRITE_UNLOCK*/
PAGECACHE_PIN_LEFT_PINNED,
PAGECACHE_UNPIN
},
{ /*PAGECACHE_LOCK_WRITE_TO_READ*/
PAGECACHE_PIN_LEFT_PINNED,
PAGECACHE_PIN_LEFT_PINNED,
}
}
};
/*
@brief Read a block of data from a cached file into a buffer;
......@@ -3096,34 +3236,11 @@ void pagecache_unpin_by_link(PAGECACHE *pagecache,
@return address from where the data is placed if successful, 0 - otherwise.
@note Pin will be chosen according to lock parameter (see lock_to_pin)
*/
static enum pagecache_page_pin lock_to_pin[2][8]=
{
{
PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_LEFT_UNLOCKED*/,
PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_LEFT_READLOCKED*/,
PAGECACHE_PIN_LEFT_PINNED /*PAGECACHE_LOCK_LEFT_WRITELOCKED*/,
PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_READ*/,
PAGECACHE_PIN /*PAGECACHE_LOCK_WRITE*/,
PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_READ_UNLOCK*/,
PAGECACHE_UNPIN /*PAGECACHE_LOCK_WRITE_UNLOCK*/,
PAGECACHE_UNPIN /*PAGECACHE_LOCK_WRITE_TO_READ*/
},
{
PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_LEFT_UNLOCKED*/,
PAGECACHE_PIN_LEFT_PINNED /*PAGECACHE_LOCK_LEFT_READLOCKED*/,
PAGECACHE_PIN_LEFT_PINNED /*PAGECACHE_LOCK_LEFT_WRITELOCKED*/,
PAGECACHE_PIN /*PAGECACHE_LOCK_READ*/,
PAGECACHE_PIN /*PAGECACHE_LOCK_WRITE*/,
PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_READ_UNLOCK*/,
PAGECACHE_UNPIN /*PAGECACHE_LOCK_WRITE_UNLOCK*/,
PAGECACHE_PIN_LEFT_PINNED /*PAGECACHE_LOCK_WRITE_TO_READ*/
}
};
/**
@note 'buff', if not NULL, must be long-aligned.
@note If buff==0 then we provide reference on the page so should keep the
page pinned.
*/
uchar *pagecache_read(PAGECACHE *pagecache,
......@@ -3136,21 +3253,26 @@ uchar *pagecache_read(PAGECACHE *pagecache,
PAGECACHE_BLOCK_LINK **page_link)
{
my_bool error= 0;
enum pagecache_page_pin pin= lock_to_pin[test(buff==0)][lock];
enum pagecache_page_pin
new_pin= lock_to_pin[buff==0][lock].new_pin,
unlock_pin= lock_to_pin[buff==0][lock].unlock_pin;
PAGECACHE_BLOCK_LINK *fake_link;
my_bool reg_request;
#ifndef DBUG_OFF
char llbuf[22];
DBUG_ENTER("pagecache_read");
DBUG_PRINT("enter", ("fd: %u page: %s buffer: 0x%lx level: %u "
"t:%s %s %s",
"t:%s (%d)%s->%s %s->%s",
(uint) file->file, ullstr(pageno, llbuf),
(ulong) buff, level,
page_cache_page_type_str[type],
page_cache_page_lock_str[lock],
page_cache_page_pin_str[pin]));
DBUG_ASSERT(buff != 0 || (buff == 0 && (pin == PAGECACHE_PIN ||
pin == PAGECACHE_PIN_LEFT_PINNED)));
lock_to_read[lock].need_lock_change,
page_cache_page_lock_str[lock_to_read[lock].new_lock],
page_cache_page_lock_str[lock_to_read[lock].unlock_lock],
page_cache_page_pin_str[new_pin],
page_cache_page_pin_str[unlock_pin]));
DBUG_ASSERT(buff != 0 || (buff == 0 && (unlock_pin == PAGECACHE_PIN ||
unlock_pin == PAGECACHE_PIN_LEFT_PINNED)));
DBUG_ASSERT(pageno < ((ULL(1)) << 40));
#endif
......@@ -3177,10 +3299,10 @@ uchar *pagecache_read(PAGECACHE *pagecache,
inc_counter_for_resize_op(pagecache);
pagecache->global_cache_r_requests++;
/* See NOTE for pagecache_unlock about registering requests. */
reg_request= ((pin == PAGECACHE_PIN_LEFT_UNPINNED) ||
(pin == PAGECACHE_PIN));
reg_request= ((new_pin == PAGECACHE_PIN_LEFT_UNPINNED) ||
(new_pin == PAGECACHE_PIN));
block= find_block(pagecache, file, pageno, level,
test(lock == PAGECACHE_LOCK_WRITE),
lock == PAGECACHE_LOCK_WRITE,
reg_request, &page_st);
DBUG_PRINT("info", ("Block type: %s current type %s",
page_cache_page_type_str[block->type],
......@@ -3214,7 +3336,8 @@ uchar *pagecache_read(PAGECACHE *pagecache,
block->type == PAGECACHE_EMPTY_PAGE)
block->type= type;
if (make_lock_and_pin(pagecache, block, lock, pin, FALSE))
if (make_lock_and_pin(pagecache, block, lock_to_read[lock].new_lock,
new_pin, FALSE))
{
/*
We failed to write lock the block, cache is unlocked,
......@@ -3262,12 +3385,20 @@ uchar *pagecache_read(PAGECACHE *pagecache,
}
remove_reader(block);
if (lock_to_read[lock].need_lock_change)
{
if (make_lock_and_pin(pagecache, block,
lock_to_read[lock].unlock_lock,
unlock_pin, FALSE))
DBUG_ASSERT(0);
}
/*
Link the block into the LRU chain if it's the last submitted request
for the block and block will not be pinned.
See NOTE for pagecache_unlock about registering requests.
*/
if (pin == PAGECACHE_PIN_LEFT_UNPINNED || pin == PAGECACHE_UNPIN)
if (unlock_pin == PAGECACHE_PIN_LEFT_UNPINNED ||
unlock_pin == PAGECACHE_UNPIN)
unreg_request(pagecache, block, 1);
else
*page_link= block;
......@@ -3485,6 +3616,18 @@ void pagecache_add_level_by_link(PAGECACHE_BLOCK_LINK *block,
write locked before) or PAGECACHE_LOCK_WRITE (delete will write
lock page before delete)
*/
static enum pagecache_page_pin lock_to_pin_one_phase[8]=
{
PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_LEFT_UNLOCKED*/,
PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_LEFT_READLOCKED*/,
PAGECACHE_PIN_LEFT_PINNED /*PAGECACHE_LOCK_LEFT_WRITELOCKED*/,
PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_READ*/,
PAGECACHE_PIN /*PAGECACHE_LOCK_WRITE*/,
PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_READ_UNLOCK*/,
PAGECACHE_UNPIN /*PAGECACHE_LOCK_WRITE_UNLOCK*/,
PAGECACHE_UNPIN /*PAGECACHE_LOCK_WRITE_TO_READ*/
};
my_bool pagecache_delete(PAGECACHE *pagecache,
PAGECACHE_FILE *file,
pgcache_page_no_t pageno,
......@@ -3492,7 +3635,7 @@ my_bool pagecache_delete(PAGECACHE *pagecache,
my_bool flush)
{
my_bool error= 0;
enum pagecache_page_pin pin= lock_to_pin[0][lock];
enum pagecache_page_pin pin= lock_to_pin_one_phase[lock];
DBUG_ENTER("pagecache_delete");
DBUG_PRINT("enter", ("fd: %u page: %lu %s %s",
(uint) file->file, (ulong) pageno,
......@@ -3608,15 +3751,7 @@ my_bool pagecache_delete_pages(PAGECACHE *pagecache,
@retval 1 Error.
*/
/* description of how to change lock before and after write */
struct write_lock_change
{
int need_lock_change; /* need changing of lock at the end of write */
enum pagecache_page_lock new_lock; /* lock at the beginning */
enum pagecache_page_lock unlock_lock; /* lock at the end */
};
static struct write_lock_change write_lock_change_table[]=
static struct rw_lock_change write_lock_change_table[]=
{
{1,
PAGECACHE_LOCK_WRITE,
......@@ -3640,14 +3775,8 @@ static struct write_lock_change write_lock_change_table[]=
PAGECACHE_LOCK_WRITE_TO_READ} /*PAGECACHE_LOCK_WRITE_TO_READ*/
};
/* description of how to change pin before and after write */
struct write_pin_change
{
enum pagecache_page_pin new_pin; /* pin status at the beginning */
enum pagecache_page_pin unlock_pin; /* pin status at the end */
};
static struct write_pin_change write_pin_change_table[]=
static struct rw_pin_change write_pin_change_table[]=
{
{PAGECACHE_PIN_LEFT_PINNED,
PAGECACHE_PIN_LEFT_PINNED} /*PAGECACHE_PIN_LEFT_PINNED*/,
......@@ -3729,7 +3858,7 @@ my_bool pagecache_write_part(PAGECACHE *pagecache,
reg_request= ((pin == PAGECACHE_PIN_LEFT_UNPINNED) ||
(pin == PAGECACHE_PIN));
block= find_block(pagecache, file, pageno, level,
test(write_mode != PAGECACHE_WRITE_DONE &&
(write_mode != PAGECACHE_WRITE_DONE &&
lock != PAGECACHE_LOCK_LEFT_WRITELOCKED &&
lock != PAGECACHE_LOCK_WRITE_UNLOCK &&
lock != PAGECACHE_LOCK_WRITE_TO_READ),
......
......@@ -94,3 +94,5 @@ SET_TARGET_PROPERTIES(ma_pagecache_consist_64kWR-t
PROPERTIES COMPILE_FLAGS "${ma_pagecache_common_cppflags} -DTEST_PAGE_SIZE=65536 -DTEST_WRITERS")
ADD_EXECUTABLE(ma_pagecache_rwconsist_1k-t ma_pagecache_rwconsist.c)
SET_TARGET_PROPERTIES(ma_pagecache_rwconsist_1k-t PROPERTIES COMPILE_FLAGS "-DTEST_PAGE_SIZE=1024")
ADD_EXECUTABLE(ma_pagecache_rwconsist2_1k-t ma_pagecache_rwconsist2.c)
SET_TARGET_PROPERTIES(ma_pagecache_rwconsist2_1k-t PROPERTIES COMPILE_FLAGS "-DTEST_PAGE_SIZE=1024")
......@@ -39,6 +39,7 @@ noinst_PROGRAMS = ma_control_file-t trnman-t \
ma_pagecache_consist_1kWR-t \
ma_pagecache_consist_64kWR-t \
ma_pagecache_rwconsist_1k-t \
ma_pagecache_rwconsist2_1k-t \
ma_test_loghandler-t \
ma_test_loghandler_multigroup-t \
ma_test_loghandler_multithread-t \
......@@ -101,6 +102,8 @@ ma_pagecache_consist_64kWR_t_CPPFLAGS = $(ma_pagecache_common_cppflags) -DTEST_P
ma_pagecache_rwconsist_1k_t_SOURCES = ma_pagecache_rwconsist.c
ma_pagecache_rwconsist_1k_t_CPPFLAGS = -DTEST_PAGE_SIZE=1024
ma_pagecache_rwconsist2_1k_t_SOURCES = ma_pagecache_rwconsist2.c
ma_pagecache_rwconsist2_1k_t_CPPFLAGS = -DTEST_PAGE_SIZE=1024
# the generic lock manager may not be used in the end and lockman1-t crashes,
# and lockman2-t takes at least quarter an hour,
......
/* Copyright (C) 2006-2008 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/**
@file this unit tests consistence of long block writing under write lock
and simultaneous reading of this block with read request without read lock
requirement.
*/
/*
TODO: use pthread_join instead of wait_for_thread_count_to_be_zero, like in
my_atomic-t.c (see BUG#22320).
*/
#include <tap.h>
#include <my_sys.h>
#include <m_string.h>
#include "test_file.h"
#include <tap.h>
#define PCACHE_SIZE (TEST_PAGE_SIZE*1024*8)
#ifndef DBUG_OFF
static const char* default_dbug_option;
#endif
#define SLEEP my_sleep(5)
static char *file1_name= (char*)"page_cache_test_file_1";
static PAGECACHE_FILE file1;
static pthread_cond_t COND_thread_count;
static pthread_mutex_t LOCK_thread_count;
static uint thread_count= 0;
static PAGECACHE pagecache;
static uint number_of_readers= 5;
static uint number_of_writers= 5;
static uint number_of_read_tests= 20000;
static uint number_of_write_tests= 1000;
static uint report_divisor= 50;
/**
@brief Dummy pagecache callback.
*/
static my_bool
dummy_callback(uchar *page __attribute__((unused)),
pgcache_page_no_t page_no __attribute__((unused)),
uchar* data_ptr __attribute__((unused)))
{
return 0;
}
/**
@brief Dummy pagecache callback.
*/
static void
dummy_fail_callback(uchar* data_ptr __attribute__((unused)))
{
return;
}
/**
@brief Checks page consistency
@param buff pointer to the page content
@param task task ID
*/
void check_page(uchar *buff, int task)
{
uint i;
DBUG_ENTER("check_page");
for (i= 1; i < TEST_PAGE_SIZE; i++)
{
if (buff[0] != buff[i])
goto err;
}
DBUG_VOID_RETURN;
err:
diag("Task %d char #%u '%u' != '%u'", task, i, (uint) buff[0],
(uint) buff[i]);
DBUG_PRINT("err", ("try to flush"));
exit(1);
}
void reader(int num)
{
unsigned char buff[TEST_PAGE_SIZE];
uint i;
for (i= 0; i < number_of_read_tests; i++)
{
if (i % report_divisor == 0)
diag("Reader %d - %u", num, i);
pagecache_read(&pagecache, &file1, 0, 3, buff,
PAGECACHE_PLAIN_PAGE,
PAGECACHE_LOCK_LEFT_UNLOCKED,
NULL);
check_page(buff, num);
}
}
void writer(int num)
{
uint i;
uchar *buff;
PAGECACHE_BLOCK_LINK *link;
for (i= 0; i < number_of_write_tests; i++)
{
uchar c= (uchar) rand() % 256;
if (i % report_divisor == 0)
diag("Writer %d - %u", num, i);
buff= pagecache_read(&pagecache, &file1, 0, 3, NULL,
PAGECACHE_PLAIN_PAGE,
PAGECACHE_LOCK_WRITE,
&link);
check_page(buff, num);
bfill(buff, TEST_PAGE_SIZE / 2, c);
SLEEP;
bfill(buff + TEST_PAGE_SIZE/2, TEST_PAGE_SIZE / 2, c);
check_page(buff, num);
pagecache_unlock_by_link(&pagecache, link,
PAGECACHE_LOCK_WRITE_UNLOCK,
PAGECACHE_UNPIN, 0, 0, 1, FALSE);
SLEEP;
}
}
static void *test_thread_reader(void *arg)
{
int param=*((int*) arg);
my_thread_init();
{
DBUG_ENTER("test_reader");
DBUG_PRINT("enter", ("param: %d", param));
reader(param);
DBUG_PRINT("info", ("Thread %s ended", my_thread_name()));
pthread_mutex_lock(&LOCK_thread_count);
ok(1, "reader%d: done", param);
thread_count--;
VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
pthread_mutex_unlock(&LOCK_thread_count);
free((uchar*) arg);
my_thread_end();
}
return 0;
}
static void *test_thread_writer(void *arg)
{
int param=*((int*) arg);
my_thread_init();
{
DBUG_ENTER("test_writer");
writer(param);
DBUG_PRINT("info", ("Thread %s ended", my_thread_name()));
pthread_mutex_lock(&LOCK_thread_count);
ok(1, "writer%d: done", param);
thread_count--;
VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
pthread_mutex_unlock(&LOCK_thread_count);
free((uchar*) arg);
my_thread_end();
}
return 0;
}
int main(int argc __attribute__((unused)),
char **argv __attribute__((unused)))
{
pthread_t tid;
pthread_attr_t thr_attr;
int *param, error, pagen;
MY_INIT(argv[0]);
#ifndef DBUG_OFF
#if defined(__WIN__)
default_dbug_option= "d:t:i:O,\\test_pagecache_consist.trace";
#else
default_dbug_option= "d:t:i:O,/tmp/test_pagecache_consist.trace";
#endif
if (argc > 1)
{
DBUG_SET(default_dbug_option);
DBUG_SET_INITIAL(default_dbug_option);
}
#endif
{
DBUG_ENTER("main");
DBUG_PRINT("info", ("Main thread: %s\n", my_thread_name()));
plan(number_of_writers + number_of_readers);
SKIP_BIG_TESTS(number_of_writers + number_of_readers)
{
if ((file1.file= my_open(file1_name,
O_CREAT | O_TRUNC | O_RDWR, MYF(0))) == -1)
{
diag( "Got error during file1 creation from open() (errno: %d)\n",
errno);
exit(1);
}
pagecache_file_init(file1, &dummy_callback, &dummy_callback,
&dummy_fail_callback, &dummy_callback, NULL);
DBUG_PRINT("info", ("file1: %d", file1.file));
if (my_chmod(file1_name, S_IRWXU | S_IRWXG | S_IRWXO, MYF(MY_WME)))
exit(1);
my_pwrite(file1.file, (const uchar*) "test file", 9, 0, MYF(0));
if ((error= pthread_cond_init(&COND_thread_count, NULL)))
{
diag( "COND_thread_count: %d from pthread_cond_init (errno: %d)\n",
error, errno);
exit(1);
}
if ((error= pthread_mutex_init(&LOCK_thread_count, MY_MUTEX_INIT_FAST)))
{
diag( "LOCK_thread_count: %d from pthread_cond_init (errno: %d)\n",
error, errno);
exit(1);
}
if ((error= pthread_attr_init(&thr_attr)))
{
diag("Got error: %d from pthread_attr_init (errno: %d)\n",
error,errno);
exit(1);
}
if ((error= pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED)))
{
diag(
"Got error: %d from pthread_attr_setdetachstate (errno: %d)\n",
error,errno);
exit(1);
}
#ifdef HAVE_THR_SETCONCURRENCY
VOID(thr_setconcurrency(2));
#endif
if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
TEST_PAGE_SIZE, 0)) == 0)
{
diag("Got error: init_pagecache() (errno: %d)\n",
errno);
exit(1);
}
DBUG_PRINT("info", ("Page cache %d pages", pagen));
{
unsigned char *buffr= malloc(TEST_PAGE_SIZE);
memset(buffr, '\0', TEST_PAGE_SIZE);
pagecache_write(&pagecache, &file1, 0, 3, buffr,
PAGECACHE_PLAIN_PAGE,
PAGECACHE_LOCK_LEFT_UNLOCKED,
PAGECACHE_PIN_LEFT_UNPINNED,
PAGECACHE_WRITE_DELAY,
0, LSN_IMPOSSIBLE);
}
pthread_mutex_lock(&LOCK_thread_count);
while (number_of_readers != 0 || number_of_writers != 0)
{
if (number_of_readers != 0)
{
param=(int*) malloc(sizeof(int));
*param= number_of_readers + number_of_writers;
if ((error= pthread_create(&tid, &thr_attr, test_thread_reader,
(void*) param)))
{
diag("Got error: %d from pthread_create (errno: %d)\n",
error,errno);
exit(1);
}
thread_count++;
number_of_readers--;
}
if (number_of_writers != 0)
{
param=(int*) malloc(sizeof(int));
*param= number_of_writers + number_of_readers;
if ((error= pthread_create(&tid, &thr_attr, test_thread_writer,
(void*) param)))
{
diag("Got error: %d from pthread_create (errno: %d)\n",
error,errno);
exit(1);
}
thread_count++;
number_of_writers--;
}
}
DBUG_PRINT("info", ("Thread started"));
pthread_mutex_unlock(&LOCK_thread_count);
pthread_attr_destroy(&thr_attr);
/* wait finishing */
pthread_mutex_lock(&LOCK_thread_count);
while (thread_count)
{
if ((error= pthread_cond_wait(&COND_thread_count, &LOCK_thread_count)))
diag("COND_thread_count: %d from pthread_cond_wait\n", error);
}
pthread_mutex_unlock(&LOCK_thread_count);
DBUG_PRINT("info", ("thread ended"));
end_pagecache(&pagecache, 1);
DBUG_PRINT("info", ("Page cache ended"));
if (my_close(file1.file, MYF(0)) != 0)
{
diag( "Got error during file1 closing from close() (errno: %d)\n",
errno);
exit(1);
}
my_delete(file1_name, MYF(0));
DBUG_PRINT("info", ("file1 (%d) closed", file1.file));
DBUG_PRINT("info", ("Program end"));
} /* SKIP_BIG_TESTS */
my_end(0);
return exit_status();
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment