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