1 : /* Copyright (C) 2006-2008 MySQL AB, 2008 Sun Microsystems, Inc.
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 : /**
18 : @file this unit tests consistence of long block writing under write lock
19 : and simultaneous reading of this block with read request without read lock
20 : requirement.
21 : */
22 :
23 : /*
24 : TODO: use pthread_join instead of wait_for_thread_count_to_be_zero, like in
25 : my_atomic-t.c (see BUG#22320).
26 : */
27 :
28 : #include <tap.h>
29 : #include <my_sys.h>
30 : #include <m_string.h>
31 : #include "test_file.h"
32 : #include <tap.h>
33 :
34 : #define PCACHE_SIZE (TEST_PAGE_SIZE*1024*8)
35 :
36 : #ifndef DBUG_OFF
37 : static const char* default_dbug_option;
38 : #endif
39 :
40 :
41 : #define SLEEP my_sleep(5)
42 :
43 : static char *file1_name= (char*)"page_cache_test_file_1";
44 : static PAGECACHE_FILE file1;
45 : static pthread_cond_t COND_thread_count;
46 : static pthread_mutex_t LOCK_thread_count;
47 : static uint thread_count= 0;
48 : static PAGECACHE pagecache;
49 :
50 : static uint number_of_readers= 5;
51 : static uint number_of_writers= 5;
52 : static uint number_of_read_tests= 20000;
53 : static uint number_of_write_tests= 1000;
54 : static uint report_divisor= 50;
55 :
56 : /**
57 : @brief Dummy pagecache callback.
58 : */
59 :
60 : static my_bool
61 : dummy_callback(uchar *page __attribute__((unused)),
62 : pgcache_page_no_t page_no __attribute__((unused)),
63 : uchar* data_ptr __attribute__((unused)))
64 0 : {
65 0 : return 0;
66 : }
67 :
68 :
69 : /**
70 : @brief Dummy pagecache callback.
71 : */
72 :
73 : static void
74 : dummy_fail_callback(uchar* data_ptr __attribute__((unused)))
75 0 : {
76 : return;
77 : }
78 :
79 :
80 : /**
81 : @brief Checks page consistency
82 :
83 : @param buff pointer to the page content
84 : @param task task ID
85 : */
86 : void check_page(uchar *buff, int task)
87 0 : {
88 : uint i;
89 0 : DBUG_ENTER("check_page");
90 :
91 0 : for (i= 1; i < TEST_PAGE_SIZE; i++)
92 : {
93 0 : if (buff[0] != buff[i])
94 0 : goto err;
95 : }
96 0 : DBUG_VOID_RETURN;
97 0 : err:
98 0 : diag("Task %d char #%u '%u' != '%u'", task, i, (uint) buff[0],
99 : (uint) buff[i]);
100 0 : DBUG_PRINT("err", ("try to flush"));
101 0 : exit(1);
102 : }
103 :
104 :
105 :
106 : void reader(int num)
107 0 : {
108 : unsigned char buff[TEST_PAGE_SIZE];
109 : uint i;
110 :
111 0 : for (i= 0; i < number_of_read_tests; i++)
112 : {
113 0 : if (i % report_divisor == 0)
114 0 : diag("Reader %d - %u", num, i);
115 0 : pagecache_read(&pagecache, &file1, 0, 3, buff,
116 : PAGECACHE_PLAIN_PAGE,
117 : PAGECACHE_LOCK_LEFT_UNLOCKED,
118 : NULL);
119 0 : check_page(buff, num);
120 : }
121 : }
122 :
123 :
124 : void writer(int num)
125 0 : {
126 : uint i;
127 : uchar *buff;
128 : PAGECACHE_BLOCK_LINK *link;
129 :
130 0 : for (i= 0; i < number_of_write_tests; i++)
131 : {
132 0 : uchar c= (uchar) rand() % 256;
133 :
134 0 : if (i % report_divisor == 0)
135 0 : diag("Writer %d - %u", num, i);
136 0 : buff= pagecache_read(&pagecache, &file1, 0, 3, NULL,
137 : PAGECACHE_PLAIN_PAGE,
138 : PAGECACHE_LOCK_WRITE,
139 : &link);
140 :
141 0 : check_page(buff, num);
142 0 : bfill(buff, TEST_PAGE_SIZE / 2, c);
143 0 : SLEEP;
144 0 : bfill(buff + TEST_PAGE_SIZE/2, TEST_PAGE_SIZE / 2, c);
145 0 : check_page(buff, num);
146 0 : pagecache_unlock_by_link(&pagecache, link,
147 : PAGECACHE_LOCK_WRITE_UNLOCK,
148 : PAGECACHE_UNPIN, 0, 0, 1, FALSE);
149 0 : SLEEP;
150 : }
151 : }
152 :
153 :
154 : static void *test_thread_reader(void *arg)
155 0 : {
156 0 : int param=*((int*) arg);
157 0 : my_thread_init();
158 : {
159 0 : DBUG_ENTER("test_reader");
160 :
161 0 : DBUG_PRINT("enter", ("param: %d", param));
162 :
163 0 : reader(param);
164 :
165 0 : DBUG_PRINT("info", ("Thread %s ended", my_thread_name()));
166 0 : pthread_mutex_lock(&LOCK_thread_count);
167 0 : ok(1, "reader%d: done", param);
168 0 : thread_count--;
169 0 : VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
170 0 : pthread_mutex_unlock(&LOCK_thread_count);
171 0 : free((uchar*) arg);
172 0 : my_thread_end();
173 : }
174 0 : return 0;
175 : }
176 :
177 :
178 : static void *test_thread_writer(void *arg)
179 0 : {
180 0 : int param=*((int*) arg);
181 0 : my_thread_init();
182 : {
183 0 : DBUG_ENTER("test_writer");
184 :
185 0 : writer(param);
186 :
187 0 : DBUG_PRINT("info", ("Thread %s ended", my_thread_name()));
188 0 : pthread_mutex_lock(&LOCK_thread_count);
189 0 : ok(1, "writer%d: done", param);
190 0 : thread_count--;
191 0 : VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
192 0 : pthread_mutex_unlock(&LOCK_thread_count);
193 0 : free((uchar*) arg);
194 0 : my_thread_end();
195 : }
196 0 : return 0;
197 : }
198 :
199 :
200 : int main(int argc __attribute__((unused)),
201 : char **argv __attribute__((unused)))
202 1 : {
203 : pthread_t tid;
204 : pthread_attr_t thr_attr;
205 : int *param, error, pagen;
206 :
207 1 : MY_INIT(argv[0]);
208 :
209 : #ifndef DBUG_OFF
210 : #if defined(__WIN__)
211 : default_dbug_option= "d:t:i:O,\\test_pagecache_consist.trace";
212 : #else
213 1 : default_dbug_option= "d:t:i:O,/tmp/test_pagecache_consist.trace";
214 : #endif
215 1 : if (argc > 1)
216 : {
217 0 : DBUG_SET(default_dbug_option);
218 0 : DBUG_SET_INITIAL(default_dbug_option);
219 : }
220 : #endif
221 :
222 : {
223 1 : DBUG_ENTER("main");
224 1 : DBUG_PRINT("info", ("Main thread: %s\n", my_thread_name()));
225 1 : plan(number_of_writers + number_of_readers);
226 1 : SKIP_BIG_TESTS(number_of_writers + number_of_readers)
227 : {
228 :
229 0 : if ((file1.file= my_open(file1_name,
230 : O_CREAT | O_TRUNC | O_RDWR, MYF(0))) == -1)
231 : {
232 0 : diag( "Got error during file1 creation from open() (errno: %d)\n",
233 : errno);
234 0 : exit(1);
235 : }
236 0 : pagecache_file_init(file1, &dummy_callback, &dummy_callback,
237 : &dummy_fail_callback, &dummy_callback, NULL);
238 0 : DBUG_PRINT("info", ("file1: %d", file1.file));
239 0 : if (my_chmod(file1_name, S_IRWXU | S_IRWXG | S_IRWXO, MYF(MY_WME)))
240 0 : exit(1);
241 0 : my_pwrite(file1.file, (const uchar*) "test file", 9, 0, MYF(0));
242 :
243 0 : if ((error= pthread_cond_init(&COND_thread_count, NULL)))
244 : {
245 0 : diag( "COND_thread_count: %d from pthread_cond_init (errno: %d)\n",
246 : error, errno);
247 0 : exit(1);
248 : }
249 0 : if ((error= pthread_mutex_init(&LOCK_thread_count, MY_MUTEX_INIT_FAST)))
250 : {
251 0 : diag( "LOCK_thread_count: %d from pthread_cond_init (errno: %d)\n",
252 : error, errno);
253 0 : exit(1);
254 : }
255 :
256 0 : if ((error= pthread_attr_init(&thr_attr)))
257 : {
258 0 : diag("Got error: %d from pthread_attr_init (errno: %d)\n",
259 : error,errno);
260 0 : exit(1);
261 : }
262 0 : if ((error= pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED)))
263 : {
264 0 : diag(
265 : "Got error: %d from pthread_attr_setdetachstate (errno: %d)\n",
266 : error,errno);
267 0 : exit(1);
268 : }
269 :
270 : #ifdef HAVE_THR_SETCONCURRENCY
271 : VOID(thr_setconcurrency(2));
272 : #endif
273 :
274 0 : if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
275 : TEST_PAGE_SIZE, 0)) == 0)
276 : {
277 0 : diag("Got error: init_pagecache() (errno: %d)\n",
278 : errno);
279 0 : exit(1);
280 : }
281 0 : DBUG_PRINT("info", ("Page cache %d pages", pagen));
282 : {
283 0 : unsigned char *buffr= malloc(TEST_PAGE_SIZE);
284 0 : memset(buffr, '\0', TEST_PAGE_SIZE);
285 0 : pagecache_write(&pagecache, &file1, 0, 3, buffr,
286 : PAGECACHE_PLAIN_PAGE,
287 : PAGECACHE_LOCK_LEFT_UNLOCKED,
288 : PAGECACHE_PIN_LEFT_UNPINNED,
289 : PAGECACHE_WRITE_DELAY,
290 : 0, LSN_IMPOSSIBLE);
291 : }
292 0 : pthread_mutex_lock(&LOCK_thread_count);
293 :
294 0 : while (number_of_readers != 0 || number_of_writers != 0)
295 : {
296 0 : if (number_of_readers != 0)
297 : {
298 0 : param=(int*) malloc(sizeof(int));
299 0 : *param= number_of_readers + number_of_writers;
300 0 : if ((error= pthread_create(&tid, &thr_attr, test_thread_reader,
301 : (void*) param)))
302 : {
303 0 : diag("Got error: %d from pthread_create (errno: %d)\n",
304 : error,errno);
305 0 : exit(1);
306 : }
307 0 : thread_count++;
308 0 : number_of_readers--;
309 : }
310 0 : if (number_of_writers != 0)
311 : {
312 0 : param=(int*) malloc(sizeof(int));
313 0 : *param= number_of_writers + number_of_readers;
314 0 : if ((error= pthread_create(&tid, &thr_attr, test_thread_writer,
315 : (void*) param)))
316 : {
317 0 : diag("Got error: %d from pthread_create (errno: %d)\n",
318 : error,errno);
319 0 : exit(1);
320 : }
321 0 : thread_count++;
322 0 : number_of_writers--;
323 : }
324 : }
325 0 : DBUG_PRINT("info", ("Thread started"));
326 0 : pthread_mutex_unlock(&LOCK_thread_count);
327 :
328 0 : pthread_attr_destroy(&thr_attr);
329 :
330 : /* wait finishing */
331 0 : pthread_mutex_lock(&LOCK_thread_count);
332 0 : while (thread_count)
333 : {
334 0 : if ((error= pthread_cond_wait(&COND_thread_count, &LOCK_thread_count)))
335 0 : diag("COND_thread_count: %d from pthread_cond_wait\n", error);
336 : }
337 0 : pthread_mutex_unlock(&LOCK_thread_count);
338 0 : DBUG_PRINT("info", ("thread ended"));
339 :
340 0 : end_pagecache(&pagecache, 1);
341 0 : DBUG_PRINT("info", ("Page cache ended"));
342 :
343 0 : if (my_close(file1.file, MYF(0)) != 0)
344 : {
345 0 : diag( "Got error during file1 closing from close() (errno: %d)\n",
346 : errno);
347 0 : exit(1);
348 : }
349 0 : my_delete(file1_name, MYF(0));
350 :
351 0 : DBUG_PRINT("info", ("file1 (%d) closed", file1.file));
352 0 : DBUG_PRINT("info", ("Program end"));
353 : } /* SKIP_BIG_TESTS */
354 1 : my_end(0);
355 :
356 1 : return exit_status();
357 : }
358 : }
|