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 : #include "../maria_def.h"
17 : #include <stdio.h>
18 : #include <errno.h>
19 : #include <tap.h>
20 : #include "../trnman.h"
21 :
22 : extern my_bool maria_log_remove();
23 : extern void translog_example_table_init();
24 :
25 : #ifndef DBUG_OFF
26 : static const char *default_dbug_option;
27 : #endif
28 :
29 : #define PCACHE_SIZE (1024*1024*10)
30 :
31 : #define LOG_FILE_SIZE (1024L*1024L*1024L + 1024L*1024L*512)
32 : /*#define LOG_FLAGS TRANSLOG_SECTOR_PROTECTION | TRANSLOG_PAGE_CRC */
33 : #define LOG_FLAGS 0
34 : /*#define LONG_BUFFER_SIZE (1024L*1024L*1024L + 1024L*1024L*512)*/
35 :
36 : #ifdef MULTIFLUSH_TEST
37 :
38 : #define LONG_BUFFER_SIZE (16384L)
39 : #define MIN_REC_LENGTH 10
40 : #define SHOW_DIVIDER 20
41 : #define ITERATIONS 10000
42 : #define FLUSH_ITERATIONS 1000
43 : #define WRITERS 2
44 : #define FLUSHERS 10
45 :
46 : #else
47 :
48 : #define LONG_BUFFER_SIZE (512L*1024L*1024L)
49 : #define MIN_REC_LENGTH 30
50 : #define SHOW_DIVIDER 10
51 : #define ITERATIONS 3
52 : #define FLUSH_ITERATIONS 0
53 : #define WRITERS 3
54 : #define FLUSHERS 0
55 :
56 : #endif
57 :
58 : static uint number_of_writers= WRITERS;
59 : static uint number_of_flushers= FLUSHERS;
60 :
61 : static pthread_cond_t COND_thread_count;
62 : static pthread_mutex_t LOCK_thread_count;
63 : static uint thread_count;
64 :
65 : static ulong lens[WRITERS][ITERATIONS];
66 : static LSN lsns1[WRITERS][ITERATIONS];
67 : static LSN lsns2[WRITERS][ITERATIONS];
68 : static uchar *long_buffer;
69 :
70 :
71 : static LSN last_lsn; /* For test purposes the variable allow dirty read/write */
72 :
73 : /*
74 : Get pseudo-random length of the field in
75 : limits [MIN_REC_LENGTH..LONG_BUFFER_SIZE]
76 :
77 : SYNOPSIS
78 : get_len()
79 :
80 : RETURN
81 : length - length >= 0 length <= LONG_BUFFER_SIZE
82 : */
83 :
84 : static uint32 get_len()
85 0 : {
86 0 : return MIN_REC_LENGTH +
87 : (uint32)(((ulonglong)rand())*
88 : (LONG_BUFFER_SIZE - MIN_REC_LENGTH - 1)/RAND_MAX);
89 : }
90 :
91 :
92 : /*
93 : Check that the buffer filled correctly
94 :
95 : SYNOPSIS
96 : check_content()
97 : ptr Pointer to the buffer
98 : length length of the buffer
99 :
100 : RETURN
101 : 0 - OK
102 : 1 - Error
103 : */
104 :
105 : static my_bool check_content(uchar *ptr, ulong length)
106 0 : {
107 : ulong i;
108 0 : for (i= 0; i < length; i++)
109 : {
110 0 : if (((uchar)ptr[i]) != (i & 0xFF))
111 : {
112 0 : fprintf(stderr, "Byte # %lu is %x instead of %x",
113 : i, (uint) ptr[i], (uint) (i & 0xFF));
114 0 : return 1;
115 : }
116 : }
117 0 : return 0;
118 : }
119 :
120 :
121 : /*
122 : Read whole record content, and check content (put with offset)
123 :
124 : SYNOPSIS
125 : read_and_check_content()
126 : rec The record header buffer
127 : buffer The buffer to read the record in
128 : skip Skip this number of bytes ot the record content
129 :
130 : RETURN
131 : 0 - OK
132 : 1 - Error
133 : */
134 :
135 :
136 : static my_bool read_and_check_content(TRANSLOG_HEADER_BUFFER *rec,
137 : uchar *buffer, uint skip)
138 0 : {
139 0 : int res= 0;
140 : translog_size_t len;
141 :
142 0 : if ((len= translog_read_record(rec->lsn, 0, rec->record_length,
143 : buffer, NULL)) != rec->record_length)
144 : {
145 0 : fprintf(stderr, "Requested %lu byte, read %lu\n",
146 : (ulong) rec->record_length, (ulong) len);
147 0 : res= 1;
148 : }
149 0 : res|= check_content(buffer + skip, rec->record_length - skip);
150 0 : return(res);
151 : }
152 :
153 : void writer(int num)
154 0 : {
155 : LSN lsn;
156 : TRN trn;
157 : uchar long_tr_id[6];
158 : uint i;
159 :
160 0 : trn.short_id= num;
161 0 : trn.first_undo_lsn= TRANSACTION_LOGGED_LONG_ID;
162 0 : for (i= 0; i < ITERATIONS; i++)
163 : {
164 0 : uint len= get_len();
165 : LEX_CUSTRING parts[TRANSLOG_INTERNAL_PARTS + 1];
166 0 : lens[num][i]= len;
167 :
168 0 : int2store(long_tr_id, num);
169 0 : int4store(long_tr_id + 2, i);
170 0 : parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_tr_id;
171 0 : parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
172 0 : if (translog_write_record(&lsn,
173 : LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
174 : &trn, NULL, 6, TRANSLOG_INTERNAL_PARTS + 1,
175 : parts, NULL, NULL))
176 : {
177 0 : fprintf(stderr, "Can't write LOGREC_FIXED_RECORD_0LSN_EXAMPLE record #%lu "
178 : "thread %i\n", (ulong) i, num);
179 0 : translog_destroy();
180 0 : pthread_mutex_lock(&LOCK_thread_count);
181 0 : ok(0, "write records");
182 0 : pthread_mutex_unlock(&LOCK_thread_count);
183 0 : return;
184 : }
185 0 : lsns1[num][i]= lsn;
186 0 : parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_buffer;
187 0 : parts[TRANSLOG_INTERNAL_PARTS + 0].length= len;
188 0 : if (translog_write_record(&lsn,
189 : LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE,
190 : &trn, NULL,
191 : len, TRANSLOG_INTERNAL_PARTS + 1,
192 : parts, NULL, NULL))
193 : {
194 0 : fprintf(stderr, "Can't write variable record #%lu\n", (ulong) i);
195 0 : translog_destroy();
196 0 : pthread_mutex_lock(&LOCK_thread_count);
197 0 : ok(0, "write records");
198 0 : pthread_mutex_unlock(&LOCK_thread_count);
199 0 : return;
200 : }
201 0 : lsns2[num][i]= lsn;
202 0 : last_lsn= lsn;
203 0 : pthread_mutex_lock(&LOCK_thread_count);
204 0 : ok(1, "write records");
205 0 : pthread_mutex_unlock(&LOCK_thread_count);
206 : }
207 : return;
208 : }
209 :
210 :
211 : static void *test_thread_writer(void *arg)
212 0 : {
213 0 : int param= *((int*) arg);
214 :
215 0 : my_thread_init();
216 :
217 0 : writer(param);
218 :
219 0 : pthread_mutex_lock(&LOCK_thread_count);
220 0 : thread_count--;
221 0 : ok(1, "writer finished"); /* just to show progress */
222 0 : VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are
223 : ready */
224 0 : pthread_mutex_unlock(&LOCK_thread_count);
225 0 : free((uchar*) arg);
226 0 : my_thread_end();
227 0 : return(0);
228 : }
229 :
230 :
231 : static void *test_thread_flusher(void *arg)
232 0 : {
233 0 : int param= *((int*) arg);
234 : int i;
235 :
236 0 : my_thread_init();
237 :
238 0 : for(i= 0; i < FLUSH_ITERATIONS; i++)
239 : {
240 0 : translog_flush(last_lsn);
241 0 : pthread_mutex_lock(&LOCK_thread_count);
242 0 : ok(1, "-- flush %d", param);
243 0 : pthread_mutex_unlock(&LOCK_thread_count);
244 : }
245 :
246 0 : pthread_mutex_lock(&LOCK_thread_count);
247 0 : thread_count--;
248 0 : ok(1, "flusher finished"); /* just to show progress */
249 0 : VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are
250 : ready */
251 0 : pthread_mutex_unlock(&LOCK_thread_count);
252 0 : free((uchar*) arg);
253 0 : my_thread_end();
254 0 : return(0);
255 : }
256 :
257 :
258 : int main(int argc __attribute__((unused)),
259 : char **argv __attribute__ ((unused)))
260 2 : {
261 : uint32 i;
262 : uint pagen;
263 : PAGECACHE pagecache;
264 : LSN first_lsn;
265 : TRANSLOG_HEADER_BUFFER rec;
266 : struct st_translog_scanner_data scanner;
267 : pthread_t tid;
268 : pthread_attr_t thr_attr;
269 : int *param, error;
270 : int rc;
271 :
272 : /* Disabled until Sanja tests */
273 2 : plan(1);
274 2 : ok(1, "disabled");
275 2 : exit(0);
276 :
277 : plan(WRITERS + FLUSHERS +
278 : ITERATIONS * WRITERS * 3 + FLUSH_ITERATIONS * FLUSHERS );
279 :
280 : bzero(&pagecache, sizeof(pagecache));
281 : maria_data_root= (char *)".";
282 : long_buffer= malloc(LONG_BUFFER_SIZE + 7 * 2 + 2);
283 : if (long_buffer == 0)
284 : {
285 : fprintf(stderr, "End of memory\n");
286 : exit(1);
287 : }
288 : for (i= 0; i < (LONG_BUFFER_SIZE + 7 * 2 + 2); i++)
289 : long_buffer[i]= (i & 0xFF);
290 :
291 : MY_INIT(argv[0]);
292 : if (maria_log_remove())
293 : exit(1);
294 :
295 :
296 : #ifndef DBUG_OFF
297 : #if defined(__WIN__)
298 : default_dbug_option= "d:t:i:O,\\ma_test_loghandler.trace";
299 : #else
300 : default_dbug_option= "d:t:i:o,/tmp/ma_test_loghandler.trace";
301 : #endif
302 : if (argc > 1)
303 : {
304 : DBUG_SET(default_dbug_option);
305 : DBUG_SET_INITIAL(default_dbug_option);
306 : }
307 : #endif
308 :
309 :
310 : if ((error= pthread_cond_init(&COND_thread_count, NULL)))
311 : {
312 : fprintf(stderr, "COND_thread_count: %d from pthread_cond_init "
313 : "(errno: %d)\n", error, errno);
314 : exit(1);
315 : }
316 : if ((error= pthread_mutex_init(&LOCK_thread_count, MY_MUTEX_INIT_FAST)))
317 : {
318 : fprintf(stderr, "LOCK_thread_count: %d from pthread_cond_init "
319 : "(errno: %d)\n", error, errno);
320 : exit(1);
321 : }
322 : if ((error= pthread_attr_init(&thr_attr)))
323 : {
324 : fprintf(stderr, "Got error: %d from pthread_attr_init "
325 : "(errno: %d)\n", error, errno);
326 : exit(1);
327 : }
328 : if ((error= pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED)))
329 : {
330 : fprintf(stderr,
331 : "Got error: %d from pthread_attr_setdetachstate (errno: %d)\n",
332 : error, errno);
333 : exit(1);
334 : }
335 :
336 : #ifdef HAVE_THR_SETCONCURRENCY
337 : VOID(thr_setconcurrency(2));
338 : #endif
339 :
340 : my_thread_global_init();
341 :
342 : if (ma_control_file_open(TRUE, TRUE))
343 : {
344 : fprintf(stderr, "Can't init control file (%d)\n", errno);
345 : exit(1);
346 : }
347 : if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
348 : TRANSLOG_PAGE_SIZE, 0)) == 0)
349 : {
350 : fprintf(stderr, "Got error: init_pagecache() (errno: %d)\n", errno);
351 : exit(1);
352 : }
353 : if (translog_init_with_table(".", LOG_FILE_SIZE, 50112, 0, &pagecache,
354 : LOG_FLAGS, 0, &translog_example_table_init,
355 : 0))
356 : {
357 : fprintf(stderr, "Can't init loghandler (%d)\n", errno);
358 : exit(1);
359 : }
360 : /* Suppressing of automatic record writing */
361 : dummy_transaction_object.first_undo_lsn|= TRANSACTION_LOGGED_LONG_ID;
362 :
363 : srand(122334817L);
364 : {
365 : LEX_CUSTRING parts[TRANSLOG_INTERNAL_PARTS + 1];
366 : uchar long_tr_id[6]=
367 : {
368 : 0x11, 0x22, 0x33, 0x44, 0x55, 0x66
369 : };
370 :
371 : parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_tr_id;
372 : parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
373 : dummy_transaction_object.first_undo_lsn= TRANSACTION_LOGGED_LONG_ID;
374 : if (translog_write_record(&first_lsn,
375 : LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
376 : &dummy_transaction_object, NULL, 6,
377 : TRANSLOG_INTERNAL_PARTS + 1,
378 : parts, NULL, NULL))
379 : {
380 : fprintf(stderr, "Can't write the first record\n");
381 : translog_destroy();
382 : exit(1);
383 : }
384 : }
385 :
386 :
387 : pthread_mutex_lock(&LOCK_thread_count);
388 : while (number_of_writers != 0 || number_of_flushers != 0)
389 : {
390 : if (number_of_writers)
391 : {
392 : param= (int*) malloc(sizeof(int));
393 : *param= number_of_writers - 1;
394 : if ((error= pthread_create(&tid, &thr_attr, test_thread_writer,
395 : (void*) param)))
396 : {
397 : fprintf(stderr, "Got error: %d from pthread_create (errno: %d)\n",
398 : error, errno);
399 : exit(1);
400 : }
401 : thread_count++;
402 : number_of_writers--;
403 : }
404 : if (number_of_flushers)
405 : {
406 : param= (int*) malloc(sizeof(int));
407 : *param= number_of_flushers - 1;
408 : if ((error= pthread_create(&tid, &thr_attr, test_thread_flusher,
409 : (void*) param)))
410 : {
411 : fprintf(stderr, "Got error: %d from pthread_create (errno: %d)\n",
412 : error, errno);
413 : exit(1);
414 : }
415 : thread_count++;
416 : number_of_flushers--;
417 : }
418 : }
419 : pthread_mutex_unlock(&LOCK_thread_count);
420 :
421 : pthread_attr_destroy(&thr_attr);
422 :
423 : /* wait finishing */
424 : pthread_mutex_lock(&LOCK_thread_count);
425 : while (thread_count)
426 : {
427 : if ((error= pthread_cond_wait(&COND_thread_count, &LOCK_thread_count)))
428 : fprintf(stderr, "COND_thread_count: %d from pthread_cond_wait\n", error);
429 : }
430 : pthread_mutex_unlock(&LOCK_thread_count);
431 :
432 : /* Find last LSN and flush up to it (all our log) */
433 : {
434 : LSN max= 0;
435 : for (i= 0; i < WRITERS; i++)
436 : {
437 : if (cmp_translog_addr(lsns2[i][ITERATIONS - 1], max) > 0)
438 : max= lsns2[i][ITERATIONS - 1];
439 : }
440 : translog_flush(max);
441 : }
442 :
443 : rc= 1;
444 :
445 : {
446 : uint indeces[WRITERS];
447 : uint index, stage;
448 : int len;
449 : bzero(indeces, sizeof(uint) * WRITERS);
450 :
451 : bzero(indeces, sizeof(indeces));
452 :
453 : if (translog_scanner_init(first_lsn, 1, &scanner, 0))
454 : {
455 : fprintf(stderr, "scanner init failed\n");
456 : goto err;
457 : }
458 : for (i= 0;; i++)
459 : {
460 : len= translog_read_next_record_header(&scanner, &rec);
461 :
462 : if (len == RECHEADER_READ_ERROR)
463 : {
464 : fprintf(stderr, "1-%d translog_read_next_record_header failed (%d)\n",
465 : i, errno);
466 : translog_free_record_header(&rec);
467 : goto err;
468 : }
469 : if (len == RECHEADER_READ_EOF)
470 : {
471 : if (i != WRITERS * ITERATIONS * 2)
472 : {
473 : fprintf(stderr, "EOL met at iteration %u instead of %u\n",
474 : i, ITERATIONS * WRITERS * 2);
475 : translog_free_record_header(&rec);
476 : goto err;
477 : }
478 : break;
479 : }
480 : index= indeces[rec.short_trid] / 2;
481 : stage= indeces[rec.short_trid] % 2;
482 : if (stage == 0)
483 : {
484 : if (rec.type !=LOGREC_FIXED_RECORD_0LSN_EXAMPLE ||
485 : rec.record_length != 6 ||
486 : uint2korr(rec.header) != rec.short_trid ||
487 : index != uint4korr(rec.header + 2) ||
488 : cmp_translog_addr(lsns1[rec.short_trid][index], rec.lsn) != 0)
489 : {
490 : fprintf(stderr, "Incorrect LOGREC_FIXED_RECORD_0LSN_EXAMPLE "
491 : "data read(%d)\n"
492 : "type %u, strid %u %u, len %u, i: %u %u, "
493 : "lsn(%lu,0x%lx) (%lu,0x%lx)\n",
494 : i, (uint) rec.type,
495 : (uint) rec.short_trid, (uint) uint2korr(rec.header),
496 : (uint) rec.record_length,
497 : (uint) index, (uint) uint4korr(rec.header + 2),
498 : LSN_IN_PARTS(rec.lsn),
499 : LSN_IN_PARTS(lsns1[rec.short_trid][index]));
500 : translog_free_record_header(&rec);
501 : goto err;
502 : }
503 : }
504 : else
505 : {
506 : if (rec.type != LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE ||
507 : len != 9 ||
508 : rec.record_length != lens[rec.short_trid][index] ||
509 : cmp_translog_addr(lsns2[rec.short_trid][index], rec.lsn) != 0 ||
510 : check_content(rec.header, (uint)len))
511 : {
512 : fprintf(stderr,
513 : "Incorrect LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE "
514 : "data read(%d) "
515 : "thread: %d, iteration %d, stage %d\n"
516 : "type %u (%d), len %d, length %lu %lu (%d) "
517 : "lsn(%lu,0x%lx) (%lu,0x%lx)\n",
518 : i, (uint) rec.short_trid, index, stage,
519 : (uint) rec.type, (rec.type !=
520 : LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE),
521 : len,
522 : (ulong) rec.record_length, lens[rec.short_trid][index],
523 : (rec.record_length != lens[rec.short_trid][index]),
524 : LSN_IN_PARTS(rec.lsn),
525 : LSN_IN_PARTS(lsns2[rec.short_trid][index]));
526 : translog_free_record_header(&rec);
527 : goto err;
528 : }
529 : if (read_and_check_content(&rec, long_buffer, 0))
530 : {
531 : fprintf(stderr,
532 : "Incorrect LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE "
533 : "in whole rec read lsn(%lu,0x%lx)\n",
534 : LSN_IN_PARTS(rec.lsn));
535 : translog_free_record_header(&rec);
536 : goto err;
537 : }
538 : }
539 : ok(1, "record read");
540 : translog_free_record_header(&rec);
541 : indeces[rec.short_trid]++;
542 : }
543 : }
544 :
545 : rc= 0;
546 : err:
547 : if (rc)
548 : ok(0, "record read");
549 : translog_destroy();
550 : end_pagecache(&pagecache, 1);
551 : ma_control_file_end();
552 : if (maria_log_remove())
553 : exit(1);
554 :
555 : return(exit_status());
556 : }
|