1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-01 03:47:19 +03:00

postreview changes for page cache and pre review commit for loghandler

storage/maria/unittest/test_file.c:
  Rename: unittest/mysys/test_file.c -> storage/maria/unittest/test_file.c
storage/maria/unittest/test_file.h:
  Rename: unittest/mysys/test_file.h -> storage/maria/unittest/test_file.h
include/pagecache.h:
  A waiting queue mechanism moved to separate file wqueue.*
  Pointer name changed for compatibility
mysys/Makefile.am:
  A waiting queue mechanism moved to separate file wqueue.*
mysys/mf_keycache.c:
  fixed unsigned comparison
mysys/mf_pagecache.c:
  A waiting queue mechanism moved to separate file wqueue.*
  Fixed bug in unregistering block during write
storage/maria/Makefile.am:
  The loghandler files added
storage/maria/ma_control_file.h:
  Now we have loghandler and can compile control file
storage/maria/maria_def.h:
  Including files need for compilation of maria
storage/maria/unittest/Makefile.am:
  unit tests of loghandler
storage/maria/unittest/ma_control_file-t.c:
  Used maria def
storage/maria/unittest/mf_pagecache_consist.c:
  fixed memory overrun
storage/maria/unittest/mf_pagecache_single.c:
  fixed used uninitialized memory
unittest/mysys/Makefile.am:
  unittests of pagecache moved to maria becase pagecache need loghandler
include/wqueue.h:
  New BitKeeper file ``include/wqueue.h''
mysys/wqueue.c:
  New BitKeeper file ``mysys/wqueue.c''
storage/maria/ma_loghandler.c:
  New BitKeeper file ``storage/maria/ma_loghandler.c''
storage/maria/ma_loghandler.h:
  New BitKeeper file ``storage/maria/ma_loghandler.h''
storage/maria/ma_loghandler_lsn.h:
  New BitKeeper file ``storage/maria/ma_loghandler_lsn.h''
storage/maria/unittest/ma_test_loghandler-t.c:
  New BitKeeper file ``storage/maria/unittest/ma_test_loghandler-t.c''
storage/maria/unittest/ma_test_loghandler_multigroup-t.c:
  New BitKeeper file ``storage/maria/unittest/ma_test_loghandler_multigroup-t.c''
storage/maria/unittest/ma_test_loghandler_multithread-t.c:
  New BitKeeper file ``storage/maria/unittest/ma_test_loghandler_multithread-t.c''
storage/maria/unittest/ma_test_loghandler_pagecache-t.c:
  New BitKeeper file ``storage/maria/unittest/ma_test_loghandler_pagecache-t.c''
This commit is contained in:
unknown
2007-02-02 09:41:32 +02:00
parent 5c7960965c
commit 0254009221
23 changed files with 8160 additions and 539 deletions

View File

@ -20,11 +20,13 @@
#define _pagecache_h
C_MODE_START
#include "../storage/maria/ma_loghandler_lsn.h"
/* Type of the page */
enum pagecache_page_type
{
#ifndef DBUG_OFF
/* used only for control page type chenging during debugging */
/* used only for control page type changing during debugging */
PAGECACHE_EMPTY_PAGE,
#endif
/* the page does not contain LSN */
@ -34,7 +36,7 @@ enum pagecache_page_type
};
/*
This enum describe lock status changing. every typr of page cache will
This enum describe lock status changing. every type of page cache will
interpret WRITE/READ lock as it need.
*/
enum pagecache_page_lock
@ -71,9 +73,7 @@ enum pagecache_write_mode
typedef void *PAGECACHE_PAGE_LINK;
/* TODO: move to loghandler emulator */
typedef void LOG_HANDLER;
typedef void *LSN;
typedef void *LSN_PTR;
/* file descriptor for Maria */
typedef struct st_pagecache_file
@ -82,7 +82,7 @@ typedef struct st_pagecache_file
} PAGECACHE_FILE;
/* page number for maria */
typedef uint32 maria_page_no_t;
typedef uint32 pgcache_page_no_t;
/* declare structures that is used by st_pagecache */
@ -93,11 +93,9 @@ typedef struct st_pagecache_page PAGECACHE_PAGE;
struct st_pagecache_hash_link;
typedef struct st_pagecache_hash_link PAGECACHE_HASH_LINK;
/* info about requests in a waiting queue */
typedef struct st_pagecache_wqueue
{
struct st_my_thread_var *last_thread; /* circular list of waiting threads */
} PAGECACHE_WQUEUE;
#include <wqueue.h>
typedef my_bool (*pagecache_disk_read_validator)(byte *page, gptr data);
#define PAGECACHE_CHANGED_BLOCKS_HASH 128 /* must be power of 2 */
@ -136,16 +134,14 @@ typedef struct st_pagecache
PAGECACHE_BLOCK_LINK *used_last;/* ptr to the last block of the LRU chain */
PAGECACHE_BLOCK_LINK *used_ins;/* ptr to the insertion block in LRU chain */
pthread_mutex_t cache_lock; /* to lock access to the cache structure */
PAGECACHE_WQUEUE resize_queue; /* threads waiting during resize operation */
PAGECACHE_WQUEUE waiting_for_hash_link;/* waiting for a free hash link */
PAGECACHE_WQUEUE waiting_for_block; /* requests waiting for a free block */
WQUEUE resize_queue; /* threads waiting during resize operation */
WQUEUE waiting_for_hash_link;/* waiting for a free hash link */
WQUEUE waiting_for_block; /* requests waiting for a free block */
/* hash for dirty file bl.*/
PAGECACHE_BLOCK_LINK *changed_blocks[PAGECACHE_CHANGED_BLOCKS_HASH];
/* hash for other file bl.*/
PAGECACHE_BLOCK_LINK *file_blocks[PAGECACHE_CHANGED_BLOCKS_HASH];
LOG_HANDLER *loghandler; /* loghandler structure */
/*
The following variables are and variables used to hold parameters for
initializing the key cache.
@ -169,24 +165,29 @@ typedef struct st_pagecache
extern int init_pagecache(PAGECACHE *pagecache, my_size_t use_mem,
uint division_limit, uint age_threshold,
uint block_size,
LOG_HANDLER *loghandler);
uint block_size);
extern int resize_pagecache(PAGECACHE *pagecache,
my_size_t use_mem, uint division_limit,
uint age_threshold);
extern void change_pagecache_param(PAGECACHE *pagecache, uint division_limit,
uint age_threshold);
extern byte *pagecache_read(PAGECACHE *pagecache,
#define pagecache_read(P,F,N,L,B,T,K,I) \
pagecache_valid_read(P,F,N,L,B,T,K,I,0,0)
extern byte *pagecache_valid_read(PAGECACHE *pagecache,
PAGECACHE_FILE *file,
maria_page_no_t pageno,
pgcache_page_no_t pageno,
uint level,
byte *buff,
enum pagecache_page_type type,
enum pagecache_page_lock lock,
PAGECACHE_PAGE_LINK *link);
PAGECACHE_PAGE_LINK *link,
pagecache_disk_read_validator validator,
gptr validator_data);
extern my_bool pagecache_write(PAGECACHE *pagecache,
PAGECACHE_FILE *file,
maria_page_no_t pageno,
pgcache_page_no_t pageno,
uint level,
byte *buff,
enum pagecache_page_type type,
@ -196,20 +197,20 @@ extern my_bool pagecache_write(PAGECACHE *pagecache,
PAGECACHE_PAGE_LINK *link);
extern void pagecache_unlock_page(PAGECACHE *pagecache,
PAGECACHE_FILE *file,
maria_page_no_t pageno,
pgcache_page_no_t pageno,
enum pagecache_page_lock lock,
enum pagecache_page_pin pin,
my_bool stamp_this_page,
LSN first_REDO_LSN_for_page);
LSN_PTR first_REDO_LSN_for_page);
extern void pagecache_unlock(PAGECACHE *pagecache,
PAGECACHE_PAGE_LINK *link,
enum pagecache_page_lock lock,
enum pagecache_page_pin pin,
my_bool stamp_this_page,
LSN first_REDO_LSN_for_page);
LSN_PTR first_REDO_LSN_for_page);
extern void pagecache_unpin_page(PAGECACHE *pagecache,
PAGECACHE_FILE *file,
maria_page_no_t pageno);
pgcache_page_no_t pageno);
extern void pagecache_unpin(PAGECACHE *pagecache,
PAGECACHE_PAGE_LINK *link);
extern int flush_pagecache_blocks(PAGECACHE *keycache,
@ -217,7 +218,7 @@ extern int flush_pagecache_blocks(PAGECACHE *keycache,
enum flush_type type);
extern my_bool pagecache_delete_page(PAGECACHE *pagecache,
PAGECACHE_FILE *file,
maria_page_no_t pageno,
pgcache_page_no_t pageno,
enum pagecache_page_lock lock,
my_bool flush);
extern void end_pagecache(PAGECACHE *keycache, my_bool cleanup);

26
include/wqueue.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef _wqueue_h
#define _wqueue_h
#include <my_global.h>
#include <my_pthread.h>
/* info about requests in a waiting queue */
typedef struct st_pagecache_wqueue
{
struct st_my_thread_var *last_thread; /* circular list of waiting
threads */
} WQUEUE;
#ifdef THREAD
void wqueue_link_into_queue(WQUEUE *wqueue, struct st_my_thread_var *thread);
void wqueue_unlink_from_queue(WQUEUE *wqueue, struct st_my_thread_var *thread);
void wqueue_add_to_queue(WQUEUE *wqueue, struct st_my_thread_var *thread);
void wqueue_add_and_wait(WQUEUE *wqueue,
struct st_my_thread_var *thread,
pthread_mutex_t *lock);
void wqueue_release_queue(WQUEUE *wqueue);
#endif
#endif

View File

@ -56,7 +56,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \
my_handler.c my_netware.c my_largepage.c \
my_memmem.c \
my_windac.c my_access.c base64.c my_libwrap.c \
mf_pagecache.c
mf_pagecache.c wqueue.c
EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \
thr_mutex.c thr_rwlock.c \
CMakeLists.txt mf_soundex.c \

View File

@ -1008,12 +1008,12 @@ static void unlink_block(KEY_CACHE *keycache, BLOCK_LINK *block)
KEYCACHE_THREAD_TRACE("unlink_block");
#if defined(KEYCACHE_DEBUG)
KEYCACHE_DBUG_ASSERT(keycache->blocks_available != 0);
keycache->blocks_available--;
KEYCACHE_DBUG_PRINT("unlink_block",
("unlinked block %u status=%x #requests=%u #available=%u",
BLOCK_NUMBER(block), block->status,
block->requests, keycache->blocks_available));
KEYCACHE_DBUG_ASSERT(keycache->blocks_available >= 0);
#endif
}

File diff suppressed because it is too large Load Diff

167
mysys/wqueue.c Normal file
View File

@ -0,0 +1,167 @@
#include <wqueue.h>
#define STRUCT_PTR(TYPE, MEMBER, a) \
(TYPE *) ((char *) (a) - offsetof(TYPE, MEMBER))
/*
Link a thread into double-linked queue of waiting threads.
SYNOPSIS
wqueue_link_into_queue()
wqueue pointer to the queue structure
thread pointer to the thread to be added to the queue
RETURN VALUE
none
NOTES.
Queue is represented by a circular list of the thread structures
The list is double-linked of the type (**prev,*next), accessed by
a pointer to the last element.
*/
void wqueue_link_into_queue(WQUEUE *wqueue, struct st_my_thread_var *thread)
{
struct st_my_thread_var *last;
if (!(last= wqueue->last_thread))
{
/* Queue is empty */
thread->next= thread;
thread->prev= &thread->next;
}
else
{
thread->prev= last->next->prev;
last->next->prev= &thread->next;
thread->next= last->next;
last->next= thread;
}
wqueue->last_thread= thread;
}
/*
Add a thread to single-linked queue of waiting threads
SYNOPSIS
wqueue_add_to_queue()
wqueue pointer to the queue structure
thread pointer to the thread to be added to the queue
RETURN VALUE
none
NOTES.
Queue is represented by a circular list of the thread structures
The list is single-linked of the type (*next), accessed by a pointer
to the last element.
*/
void wqueue_add_to_queue(WQUEUE *wqueue, struct st_my_thread_var *thread)
{
struct st_my_thread_var *last;
if (!(last= wqueue->last_thread))
thread->next= thread;
else
{
thread->next= last->next;
last->next= thread;
}
wqueue->last_thread= thread;
}
/*
Unlink a thread from double-linked queue of waiting threads
SYNOPSIS
wqueue_unlink_from_queue()
wqueue pointer to the queue structure
thread pointer to the thread to be removed from the queue
RETURN VALUE
none
NOTES.
See NOTES for link_into_queue
*/
void wqueue_unlink_from_queue(WQUEUE *wqueue, struct st_my_thread_var *thread)
{
if (thread->next == thread)
/* The queue contains only one member */
wqueue->last_thread= NULL;
else
{
thread->next->prev= thread->prev;
*thread->prev= thread->next;
if (wqueue->last_thread == thread)
wqueue->last_thread= STRUCT_PTR(struct st_my_thread_var, next,
thread->prev);
}
thread->next= NULL;
}
/*
Remove all threads from queue signaling them to proceed
SYNOPSIS
wqueue_realease_queue()
wqueue pointer to the queue structure
thread pointer to the thread to be added to the queue
RETURN VALUE
none
NOTES.
See notes for add_to_queue
When removed from the queue each thread is signaled via condition
variable thread->suspend.
*/
void wqueue_release_queue(WQUEUE *wqueue)
{
struct st_my_thread_var *last= wqueue->last_thread;
struct st_my_thread_var *next= last->next;
struct st_my_thread_var *thread;
do
{
thread= next;
pthread_cond_signal(&thread->suspend);
next= thread->next;
thread->next= NULL;
}
while (thread != last);
wqueue->last_thread= NULL;
}
/*
Add thread and wait
SYNOPSYS
wqueue_add_and_wait()
wqueue queue to add to
thread thread which is waiting
lock mutex need for the operation
*/
void wqueue_add_and_wait(WQUEUE *wqueue,
struct st_my_thread_var *thread, pthread_mutex_t *lock)
{
DBUG_ENTER("wqueue_add_and_wait");
DBUG_PRINT("enter", ("thread ox%lxcond 0x%lx, mutex 0x%lx",
(ulong) thread, (ulong) &thread->suspend, (ulong) lock));
wqueue_add_to_queue(wqueue, thread);
do
{
DBUG_PRINT("info", ("wait... cond 0x%lx, mutex 0x%lx",
(ulong) &thread->suspend, (ulong) lock));
pthread_cond_wait(&thread->suspend, lock);
DBUG_PRINT("info", ("wait done cond 0x%lx, mutex 0x%lx, next 0x%lx",
(ulong) &thread->suspend, (ulong) lock,
(ulong) thread->next));
}
while (thread->next);
DBUG_VOID_RETURN;
}

View File

@ -110,7 +110,7 @@ libmaria_a_SOURCES = ma_init.c ma_open.c ma_extra.c ma_info.c ma_rkey.c \
ma_ft_nlq_search.c ft_maria.c ma_sort.c \
ha_maria.cc trnman.c lockman.c tablockman.c \
ma_rt_index.c ma_rt_key.c ma_rt_mbr.c ma_rt_split.c \
ma_sp_key.c ma_control_file.c
ma_sp_key.c ma_control_file.c ma_loghandler.c
CLEANFILES = test?.MA? FT?.MA? isam.log ma_test_all ma_rt_test.MA? sp_test.MA?
SUFFIXES = .sh

View File

@ -17,28 +17,10 @@
/*
WL#3234 Maria control file
First version written by Guilhem Bichot on 2006-04-27.
Does not compile yet.
*/
#ifndef _control_file_h
#define _control_file_h
/*
Not everybody needs to call the control file that's why control_file.h is
not in maria_def.h. However, policy or habit may want to change this.
*/
#ifndef REMOVE_WHEN_SANJA_PUSHES_LOG_HANDLER
/*
this is to get the control file to compile, until Sanja pushes the log
handler which will supersede those definitions.
*/
typedef struct st_lsn {
uint32 file_no;
uint32 rec_offset;
} LSN;
#define maria_data_root "."
#endif
#ifndef _ma_control_file_h
#define _ma_control_file_h
#define CONTROL_FILE_BASE_NAME "maria_control"
/*

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,314 @@
#ifndef _ma_loghandler_h
#define _ma_loghandler_h
/* Transaction log flags */
#define TRANSLOG_PAGE_CRC 1
#define TRANSLOG_SECTOR_PROTECTION (1<<1)
#define TRANSLOG_RECORD_CRC (1<<2)
/* page size in transaction log */
#define TRANSLOG_PAGE_SIZE (8*1024)
#include "ma_loghandler_lsn.h"
/* short transaction ID type */
typedef uint16 SHORT_TRANSACTION_ID;
/* types of records in the transaction log */
enum translog_record_type
{
LOGREC_RESERVED_FOR_CHUNKS23= 0,
LOGREC_REDO_INSERT_ROW_HEAD= 1,
LOGREC_REDO_INSERT_ROW_TAIL= 2,
LOGREC_REDO_INSERT_ROW_BLOB= 3,
LOGREC_REDO_INSERT_ROW_BLOBS= 4,
LOGREC_REDO_PURGE_ROW= 5,
eLOGREC_REDO_PURGE_BLOCKS= 6,
LOGREC_REDO_DELETE_ROW= 7,
LOGREC_REDO_UPDATE_ROW_HEAD= 8,
LOGREC_REDO_INDEX= 9,
LOGREC_REDO_UNDELETE_ROW= 10,
LOGREC_CLR_END= 11,
LOGREC_PURGE_END= 12,
LOGREC_UNDO_ROW_INSERT= 13,
LOGREC_UNDO_ROW_DELETE= 14,
LOGREC_UNDO_ROW_UPDATE= 15,
LOGREC_UNDO_KEY_INSERT= 16,
LOGREC_UNDO_KEY_DELETE= 17,
LOGREC_PREPARE= 18,
LOGREC_PREPARE_WITH_UNDO_PURGE= 19,
LOGREC_COMMIT= 20,
LOGREC_COMMIT_WITH_UNDO_PURGE= 21,
LOGREC_CHECKPOINT_PAGE= 22,
LOGREC_CHECKPOINT_TRAN= 23,
LOGREC_CHECKPOINT_TABL= 24,
LOGREC_REDO_CREATE_TABLE= 25,
LOGREC_REDO_RENAME_TABLE= 26,
LOGREC_REDO_DROP_TABLE= 27,
LOGREC_REDO_TRUNCATE_TABLE= 28,
LOGREC_FILE_ID= 29,
LOGREC_LONG_TRANSACTION_ID= 30,
LOGREC_RESERVED_FUTURE_EXTENSION= 63
};
#define LOGREC_NUMBER_OF_TYPES 64
typedef uint32 translog_size_t;
#define TRANSLOG_RECORD_HEADER_MAX_SIZE 1024
typedef struct st_translog_group_descriptor
{
TRANSLOG_ADDRESS addr;
uint8 num;
} TRANSLOG_GROUP;
typedef struct st_translog_header_buffer
{
/* LSN of the read record */
LSN lsn;
/* type of the read record */
enum translog_record_type type;
/* short transaction ID or 0 if it has no sense for the record */
SHORT_TRANSACTION_ID short_trid;
/*
The Record length in buffer (including read header, but excluding
hidden part of record (type, short TrID, length)
*/
translog_size_t record_length;
/*
Real compressed LSN(s) size economy (<number of LSN(s)>*7 - <real_size>)
*/
uint16 compressed_LSN_economy;
/*
Buffer for write decoded header of the record (depend on the record
type)
*/
uchar header[TRANSLOG_RECORD_HEADER_MAX_SIZE];
/* non read body data offset on the page */
uint16 non_header_data_start_offset;
/* non read body data length in this first chunk */
uint16 non_header_data_len;
/* number of groups listed in */
uint groups_no;
/* array of groups descriptors, can be used only if groups_no > 0 */
TRANSLOG_GROUP *groups;
/* in multi-group number of chunk0 pages (valid only if groups_no > 0) */
uint chunk0_pages;
/* chunk 0 data address (valid only if groups_no > 0) */
TRANSLOG_ADDRESS chunk0_data_addr;
/* chunk 0 data size (valid only if groups_no > 0) */
uint16 chunk0_data_len;
} TRANSLOG_HEADER_BUFFER;
struct st_translog_scanner_data
{
uchar buffer[TRANSLOG_PAGE_SIZE]; /* buffer for page content */
TRANSLOG_ADDRESS page_addr; /* current page address */
TRANSLOG_ADDRESS horizon; /* end of the log which we saw
last time */
TRANSLOG_ADDRESS last_file_page; /* Last page on in this file */
uchar *page; /* page content pointer */
translog_size_t page_offset; /* offset of the chunk in the
page */
my_bool fixed_horizon; /* set horizon only once at
init */
};
struct st_translog_reader_data
{
TRANSLOG_HEADER_BUFFER header; /* Header */
struct st_translog_scanner_data scanner; /* chunks scanner */
translog_size_t body_offset; /* current chunk body offset */
translog_size_t current_offset; /* data offset from the record
beginning */
uint16 read_header; /* number of bytes read in
header */
uint16 chunk_size; /* current chunk size */
uint current_group; /* current group */
uint current_chunk; /* current chunk in the group */
my_bool eor; /* end of the record */
};
/*
Initialize transaction log
SYNOPSIS
translog_init()
directory Directory where log files are put
log_file_max_size max size of one log size (for new logs creation)
server_version version of MySQL servger (MYSQL_VERSION_ID)
server_id server ID (replication & Co)
pagecache Page cache for the log reads
flags flags (TRANSLOG_PAGE_CRC, TRANSLOG_SECTOR_PROTECTION
TRANSLOG_RECORD_CRC)
RETURN
0 - OK
1 - Error
*/
my_bool translog_init(const char *directory, uint32 log_file_max_size,
uint32 server_version,
uint32 server_id, PAGECACHE *pagecache, uint flags);
/*
Write the log record
SYNOPSIS
translog_write_record()
lsn LSN of the record will be writen here
type the log record type
short_trid Sort transaction ID or 0 if it has no sense
tcb Transaction control block pointer for hooks by
record log type
partN_length length of Ns part of the log
partN_buffer pointer on Ns part buffer
0 sign of the end of parts
RETURN
0 - OK
1 - Error
*/
my_bool translog_write_record(LSN *lsn,
enum translog_record_type type,
SHORT_TRANSACTION_ID short_trid,
void *tcb,
translog_size_t part1_length,
uchar *part1_buff, ...);
/*
Free log handler resources
SYNOPSIS
translog_destroy()
*/
void translog_destroy();
/*
Read record header and some fixed part of a record (the part depend on
record type).
SYNOPSIS
translog_read_record_header()
lsn log record serial number (address of the record)
buff log record header buffer
NOTE
- lsn can point to TRANSLOG_HEADER_BUFFER::lsn and it will be processed
correctly.
- Some type of record can be read completely by this call
- "Decoded" header stored in TRANSLOG_HEADER_BUFFER::header (relative
LSN can be translated to absolute one), some fields can be added
(like actual header length in the record if the header has variable
length)
RETURN
0 - error
number of bytes in TRANSLOG_HEADER_BUFFER::header where stored decoded
part of the header
*/
translog_size_t translog_read_record_header(LSN *lsn,
TRANSLOG_HEADER_BUFFER *buff);
/*
Free resources used by TRANSLOG_HEADER_BUFFER
SYNOPSIS
translog_free_record_header();
*/
void translog_free_record_header(TRANSLOG_HEADER_BUFFER *buff);
/*
Read a part of the record.
SYNOPSIS
translog_read_record_header()
lsn log record serial number (address of the record)
offset from the beginning of the record beginning (read
by translog_read_record_header).
length length of record part which have to be read.
buffer buffer where to read the record part (have to be at
least 'length' bytes length)
RETURN
0 - error (or read out of the record)
length of data actually read
*/
translog_size_t translog_read_record(LSN *lsn,
translog_size_t offset,
translog_size_t length,
uchar *buffer,
struct st_translog_reader_data *data);
/*
Flush the log up to given LSN (included)
SYNOPSIS
translog_flush()
lsn log record serial number up to which (inclusive)
the log have to be flushed
RETURN
0 - OK
1 - Error
*/
my_bool translog_flush(LSN *lsn);
/*
Read record header and some fixed part of the next record (the part
depend on record type).
SYNOPSIS
translog_read_next_record_header()
lsn log record serial number (address of the record)
previous to the record which will be read
If LSN present scanner will be initialized from it,
do not use LSN after initialization for fast scanning.
buff log record header buffer
fixed_horizon true if it is OK do not read records which was written
after scaning begining
scanner data for scaning if lsn is NULL scanner data
will be used for continue scaning.
scanner can be NULL.
NOTE
- lsn can point to TRANSLOG_HEADER_BUFFER::lsn and it will be processed
correctly (lsn in buffer will be replaced by next record, but initial
lsn will be read correctly).
- it is like translog_read_record_header, but read next record, so see
its NOTES.
- in case of end of the log buff->lsn will be set to
(CONTROL_FILE_IMPOSSIBLE_LOGNO, 0)
RETURN
0 - error
TRANSLOG_RECORD_HEADER_MAX_SIZE + 1 - End of the log
number of bytes in TRANSLOG_HEADER_BUFFER::header where stored decoded
part of the header
*/
translog_size_t translog_read_next_record_header(LSN *lsn,
TRANSLOG_HEADER_BUFFER *buff,
my_bool fixed_horizon,
struct
st_translog_scanner_data
*scanner);
#endif

View File

@ -0,0 +1,39 @@
#ifndef _ma_loghandler_lsn_h
#define _ma_loghandler_lsn_h
/* Transaction log record address (file_no is int24 on the disk) */
typedef struct st_translog_address
{
uint32 file_no;
uint32 rec_offset;
} TRANSLOG_ADDRESS;
/*
Compare addresses
A1 > A2 -> result > 0
A1 == A2 -> 0
A1 < A2 -> result < 0
*/
#define cmp_translog_addr(A1,A2) \
((A1).file_no == (A2).file_no ? \
((int64)(A1).rec_offset) - (int64)(A2).rec_offset : \
((int64)(A1).file_no - (int64)(A2).file_no))
/* LSN type (address of certain log record chank */
typedef TRANSLOG_ADDRESS LSN;
/* Puts LSN into buffer (dst) */
#define lsn7store(dst, lsn) \
do { \
int3store((dst), (lsn)->file_no); \
int4store((dst) + 3, (lsn)->rec_offset); \
} while (0)
/* Unpacks LSN from the buffer (P) */
#define lsn7korr(lsn, P) \
do { \
(lsn)->file_no= uint3korr(P); \
(lsn)->rec_offset= uint4korr((P) + 3); \
} while (0)
#endif

View File

@ -26,6 +26,10 @@
#include <my_no_pthread.h>
#endif
#include <pagecache.h>
#include "ma_loghandler.h"
#include "ma_control_file.h"
/* undef map from my_nosys; We need test-if-disk full */
#undef my_write
@ -438,6 +442,7 @@ extern LIST *maria_open_list;
extern uchar NEAR maria_file_magic[], NEAR maria_pack_file_magic[];
extern uint NEAR maria_read_vec[], NEAR maria_readnext_vec[];
extern uint maria_quick_table_bits;
extern const char *maria_data_root;
extern my_bool maria_inited;
/* This is used by _ma_calc_xxx_key_length och _ma_store_key */

View File

@ -14,8 +14,10 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
AM_CPPFLAGS = @ZLIB_INCLUDES@ -I$(top_builddir)/include
AM_CPPFLAGS += -I$(top_srcdir)/include -I$(top_srcdir)/unittest/mytap
AM_CPPFLAGS = @ZLIB_INCLUDES@ -I$(top_builddir)/include \
-I$(top_srcdir)/include -I$(top_srcdir)/unittest/mytap
INCLUDES = @ZLIB_INCLUDES@ -I$(top_builddir)/include \
-I$(top_srcdir)/include -I$(top_srcdir)/unittest/mytap
# Only reason to link with libmyisam.a here is that it's where some fulltext
# pieces are (but soon we'll remove fulltext dependencies from Maria).
@ -24,6 +26,54 @@ LDADD= $(top_builddir)/unittest/mytap/libmytap.a \
$(top_builddir)/storage/myisam/libmyisam.a \
$(top_builddir)/mysys/libmysys.a \
$(top_builddir)/dbug/libdbug.a \
$(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@
noinst_PROGRAMS = ma_control_file-t trnman-t lockman-t lockman1-t lockman2-t
CLEANFILES = maria_control
$(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@ \
$(top_builddir)/storage/maria/ma_loghandler.o
noinst_PROGRAMS = ma_control_file-t trnman-t lockman-t lockman1-t \
lockman2-t \
mf_pagecache_single_1k-t mf_pagecache_single_8k-t \
mf_pagecache_single_64k-t \
mf_pagecache_consist_1k-t mf_pagecache_consist_64k-t \
mf_pagecache_consist_1kHC-t \
mf_pagecache_consist_64kHC-t \
mf_pagecache_consist_1kRD-t \
mf_pagecache_consist_64kRD-t \
mf_pagecache_consist_1kWR-t \
mf_pagecache_consist_64kWR-t \
ma_test_loghandler-t \
ma_test_loghandler_multigroup-t \
ma_test_loghandler_multithread-t \
ma_test_loghandler_pagecache-t
mf_pagecache_single_src = mf_pagecache_single.c $(top_srcdir)/mysys/mf_pagecache.c test_file.c
mf_pagecache_consist_src = mf_pagecache_consist.c $(top_srcdir)/mysys/mf_pagecache.c test_file.c
mf_pagecache_common_cppflags = -DEXTRA_DEBUG -DPAGECACHE_DEBUG -DMAIN
mf_pagecache_single_1k_t_SOURCES = $(mf_pagecache_single_src)
mf_pagecache_single_8k_t_SOURCES = $(mf_pagecache_single_src)
mf_pagecache_single_64k_t_SOURCES = $(mf_pagecache_single_src)
mf_pagecache_single_1k_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=1024
mf_pagecache_single_8k_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=8192
mf_pagecache_single_64k_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=65536
mf_pagecache_consist_1k_t_SOURCES = $(mf_pagecache_consist_src)
mf_pagecache_consist_1k_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=1024
mf_pagecache_consist_64k_t_SOURCES = $(mf_pagecache_consist_src)
mf_pagecache_consist_64k_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=65536
mf_pagecache_consist_1kHC_t_SOURCES = $(mf_pagecache_consist_src)
mf_pagecache_consist_1kHC_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=1024 -DTEST_HIGH_CONCURENCY
mf_pagecache_consist_64kHC_t_SOURCES = $(mf_pagecache_consist_src)
mf_pagecache_consist_64kHC_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=65536 -DTEST_HIGH_CONCURENCY
mf_pagecache_consist_1kRD_t_SOURCES = $(mf_pagecache_consist_src)
mf_pagecache_consist_1kRD_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=1024 -DTEST_READERS
mf_pagecache_consist_64kRD_t_SOURCES = $(mf_pagecache_consist_src)
mf_pagecache_consist_64kRD_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=65536 -DTEST_READERS
mf_pagecache_consist_1kWR_t_SOURCES = $(mf_pagecache_consist_src)
mf_pagecache_consist_1kWR_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=1024 -DTEST_WRITERS
mf_pagecache_consist_64kWR_t_SOURCES = $(mf_pagecache_consist_src)
mf_pagecache_consist_64kWR_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=65536 -DTEST_WRITERS
CLEANFILES = maria_control page_cache_test_file_1 \
maria_log.???????? maria_control

View File

@ -33,7 +33,7 @@
#endif
#include "maria.h"
#include "../../../storage/maria/ma_control_file.h"
#include "../../../storage/maria/maria_def.h"
#include <my_getopt.h>
char file_name[FN_REFLEN];

View File

@ -0,0 +1,540 @@
#include "../maria_def.h"
#include <stdio.h>
#include <errno.h>
#ifndef DBUG_OFF
static const char *default_dbug_option;
#endif
#define PCACHE_SIZE (1024*1024*10)
#define LONG_BUFFER_SIZE (100 * 1024)
#define LOG_FLAGS TRANSLOG_SECTOR_PROTECTION | TRANSLOG_PAGE_CRC
#define LOG_FILE_SIZE 1024L*1024L*3L
#define ITERATIONS 1600
/*
#define LOG_FLAGS 0
#define LOG_FILE_SIZE 1024L*1024L*1024L
#define ITERATIONS 181000
*/
/*
#define LOG_FLAGS 0
#define LOG_FILE_SIZE 1024L*1024L*3L
#define ITERATIONS 1600
*/
/*
#define LOG_FLAGS 0
#define LOG_FILE_SIZE 1024L*1024L*100L
#define ITERATIONS 65000
*/
/*
Check that the buffer filled correctly
SYNOPSIS
check_content()
ptr Pointer to the buffer
length length of the buffer
RETURN
0 - OK
1 - Error
*/
static my_bool check_content(uchar *ptr, ulong length)
{
ulong i;
uchar buff[2];
for (i= 0; i < length; i++)
{
if (i % 2 == 0)
int2store(buff, i >> 1);
if (ptr[i] != buff[i % 2])
{
fprintf(stderr, "Byte # %lu is %x instead of %x",
i, (uint) ptr[i], (uint) buff[i % 2]);
return 1;
}
}
return 0;
}
/*
Read whole record content, and check content (put with offset)
SYNOPSIS
read_and_check_content()
rec The record header buffer
buffer The buffer to read the record in
skip Skip this number of bytes ot the record content
RETURN
0 - OK
1 - Error
*/
static my_bool read_and_check_content(TRANSLOG_HEADER_BUFFER *rec,
uchar *buffer, uint skip)
{
DBUG_ASSERT(rec->record_length < LONG_BUFFER_SIZE * 2 + 7 * 2 + 2);
if (translog_read_record(&rec->lsn, 0, rec->record_length, buffer, NULL) !=
rec->record_length)
return 1;
return check_content(buffer + skip, rec->record_length - skip);
}
int main(int argc, char *argv[])
{
uint32 i;
uint32 rec_len;
uint pagen;
uchar long_tr_id[6];
uchar lsn_buff[23]=
{
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55
};
uchar long_buffer[LONG_BUFFER_SIZE * 2 + 7 * 2 + 2];
PAGECACHE pagecache;
LSN lsn, lsn_base, first_lsn, *lsn_ptr;
TRANSLOG_HEADER_BUFFER rec;
struct st_translog_scanner_data scanner;
int rc;
MY_INIT(argv[0]);
bzero(&pagecache, sizeof(pagecache));
maria_data_root= ".";
for (i= 0; i < (LONG_BUFFER_SIZE + 7 * 2 + 2); i+= 2)
{
int2store(long_buffer + i, (i >> 1));
/* long_buffer[i]= (i & 0xFF); */
}
bzero(long_tr_id, 6);
#ifndef DBUG_OFF
#if defined(__WIN__)
default_dbug_option= "d:t:i:O,\\ma_test_loghandler.trace";
#else
default_dbug_option= "d:t:i:o,/tmp/ma_test_loghandler.trace";
#endif
if (argc > 1)
{
DBUG_SET(default_dbug_option);
DBUG_SET_INITIAL(default_dbug_option);
}
#endif
if (ma_control_file_create_or_open())
{
fprintf(stderr, "Can't init control file (%d)\n", errno);
exit(1);
}
if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
TRANSLOG_PAGE_SIZE)) == 0)
{
fprintf(stderr, "Got error: init_pagecache() (errno: %d)\n", errno);
exit(1);
}
if (translog_init(".", LOG_FILE_SIZE, 50112, 0, &pagecache, LOG_FLAGS))
{
fprintf(stderr, "Can't init loghandler (%d)\n", errno);
translog_destroy();
exit(1);
}
srandom(122334817L);
long_tr_id[5]= 0xff;
int4store(long_tr_id, 0);
if (translog_write_record(&lsn,
LOGREC_LONG_TRANSACTION_ID,
0, NULL, 6, long_tr_id, 0))
{
fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
translog_destroy();
exit(1);
}
lsn_base= first_lsn= lsn;
for (i= 1; i < ITERATIONS; i++)
{
if (i % 1000 == 0)
printf("write %d\n", i);
if (i % 2)
{
lsn7store(lsn_buff, &lsn_base);
if (translog_write_record(&lsn,
LOGREC_CLR_END,
(i % 0xFFFF), NULL, 7, lsn_buff, 0))
{
fprintf(stderr, "1 Can't write reference defore record #%lu\n",
(ulong) i);
translog_destroy();
exit(1);
}
lsn7store(lsn_buff, &lsn_base);
if ((rec_len= random() / (RAND_MAX / (LONG_BUFFER_SIZE + 1))) < 12)
rec_len= 12;
if (translog_write_record(&lsn,
LOGREC_UNDO_KEY_INSERT,
(i % 0xFFFF),
NULL, 7, lsn_buff, rec_len, long_buffer, 0))
{
fprintf(stderr, "1 Can't write var reference defore record #%lu\n",
(ulong) i);
translog_destroy();
exit(1);
}
}
else
{
lsn7store(lsn_buff, &lsn_base);
lsn7store(lsn_buff + 7, &first_lsn);
if (translog_write_record(&lsn,
LOGREC_UNDO_ROW_DELETE,
(i % 0xFFFF), NULL, 23, lsn_buff, 0))
{
fprintf(stderr, "0 Can't write reference defore record #%lu\n",
(ulong) i);
translog_destroy();
exit(1);
}
lsn7store(lsn_buff, &lsn_base);
lsn7store(lsn_buff + 7, &first_lsn);
if ((rec_len= random() / (RAND_MAX / (LONG_BUFFER_SIZE + 1))) < 19)
rec_len= 19;
if (translog_write_record(&lsn,
LOGREC_UNDO_KEY_DELETE,
(i % 0xFFFF),
NULL, 14, lsn_buff, rec_len, long_buffer, 0))
{
fprintf(stderr, "0 Can't write var reference defore record #%lu\n",
(ulong) i);
translog_destroy();
exit(1);
}
}
int4store(long_tr_id, i);
if (translog_write_record(&lsn,
LOGREC_LONG_TRANSACTION_ID,
(i % 0xFFFF), NULL, 6, long_tr_id, 0))
{
fprintf(stderr, "Can't write record #%lu\n", (ulong) i);
translog_destroy();
exit(1);
}
lsn_base= lsn;
if ((rec_len= random() / (RAND_MAX / (LONG_BUFFER_SIZE + 1))) < 9)
rec_len= 9;
if (translog_write_record(&lsn,
LOGREC_REDO_INSERT_ROW_HEAD,
(i % 0xFFFF), NULL, rec_len, long_buffer, 0))
{
fprintf(stderr, "Can't write variable record #%lu\n", (ulong) i);
translog_destroy();
exit(1);
}
if (translog_flush(&lsn))
{
fprintf(stderr, "Can't flush #%lu\n", (ulong) i);
translog_destroy();
exit(1);
}
}
translog_destroy();
end_pagecache(&pagecache, 1);
ma_control_file_end();
if (ma_control_file_create_or_open())
{
fprintf(stderr, "pass2: Can't init control file (%d)\n", errno);
exit(1);
}
if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
TRANSLOG_PAGE_SIZE)) == 0)
{
fprintf(stderr, "pass2: Got error: init_pagecache() (errno: %d)\n", errno);
exit(1);
}
if (translog_init(".", LOG_FILE_SIZE, 50112, 0, &pagecache, LOG_FLAGS))
{
fprintf(stderr, "pass2: Can't init loghandler (%d)\n", errno);
translog_destroy();
exit(1);
}
srandom(122334817L);
rc= 1;
{
translog_size_t len= translog_read_record_header(&first_lsn, &rec);
if (len == 0)
{
fprintf(stderr, "translog_read_record_header failed (%d)\n", errno);
goto err;
}
if (rec.type !=LOGREC_LONG_TRANSACTION_ID || rec.short_trid != 0 ||
rec.record_length != 6 || uint4korr(rec.header) != 0 ||
(uint)rec.header[4] != 0 || rec.header[5] != 0xFF ||
first_lsn.file_no != rec.lsn.file_no ||
first_lsn.rec_offset != rec.lsn.rec_offset)
{
fprintf(stderr, "Incorrect LOGREC_LONG_TRANSACTION_ID data read(0)\n"
"type %u, strid %u, len %u, i: %u, 4: %u 5: %u, "
"lsn(0x%lx,0x%lx)\n",
(uint) rec.type, (uint) rec.short_trid, (uint) rec.record_length,
uint4korr(rec.header), (uint) rec.header[4], (uint) rec.header[5],
(ulong) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
goto err;
}
lsn= first_lsn;
lsn_ptr= &first_lsn;
for (i= 1;; i++)
{
if (i % 1000 == 0)
printf("read %d\n", i);
len= translog_read_next_record_header(lsn_ptr, &rec, 1, &scanner);
if (len == 0)
{
fprintf(stderr, "1-%d translog_read_next_record_header failed (%d)\n",
i, errno);
goto err;
}
if (rec.lsn.file_no == CONTROL_FILE_IMPOSSIBLE_FILENO)
{
if (i != ITERATIONS)
{
fprintf(stderr, "EOL met at iteration %u instead of %u\n",
i, ITERATIONS);
goto err;
}
break;
}
lsn_ptr= NULL; /* use scanner after its
initialization */
if (i % 2)
{
LSN ref;
lsn7korr(&ref, rec.header);
if (rec.type !=LOGREC_CLR_END || rec.short_trid != (i % 0xFFFF) ||
rec.record_length != 7 || ref.file_no != lsn.file_no ||
ref.rec_offset != lsn.rec_offset)
{
fprintf(stderr, "Incorrect LOGREC_CLR_END data read(%d)"
"type %u, strid %u, len %u, ref(%u,0x%lx), lsn(%u,0x%lx)\n",
i, (uint) rec.type, (uint) rec.short_trid,
(uint) rec.record_length,
(uint) ref.file_no, (ulong) ref.rec_offset,
(uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
goto err;
}
}
else
{
LSN ref1, ref2;
lsn7korr(&ref1, rec.header);
lsn7korr(&ref2, rec.header + 7);
if (rec.type !=LOGREC_UNDO_ROW_DELETE ||
rec.short_trid != (i % 0xFFFF) ||
rec.record_length != 23 ||
ref1.file_no != lsn.file_no ||
ref1.rec_offset != lsn.rec_offset ||
ref2.file_no != first_lsn.file_no ||
ref2.rec_offset != first_lsn.rec_offset ||
rec.header[22] != 0x55 || rec.header[21] != 0xAA ||
rec.header[20] != 0x55 || rec.header[19] != 0xAA ||
rec.header[18] != 0x55 || rec.header[17] != 0xAA ||
rec.header[16] != 0x55 || rec.header[15] != 0xAA ||
rec.header[14] != 0x55)
{
fprintf(stderr, "Incorrect LOGREC_UNDO_ROW_DELETE data read(%d)"
"type %u, strid %u, len %u, ref1(%u,0x%lx), "
"ref2(%u,0x%lx) %x%x%x%x%x%x%x%x%x "
"lsn(%u,0x%lx)\n",
i, (uint) rec.type, (uint) rec.short_trid,
(uint) rec.record_length,
(uint) ref1.file_no, (ulong) ref1.rec_offset,
(uint) ref2.file_no, (ulong) ref2.rec_offset,
(uint) rec.header[14], (uint) rec.header[15],
(uint) rec.header[16], (uint) rec.header[17],
(uint) rec.header[18], (uint) rec.header[19],
(uint) rec.header[20], (uint) rec.header[21],
(uint) rec.header[22],
(uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
goto err;
}
}
len= translog_read_next_record_header(lsn_ptr, &rec, 1, &scanner);
if (len == 0)
{
fprintf(stderr, "1-%d translog_read_next_record_header (var) "
"failed (%d)\n", i, errno);
goto err;
}
if (rec.lsn.file_no == CONTROL_FILE_IMPOSSIBLE_FILENO)
{
fprintf(stderr, "EOL met at the middle of iteration (first var) %u "
"instead of beginning of %u\n", i, ITERATIONS);
goto err;
}
if (i % 2)
{
LSN ref;
lsn7korr(&ref, rec.header);
if ((rec_len= random() / (RAND_MAX / (LONG_BUFFER_SIZE + 1))) < 12)
rec_len= 12;
if (rec.type !=LOGREC_UNDO_KEY_INSERT ||
rec.short_trid != (i % 0xFFFF) ||
rec.record_length != rec_len + 7 ||
len != 12 || ref.file_no != lsn.file_no ||
ref.rec_offset != lsn.rec_offset ||
check_content(rec.header + 7, len - 7))
{
fprintf(stderr, "Incorrect LOGREC_UNDO_KEY_INSERT data read(%d)"
"type %u (%d), strid %u (%d), len %lu, %lu + 7 (%d), "
"hdr len: %u (%d), "
"ref(%u,0x%lx), lsn(%u,0x%lx) (%d), content: %d\n",
i, (uint) rec.type,
rec.type !=LOGREC_UNDO_KEY_INSERT,
(uint) rec.short_trid,
rec.short_trid != (i % 0xFFFF),
(ulong) rec.record_length, (ulong) rec_len,
rec.record_length != rec_len + 7,
(uint) len,
len != 12,
(uint) ref.file_no, (ulong) ref.rec_offset,
(uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset,
(len != 12 || ref.file_no != lsn.file_no ||
ref.rec_offset != lsn.rec_offset),
check_content(rec.header + 7, len - 7));
goto err;
}
if (read_and_check_content(&rec, long_buffer, 7))
{
fprintf(stderr,
"Incorrect LOGREC_UNDO_KEY_INSERT in whole rec read "
"lsn(%u,0x%lx)\n",
(uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
goto err;
}
}
else
{
LSN ref1, ref2;
lsn7korr(&ref1, rec.header);
lsn7korr(&ref2, rec.header + 7);
if ((rec_len= random() / (RAND_MAX / (LONG_BUFFER_SIZE + 1))) < 19)
rec_len= 19;
if (rec.type !=LOGREC_UNDO_KEY_DELETE ||
rec.short_trid != (i % 0xFFFF) ||
rec.record_length != rec_len + 14 ||
len != 19 ||
ref1.file_no != lsn.file_no ||
ref1.rec_offset != lsn.rec_offset ||
ref2.file_no != first_lsn.file_no ||
ref2.rec_offset != first_lsn.rec_offset ||
check_content(rec.header + 14, len - 14))
{
fprintf(stderr, "Incorrect LOGREC_UNDO_KEY_DELETE data read(%d)"
"type %u, strid %u, len %lu != %lu + 7, hdr len: %u, "
"ref1(%u,0x%lx), ref2(%u,0x%lx), "
"lsn(%u,0x%lx)\n",
i, (uint) rec.type, (uint) rec.short_trid,
(ulong) rec.record_length, (ulong) rec_len,
(uint) len,
(uint) ref1.file_no, (ulong) ref1.rec_offset,
(uint) ref2.file_no, (ulong) ref2.rec_offset,
(uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
goto err;
}
if (read_and_check_content(&rec, long_buffer, 14))
{
fprintf(stderr,
"Incorrect LOGREC_UNDO_KEY_DELETE in whole rec read "
"lsn(%u,0x%lx)\n",
(uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
goto err;
}
}
len= translog_read_next_record_header(lsn_ptr, &rec, 1, &scanner);
if (len == 0)
{
fprintf(stderr, "1-%d translog_read_next_record_header failed (%d)\n",
i, errno);
goto err;
}
if (rec.lsn.file_no == CONTROL_FILE_IMPOSSIBLE_FILENO)
{
fprintf(stderr, "EOL met at the middle of iteration %u "
"instead of beginning of %u\n", i, ITERATIONS);
goto err;
}
if (rec.type !=LOGREC_LONG_TRANSACTION_ID ||
rec.short_trid != (i % 0xFFFF) ||
rec.record_length != 6 || uint4korr(rec.header) != i ||
rec.header[4] != 0 || rec.header[5] != 0xFF)
{
fprintf(stderr, "Incorrect LOGREC_LONG_TRANSACTION_ID data read(%d)\n"
"type %u, strid %u, len %u, i: %u, 4: %u 5: %u "
"lsn(%u,0x%lx)\n",
i, (uint) rec.type, (uint) rec.short_trid,
(uint) rec.record_length,
uint4korr(rec.header), (uint) rec.header[4],
(uint) rec.header[5],
(uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
goto err;
}
lsn= rec.lsn;
len= translog_read_next_record_header(lsn_ptr, &rec, 1, &scanner);
if ((rec_len= random() / (RAND_MAX / (LONG_BUFFER_SIZE + 1))) < 9)
rec_len= 9;
if (rec.type !=LOGREC_REDO_INSERT_ROW_HEAD ||
rec.short_trid != (i % 0xFFFF) ||
rec.record_length != rec_len ||
len != 9 || check_content(rec.header, len))
{
fprintf(stderr, "Incorrect LOGREC_REDO_INSERT_ROW_HEAD data read(%d)"
"type %u, strid %u, len %lu != %lu, hdr len: %u, "
"lsn(%u,0x%lx)\n",
i, (uint) rec.type, (uint) rec.short_trid,
(ulong) rec.record_length, (ulong) rec_len,
(uint) len, (uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
goto err;
}
if (read_and_check_content(&rec, long_buffer, 0))
{
fprintf(stderr,
"Incorrect LOGREC_UNDO_KEY_DELETE in whole rec read "
"lsn(%u,0x%lx)\n",
(uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
goto err;
}
}
}
rc= 1;
err:
translog_destroy();
end_pagecache(&pagecache, 1);
ma_control_file_end();
return(test(exit_status() || rc));
}

View File

@ -0,0 +1,570 @@
#include "../maria_def.h"
#include <stdio.h>
#include <errno.h>
#ifndef DBUG_OFF
static const char *default_dbug_option;
#endif
#define PCACHE_SIZE (1024*1024*10)
#define LONG_BUFFER_SIZE ((1024L*1024L*1024L) + (1024L*1024L*512))
#define MIN_REC_LENGTH (1024L*1024L + 1024L*512L + 1)
#define SHOW_DIVIDER 2
#define LOG_FILE_SIZE (1024L*1024L*1024L + 1024L*1024L*512)
#define ITERATIONS 2
/*#define ITERATIONS 63 */
/*
#define LOG_FILE_SIZE 1024L*1024L*3L
#define ITERATIONS 1600
*/
/*
#define LOG_FILE_SIZE 1024L*1024L*100L
#define ITERATIONS 65000
*/
/*
Check that the buffer filled correctly
SYNOPSIS
check_content()
ptr Pointer to the buffer
length length of the buffer
RETURN
0 - OK
1 - Error
*/
static my_bool check_content(uchar *ptr, ulong length)
{
ulong i;
uchar buff[4];
DBUG_ENTER("check_content");
for (i= 0; i < length; i++)
{
if (i % 4 == 0)
int4store(buff, (i >> 2));
if (ptr[i] != buff[i % 4])
{
fprintf(stderr, "Byte # %lu is %x instead of %x",
i, (uint) ptr[i], (uint) buff[i % 4]);
DBUG_DUMP("mem", ptr +(ulong) (i > 16 ? i - 16 : 0),
(i > 16 ? 16 : i) + (i + 16 < length ? 16 : length - i));
DBUG_RETURN(1);
}
}
DBUG_RETURN(0);
}
/*
Read whole record content, and check content (put with offset)
SYNOPSIS
read_and_check_content()
rec The record header buffer
buffer The buffer to read the record in
skip Skip this number of bytes ot the record content
RETURN
0 - OK
1 - Error
*/
static my_bool read_and_check_content(TRANSLOG_HEADER_BUFFER *rec,
uchar *buffer, uint skip)
{
int res= 0;
translog_size_t len;
DBUG_ENTER("read_and_check_content");
DBUG_ASSERT(rec->record_length < LONG_BUFFER_SIZE + 7 * 2 + 2);
if ((len= translog_read_record(&rec->lsn, 0, rec->record_length,
buffer, NULL)) != rec->record_length)
{
fprintf(stderr, "Requested %lu byte, read %lu\n",
(ulong) rec->record_length, (ulong) len);
res= 1;
}
res|= check_content(buffer + skip, rec->record_length - skip);
DBUG_RETURN(res);
}
static uint32 get_len()
{
uint32 rec_len;
do
{
rec_len= random() /
(RAND_MAX / (LONG_BUFFER_SIZE - MIN_REC_LENGTH - 1)) + MIN_REC_LENGTH;
} while (rec_len >= LONG_BUFFER_SIZE);
return rec_len;
}
int main(int argc, char *argv[])
{
uint32 i;
uint32 rec_len;
uint pagen;
uchar long_tr_id[6];
uchar lsn_buff[23]=
{
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55
};
uchar *long_buffer= malloc(LONG_BUFFER_SIZE + 7 * 2 + 2);
PAGECACHE pagecache;
LSN lsn, lsn_base, first_lsn, *lsn_ptr;
TRANSLOG_HEADER_BUFFER rec;
struct st_translog_scanner_data scanner;
int rc;
MY_INIT(argv[0]);
bzero(&pagecache, sizeof(pagecache));
maria_data_root= ".";
{
uchar buff[4];
for (i= 0; i < (LONG_BUFFER_SIZE + 7 * 2 + 2); i++)
{
if (i % 4 == 0)
int4store(buff, (i >> 2));
long_buffer[i]= buff[i % 4];
}
}
bzero(long_tr_id, 6);
#ifndef DBUG_OFF
#if defined(__WIN__)
default_dbug_option= "d:t:i:O,\\ma_test_loghandler.trace";
#else
default_dbug_option= "d:t:i:o,/tmp/ma_test_loghandler.trace";
#endif
if (argc > 1)
{
DBUG_SET(default_dbug_option);
DBUG_SET_INITIAL(default_dbug_option);
}
#endif
if (ma_control_file_create_or_open())
{
fprintf(stderr, "Can't init control file (%d)\n", errno);
exit(1);
}
if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
TRANSLOG_PAGE_SIZE)) == 0)
{
fprintf(stderr, "Got error: init_pagecache() (errno: %d)\n", errno);
exit(1);
}
if (translog_init(".", LOG_FILE_SIZE, 50112, 0, &pagecache, 0))
{
fprintf(stderr, "Can't init loghandler (%d)\n", errno);
translog_destroy();
exit(1);
}
srandom(122334817L);
long_tr_id[5]= 0xff;
int4store(long_tr_id, 0);
if (translog_write_record(&lsn,
LOGREC_LONG_TRANSACTION_ID,
0, NULL, 6, long_tr_id, 0))
{
fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
translog_destroy();
exit(1);
}
lsn_base= first_lsn= lsn;
for (i= 1; i < ITERATIONS; i++)
{
if (i % SHOW_DIVIDER == 0)
printf("write %d\n", i);
if (i % 2)
{
lsn7store(lsn_buff, &lsn_base);
if (translog_write_record(&lsn,
LOGREC_CLR_END,
(i % 0xFFFF), NULL, 7, lsn_buff, 0))
{
fprintf(stderr, "1 Can't write reference before record #%lu\n",
(ulong) i);
translog_destroy();
exit(1);
}
lsn7store(lsn_buff, &lsn_base);
rec_len= get_len();
if (translog_write_record(&lsn,
LOGREC_UNDO_KEY_INSERT,
(i % 0xFFFF),
NULL, 7, lsn_buff, rec_len, long_buffer, 0))
{
fprintf(stderr, "1 Can't write var reference before record #%lu\n",
(ulong) i);
translog_destroy();
exit(1);
}
}
else
{
lsn7store(lsn_buff, &lsn_base);
lsn7store(lsn_buff + 7, &first_lsn);
if (translog_write_record(&lsn,
LOGREC_UNDO_ROW_DELETE,
(i % 0xFFFF), NULL, 23, lsn_buff, 0))
{
fprintf(stderr, "0 Can't write reference before record #%lu\n",
(ulong) i);
translog_destroy();
exit(1);
}
lsn7store(lsn_buff, &lsn_base);
lsn7store(lsn_buff + 7, &first_lsn);
rec_len= get_len();
if (translog_write_record(&lsn,
LOGREC_UNDO_KEY_DELETE,
(i % 0xFFFF),
NULL, 14, lsn_buff, rec_len, long_buffer, 0))
{
fprintf(stderr, "0 Can't write var reference before record #%lu\n",
(ulong) i);
translog_destroy();
exit(1);
}
}
int4store(long_tr_id, i);
if (translog_write_record(&lsn,
LOGREC_LONG_TRANSACTION_ID,
(i % 0xFFFF), NULL, 6, long_tr_id, 0))
{
fprintf(stderr, "Can't write record #%lu\n", (ulong) i);
translog_destroy();
exit(1);
}
lsn_base= lsn;
rec_len= get_len();
if (translog_write_record(&lsn,
LOGREC_REDO_INSERT_ROW_HEAD,
(i % 0xFFFF), NULL, rec_len, long_buffer, 0))
{
fprintf(stderr, "Can't write variable record #%lu\n", (ulong) i);
translog_destroy();
exit(1);
}
}
translog_destroy();
end_pagecache(&pagecache, 1);
ma_control_file_end();
if (ma_control_file_create_or_open())
{
fprintf(stderr, "pass2: Can't init control file (%d)\n", errno);
exit(1);
}
if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
TRANSLOG_PAGE_SIZE)) == 0)
{
fprintf(stderr, "pass2: Got error: init_pagecache() (errno: %d)\n", errno);
exit(1);
}
if (translog_init(".", LOG_FILE_SIZE, 50112, 0, &pagecache, 0))
{
fprintf(stderr, "pass2: Can't init loghandler (%d)\n", errno);
translog_destroy();
exit(1);
}
srandom(122334817L);
rc= 1;
{
translog_size_t len= translog_read_record_header(&first_lsn, &rec);
if (len == 0)
{
fprintf(stderr, "translog_read_record_header failed (%d)\n", errno);
translog_free_record_header(&rec);
goto err;
}
if (rec.type !=LOGREC_LONG_TRANSACTION_ID || rec.short_trid != 0 ||
rec.record_length != 6 || uint4korr(rec.header) != 0 ||
(uint)rec.header[4] != 0 || rec.header[5] != 0xFF ||
first_lsn.file_no != rec.lsn.file_no ||
first_lsn.rec_offset != rec.lsn.rec_offset)
{
fprintf(stderr, "Incorrect LOGREC_LONG_TRANSACTION_ID data read(0)\n"
"type %u, strid %u, len %u, i: %u, 4: %u 5: %u, "
"lsn(0x%lx,0x%lx)\n",
(uint) rec.type, (uint) rec.short_trid, (uint) rec.record_length,
uint4korr(rec.header), (uint) rec.header[4], (uint) rec.header[5],
(ulong) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
translog_free_record_header(&rec);
goto err;
}
translog_free_record_header(&rec);
lsn= first_lsn;
lsn_ptr= &first_lsn;
for (i= 1;; i++)
{
if (i % SHOW_DIVIDER == 0)
printf("read %d\n", i);
len= translog_read_next_record_header(lsn_ptr, &rec, 1, &scanner);
if (len == 0)
{
fprintf(stderr, "1-%d translog_read_next_record_header failed (%d)\n",
i, errno);
translog_free_record_header(&rec);
goto err;
}
if (rec.lsn.file_no == CONTROL_FILE_IMPOSSIBLE_FILENO)
{
if (i != ITERATIONS)
{
fprintf(stderr, "EOL met at iteration %u instead of %u\n",
i, ITERATIONS);
translog_free_record_header(&rec);
goto err;
}
break;
}
lsn_ptr= NULL; /* use scanner after its
initialization */
if (i % 2)
{
LSN ref;
lsn7korr(&ref, rec.header);
if (rec.type !=LOGREC_CLR_END || rec.short_trid != (i % 0xFFFF) ||
rec.record_length != 7 || ref.file_no != lsn.file_no ||
ref.rec_offset != lsn.rec_offset)
{
fprintf(stderr, "Incorrect LOGREC_CLR_END data read(%d)"
"type %u, strid %u, len %u, ref(%u,0x%lx), lsn(%u,0x%lx)\n",
i, (uint) rec.type, (uint) rec.short_trid,
(uint) rec.record_length,
(uint) ref.file_no, (ulong) ref.rec_offset,
(uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
translog_free_record_header(&rec);
goto err;
}
}
else
{
LSN ref1, ref2;
lsn7korr(&ref1, rec.header);
lsn7korr(&ref2, rec.header + 7);
if (rec.type !=LOGREC_UNDO_ROW_DELETE ||
rec.short_trid != (i % 0xFFFF) ||
rec.record_length != 23 ||
ref1.file_no != lsn.file_no ||
ref1.rec_offset != lsn.rec_offset ||
ref2.file_no != first_lsn.file_no ||
ref2.rec_offset != first_lsn.rec_offset ||
rec.header[22] != 0x55 || rec.header[21] != 0xAA ||
rec.header[20] != 0x55 || rec.header[19] != 0xAA ||
rec.header[18] != 0x55 || rec.header[17] != 0xAA ||
rec.header[16] != 0x55 || rec.header[15] != 0xAA ||
rec.header[14] != 0x55)
{
fprintf(stderr, "Incorrect LOGREC_UNDO_ROW_DELETE data read(%d)"
"type %u, strid %u, len %u, ref1(%u,0x%lx), "
"ref2(%u,0x%lx) %x%x%x%x%x%x%x%x%x "
"lsn(%u,0x%lx)\n",
i, (uint) rec.type, (uint) rec.short_trid,
(uint) rec.record_length,
(uint) ref1.file_no, (ulong) ref1.rec_offset,
(uint) ref2.file_no, (ulong) ref2.rec_offset,
(uint) rec.header[14], (uint) rec.header[15],
(uint) rec.header[16], (uint) rec.header[17],
(uint) rec.header[18], (uint) rec.header[19],
(uint) rec.header[20], (uint) rec.header[21],
(uint) rec.header[22],
(uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
translog_free_record_header(&rec);
goto err;
}
}
translog_free_record_header(&rec);
len= translog_read_next_record_header(lsn_ptr, &rec, 1, &scanner);
if (len == 0)
{
fprintf(stderr, "1-%d translog_read_next_record_header (var) "
"failed (%d)\n", i, errno);
goto err;
}
if (rec.lsn.file_no == CONTROL_FILE_IMPOSSIBLE_FILENO)
{
fprintf(stderr, "EOL met at the middle of iteration (first var) %u "
"instead of beginning of %u\n", i, ITERATIONS);
goto err;
}
if (i % 2)
{
LSN ref;
lsn7korr(&ref, rec.header);
rec_len= get_len();
if (rec.type !=LOGREC_UNDO_KEY_INSERT ||
rec.short_trid != (i % 0xFFFF) ||
rec.record_length != rec_len + 7 ||
len != 12 || ref.file_no != lsn.file_no ||
ref.rec_offset != lsn.rec_offset ||
check_content(rec.header + 7, len - 7))
{
fprintf(stderr, "Incorrect LOGREC_UNDO_KEY_INSERT data read(%d)"
"type %u (%d), strid %u (%d), len %lu, %lu + 7 (%d), "
"hdr len: %u (%d), "
"ref(%u,0x%lx), lsn(%u,0x%lx) (%d), content: %d\n",
i, (uint) rec.type,
rec.type !=LOGREC_UNDO_KEY_INSERT,
(uint) rec.short_trid,
rec.short_trid != (i % 0xFFFF),
(ulong) rec.record_length, (ulong) rec_len,
rec.record_length != rec_len + 7,
(uint) len,
len != 12,
(uint) ref.file_no, (ulong) ref.rec_offset,
(uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset,
(ref.file_no != lsn.file_no ||
ref.rec_offset != lsn.rec_offset),
check_content(rec.header + 7, len - 7));
translog_free_record_header(&rec);
goto err;
}
if (read_and_check_content(&rec, long_buffer, 7))
{
fprintf(stderr,
"Incorrect LOGREC_UNDO_KEY_INSERT in whole rec read "
"lsn(%u,0x%lx)\n",
(uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
translog_free_record_header(&rec);
goto err;
}
}
else
{
LSN ref1, ref2;
lsn7korr(&ref1, rec.header);
lsn7korr(&ref2, rec.header + 7);
rec_len= get_len();
if (rec.type !=LOGREC_UNDO_KEY_DELETE ||
rec.short_trid != (i % 0xFFFF) ||
rec.record_length != rec_len + 14 ||
len != 19 ||
ref1.file_no != lsn.file_no ||
ref1.rec_offset != lsn.rec_offset ||
ref2.file_no != first_lsn.file_no ||
ref2.rec_offset != first_lsn.rec_offset ||
check_content(rec.header + 14, len - 14))
{
fprintf(stderr, "Incorrect LOGREC_UNDO_KEY_DELETE data read(%d)"
"type %u, strid %u, len %lu != %lu + 7, hdr len: %u, "
"ref1(%u,0x%lx), ref2(%u,0x%lx), "
"lsn(%u,0x%lx)\n",
i, (uint) rec.type, (uint) rec.short_trid,
(ulong) rec.record_length, (ulong) rec_len,
(uint) len,
(uint) ref1.file_no, (ulong) ref1.rec_offset,
(uint) ref2.file_no, (ulong) ref2.rec_offset,
(uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
translog_free_record_header(&rec);
goto err;
}
if (read_and_check_content(&rec, long_buffer, 14))
{
fprintf(stderr,
"Incorrect LOGREC_UNDO_KEY_DELETE in whole rec read "
"lsn(%u,0x%lx)\n",
(uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
translog_free_record_header(&rec);
goto err;
}
}
translog_free_record_header(&rec);
len= translog_read_next_record_header(lsn_ptr, &rec, 1, &scanner);
if (len == 0)
{
fprintf(stderr, "1-%d translog_read_next_record_header failed (%d)\n",
i, errno);
translog_free_record_header(&rec);
goto err;
}
if (rec.lsn.file_no == CONTROL_FILE_IMPOSSIBLE_FILENO)
{
fprintf(stderr, "EOL met at the middle of iteration %u "
"instead of beginning of %u\n", i, ITERATIONS);
translog_free_record_header(&rec);
goto err;
}
if (rec.type !=LOGREC_LONG_TRANSACTION_ID ||
rec.short_trid != (i % 0xFFFF) ||
rec.record_length != 6 || uint4korr(rec.header) != i ||
rec.header[4] != 0 || rec.header[5] != 0xFF)
{
fprintf(stderr, "Incorrect LOGREC_LONG_TRANSACTION_ID data read(%d)\n"
"type %u, strid %u, len %u, i: %u, 4: %u 5: %u "
"lsn(%u,0x%lx)\n",
i, (uint) rec.type, (uint) rec.short_trid,
(uint) rec.record_length,
uint4korr(rec.header), (uint) rec.header[4],
(uint) rec.header[5],
(uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
translog_free_record_header(&rec);
goto err;
}
translog_free_record_header(&rec);
lsn= rec.lsn;
len= translog_read_next_record_header(lsn_ptr, &rec, 1, &scanner);
rec_len= get_len();
if (rec.type !=LOGREC_REDO_INSERT_ROW_HEAD ||
rec.short_trid != (i % 0xFFFF) ||
rec.record_length != rec_len ||
len != 9 || check_content(rec.header, len))
{
fprintf(stderr, "Incorrect LOGREC_REDO_INSERT_ROW_HEAD data read(%d)"
"type %u, strid %u, len %lu != %lu, hdr len: %u, "
"lsn(%u,0x%lx)\n",
i, (uint) rec.type, (uint) rec.short_trid,
(ulong) rec.record_length, (ulong) rec_len,
(uint) len, (uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
translog_free_record_header(&rec);
goto err;
}
if (read_and_check_content(&rec, long_buffer, 0))
{
fprintf(stderr,
"Incorrect LOGREC_UNDO_KEY_DELETE in whole rec read "
"lsn(%u,0x%lx)\n",
(uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
translog_free_record_header(&rec);
goto err;
}
}
}
rc= 0;
err:
translog_destroy();
end_pagecache(&pagecache, 1);
ma_control_file_end();
return (test(exit_status() || rc));
}

View File

@ -0,0 +1,468 @@
#include "../maria_def.h"
#include <stdio.h>
#include <errno.h>
#ifndef DBUG_OFF
static const char *default_dbug_option;
#endif
#define PCACHE_SIZE (1024*1024*10)
/*#define LOG_FLAGS TRANSLOG_SECTOR_PROTECTION | TRANSLOG_PAGE_CRC */
#define LOG_FLAGS 0
/*#define LONG_BUFFER_SIZE (1024L*1024L*1024L + 1024L*1024L*512)*/
#define LONG_BUFFER_SIZE (1024L*1024L*1024L)
#define MIN_REC_LENGTH 30
#define SHOW_DIVIDER 10
#define LOG_FILE_SIZE (1024L*1024L*1024L + 1024L*1024L*512)
#define ITERATIONS 3
#define WRITERS 3
static uint number_of_writers= WRITERS;
static pthread_cond_t COND_thread_count;
static pthread_mutex_t LOCK_thread_count;
static uint thread_count;
static ulong lens[WRITERS][ITERATIONS];
static LSN lsns1[WRITERS][ITERATIONS];
static LSN lsns2[WRITERS][ITERATIONS];
static uchar *long_buffer;
/*
Get pseudo-random length of the field in
limits [MIN_REC_LENGTH..LONG_BUFFER_SIZE]
SYNOPSYS
get_len()
RETURN
length - length >= 0 length <= LONG_BUFFER_SIZE
*/
static uint32 get_len()
{
uint32 rec_len;
do
{
rec_len= random() /
(RAND_MAX / (LONG_BUFFER_SIZE - MIN_REC_LENGTH - 1)) + MIN_REC_LENGTH;
} while (rec_len >= LONG_BUFFER_SIZE);
return rec_len;
}
/*
Check that the buffer filled correctly
SYNOPSIS
check_content()
ptr Pointer to the buffer
length length of the buffer
RETURN
0 - OK
1 - Error
*/
static my_bool check_content(uchar *ptr, ulong length)
{
ulong i;
for (i= 0; i < length; i++)
{
if (ptr[i] != (i & 0xFF))
{
fprintf(stderr, "Byte # %lu is %x instead of %x",
i, (uint) ptr[i], (uint) (i & 0xFF));
return 1;
}
}
return 0;
}
/*
Read whole record content, and check content (put with offset)
SYNOPSIS
read_and_check_content()
rec The record header buffer
buffer The buffer to read the record in
skip Skip this number of bytes ot the record content
RETURN
0 - OK
1 - Error
*/
static my_bool read_and_check_content(TRANSLOG_HEADER_BUFFER *rec,
uchar *buffer, uint skip)
{
int res= 0;
translog_size_t len;
DBUG_ENTER("read_and_check_content");
DBUG_ASSERT(rec->record_length < LONG_BUFFER_SIZE + 7 * 2 + 2);
if ((len= translog_read_record(&rec->lsn, 0, rec->record_length,
buffer, NULL)) != rec->record_length)
{
fprintf(stderr, "Requested %lu byte, read %lu\n",
(ulong) rec->record_length, (ulong) len);
res= 1;
}
res|= check_content(buffer + skip, rec->record_length - skip);
DBUG_RETURN(res);
}
void writer(int num)
{
LSN lsn;
uchar long_tr_id[6];
uint i;
DBUG_ENTER("writer");
for (i= 0; i < ITERATIONS; i++)
{
uint len= get_len();
lens[num][i]= len;
int2store(long_tr_id, num);
int4store(long_tr_id + 2, i);
if (translog_write_record(&lsn,
LOGREC_LONG_TRANSACTION_ID,
num, NULL, 6, long_tr_id, 0))
{
fprintf(stderr, "Can't write LOGREC_LONG_TRANSACTION_ID record #%lu "
"thread %i\n", (ulong) i, num);
translog_destroy();
return;
}
lsns1[num][i]= lsn;
if (translog_write_record(&lsn,
LOGREC_REDO_INSERT_ROW_HEAD,
num, NULL, len, long_buffer, 0))
{
fprintf(stderr, "Can't write variable record #%lu\n", (ulong) i);
translog_destroy();
return;
}
lsns2[num][i]= lsn;
DBUG_PRINT("info", ("thread: %u, iteration: %u, len: %lu, "
"lsn1 (%lu,0x%lx) lsn2 (%lu,0x%lx)",
num, i, (ulong) lens[num][i],
(ulong) lsns1[num][i].file_no,
(ulong) lsns1[num][i].rec_offset,
(ulong) lsns2[num][i].file_no,
(ulong) lsns2[num][i].rec_offset));
printf("thread: %u, iteration: %u, len: %lu, "
"lsn1 (%lu,0x%lx) lsn2 (%lu,0x%lx)\n",
num, i, (ulong) lens[num][i],
(ulong) lsns1[num][i].file_no,
(ulong) lsns1[num][i].rec_offset,
(ulong) lsns2[num][i].file_no, (ulong) lsns2[num][i].rec_offset);
}
DBUG_VOID_RETURN;
}
static void *test_thread_writer(void *arg)
{
int param= *((int*) arg);
my_thread_init();
DBUG_ENTER("test_writer");
DBUG_PRINT("enter", ("param: %d", param));
writer(param);
DBUG_PRINT("info", ("Thread %s ended\n", my_thread_name()));
pthread_mutex_lock(&LOCK_thread_count);
thread_count--;
VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are
ready */
pthread_mutex_unlock(&LOCK_thread_count);
free((gptr) arg);
my_thread_end();
DBUG_RETURN(0);
}
int main(int argc, char **argv __attribute__ ((unused)))
{
uint32 i;
uint pagen;
PAGECACHE pagecache;
LSN first_lsn, *lsn_ptr;
TRANSLOG_HEADER_BUFFER rec;
struct st_translog_scanner_data scanner;
pthread_t tid;
pthread_attr_t thr_attr;
int *param, error;
int rc;
bzero(&pagecache, sizeof(pagecache));
maria_data_root= ".";
long_buffer= malloc(LONG_BUFFER_SIZE + 7 * 2 + 2);
if (long_buffer == 0)
{
fprintf(stderr, "End of memory\n");
exit(1);
}
for (i= 0; i < (LONG_BUFFER_SIZE + 7 * 2 + 2); i++)
long_buffer[i]= (i & 0xFF);
MY_INIT(argv[0]);
#ifndef DBUG_OFF
#if defined(__WIN__)
default_dbug_option= "d:t:i:O,\\ma_test_loghandler.trace";
#else
default_dbug_option= "d:t:i:o,/tmp/ma_test_loghandler.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()));
if ((error= pthread_cond_init(&COND_thread_count, NULL)))
{
fprintf(stderr, "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)))
{
fprintf(stderr, "LOCK_thread_count: %d from pthread_cond_init "
"(errno: %d)\n", error, errno);
exit(1);
}
if ((error= pthread_attr_init(&thr_attr)))
{
fprintf(stderr, "Got error: %d from pthread_attr_init "
"(errno: %d)\n", error, errno);
exit(1);
}
if ((error= pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED)))
{
fprintf(stderr,
"Got error: %d from pthread_attr_setdetachstate (errno: %d)\n",
error, errno);
exit(1);
}
#ifndef pthread_attr_setstacksize /* void return value */
if ((error= pthread_attr_setstacksize(&thr_attr, 65536L)))
{
fprintf(stderr, "Got error: %d from pthread_attr_setstacksize "
"(errno: %d)\n", error, errno);
exit(1);
}
#endif
#ifdef HAVE_THR_SETCONCURRENCY
VOID(thr_setconcurrency(2));
#endif
my_thread_global_init();
if (ma_control_file_create_or_open())
{
fprintf(stderr, "Can't init control file (%d)\n", errno);
exit(1);
}
if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
TRANSLOG_PAGE_SIZE)) == 0)
{
fprintf(stderr, "Got error: init_pagecache() (errno: %d)\n", errno);
exit(1);
}
if (translog_init(".", LOG_FILE_SIZE, 50112, 0, &pagecache, LOG_FLAGS))
{
fprintf(stderr, "Can't init loghandler (%d)\n", errno);
translog_destroy();
exit(1);
}
srandom(122334817L);
{
uchar long_tr_id[6]=
{
0x11, 0x22, 0x33, 0x44, 0x55, 0x66
};
if (translog_write_record(&first_lsn,
LOGREC_LONG_TRANSACTION_ID,
0, NULL, 6, long_tr_id, 0))
{
fprintf(stderr, "Can't write the first record\n");
translog_destroy();
exit(1);
}
}
if ((error= pthread_mutex_lock(&LOCK_thread_count)))
{
fprintf(stderr, "LOCK_thread_count: %d from pthread_mutex_lock "
"(errno: %d)\n", error, errno);
exit(1);
}
while (number_of_writers != 0)
{
param= (int*) malloc(sizeof(int));
*param= number_of_writers - 1;
if ((error= pthread_create(&tid, &thr_attr, test_thread_writer,
(void*) param)))
{
fprintf(stderr, "Got error: %d from pthread_create (errno: %d)\n",
error, errno);
exit(1);
}
thread_count++;
number_of_writers--;
}
DBUG_PRINT("info", ("All threads are started"));
pthread_mutex_unlock(&LOCK_thread_count);
pthread_attr_destroy(&thr_attr);
/* wait finishing */
if ((error= pthread_mutex_lock(&LOCK_thread_count)))
fprintf(stderr, "LOCK_thread_count: %d from pthread_mutex_lock\n", error);
while (thread_count)
{
if ((error= pthread_cond_wait(&COND_thread_count, &LOCK_thread_count)))
fprintf(stderr, "COND_thread_count: %d from pthread_cond_wait\n", error);
}
if ((error= pthread_mutex_unlock(&LOCK_thread_count)))
fprintf(stderr, "LOCK_thread_count: %d from pthread_mutex_unlock\n", error);
DBUG_PRINT("info", ("All threads ended"));
/* Find last LSN and flush up to it (all our log) */
{
LSN max=
{
0, 0
};
for (i= 0; i < WRITERS; i++)
{
if (cmp_translog_addr(lsns2[i][ITERATIONS - 1], max) > 0)
max= lsns2[i][ITERATIONS - 1];
}
DBUG_PRINT("info", ("first lsn: (%lu,0x%lx), max lsn: (%lu,0x%lx)",
(ulong) first_lsn.file_no,
(ulong) first_lsn.rec_offset,
(ulong) max.file_no, (ulong) max.rec_offset));
translog_flush(&max);
}
rc= 1;
{
uint indeces[WRITERS];
uint index, len, stage;
bzero(indeces, sizeof(uint) * WRITERS);
bzero(indeces, sizeof(indeces));
lsn_ptr= &first_lsn;
for (i= 0;; i++)
{
len= translog_read_next_record_header(lsn_ptr, &rec, 1, &scanner);
lsn_ptr= NULL;
if (len == 0)
{
fprintf(stderr, "1-%d translog_read_next_record_header failed (%d)\n",
i, errno);
translog_free_record_header(&rec);
goto err;
}
if (rec.lsn.file_no == CONTROL_FILE_IMPOSSIBLE_FILENO)
{
if (i != WRITERS * ITERATIONS * 2)
{
fprintf(stderr, "EOL met at iteration %u instead of %u\n",
i, ITERATIONS * WRITERS * 2);
translog_free_record_header(&rec);
goto err;
}
break;
}
index= indeces[rec.short_trid] / 2;
stage= indeces[rec.short_trid] % 2;
printf("read(%d) thread: %d, iteration %d, stage %d\n",
i, (uint) rec.short_trid, index, stage);
if (stage == 0)
{
if (rec.type !=LOGREC_LONG_TRANSACTION_ID ||
rec.record_length != 6 ||
uint2korr(rec.header) != rec.short_trid ||
index != uint4korr(rec.header + 2) ||
cmp_translog_addr(lsns1[rec.short_trid][index], rec.lsn) != 0)
{
fprintf(stderr, "Incorrect LOGREC_LONG_TRANSACTION_ID data read(%d)\n"
"type %u, strid %u %u, len %u, i: %u %u, "
"lsn(%lu,0x%lx) (%lu,0x%lx)\n",
i, (uint) rec.type,
(uint) rec.short_trid, (uint) uint2korr(rec.header),
(uint) rec.record_length,
(uint) index, (uint) uint4korr(rec.header + 2),
(ulong) rec.lsn.file_no, (ulong) rec.lsn.rec_offset,
(ulong) lsns1[rec.short_trid][index].file_no,
(ulong) lsns1[rec.short_trid][index].rec_offset);
translog_free_record_header(&rec);
goto err;
}
}
else
{
if (rec.type !=LOGREC_REDO_INSERT_ROW_HEAD ||
len != 9 ||
rec.record_length != lens[rec.short_trid][index] ||
cmp_translog_addr(lsns2[rec.short_trid][index], rec.lsn) != 0 ||
check_content(rec.header, len))
{
fprintf(stderr,
"Incorrect LOGREC_REDO_INSERT_ROW_HEAD data read(%d) "
" thread: %d, iteration %d, stage %d\n"
"type %u (%d), len %u, length %lu %lu (%d) "
"lsn(%lu,0x%lx) (%lu,0x%lx)\n",
i, (uint) rec.short_trid, index, stage,
(uint) rec.type, (rec.type !=LOGREC_REDO_INSERT_ROW_HEAD),
(uint) len,
(ulong) rec.record_length, lens[rec.short_trid][index],
(rec.record_length != lens[rec.short_trid][index]),
(ulong) rec.lsn.file_no, (ulong) rec.lsn.rec_offset,
(ulong) lsns2[rec.short_trid][index].file_no,
(ulong) lsns2[rec.short_trid][index].rec_offset);
translog_free_record_header(&rec);
goto err;
}
if (read_and_check_content(&rec, long_buffer, 0))
{
fprintf(stderr,
"Incorrect LOGREC_REDO_INSERT_ROW_HEAD in whole rec read "
"lsn(%u,0x%lx)\n",
(uint) rec.lsn.file_no, (ulong) rec.lsn.rec_offset);
translog_free_record_header(&rec);
goto err;
}
}
translog_free_record_header(&rec);
indeces[rec.short_trid]++;
}
}
rc= 0;
err:
translog_destroy();
end_pagecache(&pagecache, 1);
ma_control_file_end();
DBUG_RETURN(test(exit_status() || rc));
}

View File

@ -0,0 +1,140 @@
#include "../maria_def.h"
#include <stdio.h>
#include <errno.h>
#ifndef DBUG_OFF
static const char *default_dbug_option;
#endif
#define PCACHE_SIZE (1024*1024*10)
#define PCACHE_PAGE TRANSLOG_PAGE_SIZE
#define LOG_FILE_SIZE (1024L*1024L*1024L + 1024L*1024L*512)
#define LOG_FLAGS 0
static char *first_translog_file= (char*)"maria_log.00000001";
static char *file1_name= (char*)"page_cache_test_file_1";
static PAGECACHE_FILE file1;
int main(int argc, char *argv[])
{
uint pagen;
uchar long_tr_id[6];
PAGECACHE pagecache;
LSN lsn;
MY_STAT st, *stat;
MY_INIT(argv[0]);
bzero(&pagecache, sizeof(pagecache));
maria_data_root= ".";
/* be sure that we have no logs in the directory*/
if (my_stat(CONTROL_FILE_BASE_NAME, &st, MYF(0)))
my_delete(CONTROL_FILE_BASE_NAME, MYF(0));
if (my_stat(first_translog_file, &st, MYF(0)))
my_delete(first_translog_file, MYF(0));
bzero(long_tr_id, 6);
#ifndef DBUG_OFF
#if defined(__WIN__)
default_dbug_option= "d:t:i:O,\\ma_test_loghandler_pagecache.trace";
#else
default_dbug_option= "d:t:i:o,/tmp/ma_test_loghandler_pagecache.trace";
#endif
if (argc > 1)
{
DBUG_SET(default_dbug_option);
DBUG_SET_INITIAL(default_dbug_option);
}
#endif
if (ma_control_file_create_or_open())
{
fprintf(stderr, "Can't init control file (%d)\n", errno);
exit(1);
}
if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
PCACHE_PAGE)) == 0)
{
fprintf(stderr, "Got error: init_pagecache() (errno: %d)\n", errno);
exit(1);
}
if (translog_init(".", LOG_FILE_SIZE, 50112, 0, &pagecache, LOG_FLAGS))
{
fprintf(stderr, "Can't init loghandler (%d)\n", errno);
translog_destroy();
exit(1);
}
if ((stat= my_stat(first_translog_file, &st, MYF(0))) == 0)
{
fprintf(stderr, "There is no %s (%d)\n", first_translog_file, errno);
exit(1);
}
if (st.st_size != TRANSLOG_PAGE_SIZE)
{
fprintf(stderr,
"incorrect initial size of %s: %ld instead of %ld\n",
first_translog_file, (long)st.st_size, (long)TRANSLOG_PAGE_SIZE);
exit(1);
}
int4store(long_tr_id, 0);
if (translog_write_record(&lsn,
LOGREC_LONG_TRANSACTION_ID,
0, NULL, 6, long_tr_id, 0))
{
fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
translog_destroy();
exit(1);
}
if ((file1.file= my_open(file1_name,
O_CREAT | O_TRUNC | O_RDWR, MYF(0))) == -1)
{
fprintf(stderr, "Got error during file1 creation from open() (errno: %d)\n",
errno);
exit(1);
}
if (chmod(file1_name, S_IRWXU | S_IRWXG | S_IRWXO) != 0)
{
fprintf(stderr, "Got error during file1 chmod() (errno: %d)\n",
errno);
exit(1);
}
{
uchar page[PCACHE_PAGE];
bzero(page, PCACHE_PAGE);
#define PAGE_LSN_OFFSET 0
lsn7store(page + PAGE_LSN_OFFSET, &lsn);
pagecache_write(&pagecache, &file1, 0, 3, (char*)page,
PAGECACHE_LSN_PAGE,
PAGECACHE_LOCK_LEFT_UNLOCKED,
PAGECACHE_PIN_LEFT_UNPINNED,
PAGECACHE_WRITE_DELAY,
0);
flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE);
}
if ((stat= my_stat(first_translog_file, &st, MYF(0))) == 0)
{
fprintf(stderr, "can't stat %s (%d)\n", first_translog_file, errno);
exit(1);
}
if (st.st_size != TRANSLOG_PAGE_SIZE * 2)
{
fprintf(stderr,
"incorrect initial size of %s: %ld instead of %ld\n",
first_translog_file,
(long)st.st_size, (long)(TRANSLOG_PAGE_SIZE * 2));
exit(1);
}
translog_destroy();
end_pagecache(&pagecache, 1);
ma_control_file_end();
my_delete(CONTROL_FILE_BASE_NAME, MYF(0));
my_delete(first_translog_file, MYF(0));
my_delete(file1_name, MYF(0));
exit(0);
}

View File

@ -57,6 +57,29 @@ static uint flush_divider= 1000;
#endif /*TEST_HIGH_CONCURENCY*/
/*
Get pseudo-random length of the field in (0;limit)
SYNOPSYS
get_len()
limit limit for generated value
RETURN
length where length >= 0 & length < limit
*/
static uint get_len(uint limit)
{
uint32 rec_len;
do
{
rec_len= random() /
(RAND_MAX / limit);
} while (rec_len >= limit || rec_len == 0);
return rec_len;
}
/* check page consistency */
uint check_page(uchar *buff, ulong offset, int page_locked, int page_no,
int tag)
@ -70,7 +93,7 @@ uint check_page(uchar *buff, ulong offset, int page_locked, int page_no,
{
uint len= *((uint *)(buff + end));
uint j;
end+= sizeof(uint)+ sizeof(uint);
end+= sizeof(uint) + sizeof(uint);
if (len + end > PAGE_SIZE)
{
diag("incorrect field header #%u by offset %lu\n", i, offset + end + j);
@ -178,7 +201,7 @@ void reader(int num)
for (i= 0; i < number_of_tests; i++)
{
uint page= rand()/(RAND_MAX/number_of_pages);
uint page= get_len(number_of_pages);
pagecache_read(&pagecache, &file1, page, 3, (char*)buffr,
PAGECACHE_PLAIN_PAGE,
PAGECACHE_LOCK_LEFT_UNLOCKED,
@ -201,13 +224,13 @@ void writer(int num)
for (i= 0; i < number_of_tests; i++)
{
uint end;
uint page= rand()/(RAND_MAX/number_of_pages);
uint page= get_len(number_of_pages);
pagecache_read(&pagecache, &file1, page, 3, (char*)buffr,
PAGECACHE_PLAIN_PAGE,
PAGECACHE_LOCK_WRITE,
0);
end= check_page(buffr, page * PAGE_SIZE, 1, page, num);
put_rec(buffr, end, rand()/(RAND_MAX/record_length_limit), num);
put_rec(buffr, end, get_len(record_length_limit), num);
pagecache_write(&pagecache, &file1, page, 3, (char*)buffr,
PAGECACHE_PLAIN_PAGE,
PAGECACHE_LOCK_WRITE_UNLOCK,
@ -348,7 +371,7 @@ int main(int argc, char **argv __attribute__((unused)))
if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
PAGE_SIZE, 0)) == 0)
PAGE_SIZE)) == 0)
{
fprintf(stderr,"Got error: init_pagecache() (errno: %d)\n",
errno);

View File

@ -346,7 +346,7 @@ int simple_big_test()
unsigned char *buffw= (unsigned char *)malloc(PAGE_SIZE);
unsigned char *buffr= (unsigned char *)malloc(PAGE_SIZE);
struct file_desc *desc=
(struct file_desc *)malloc((PCACHE_SIZE/(PAGE_SIZE/2)) *
(struct file_desc *)malloc((PCACHE_SIZE/(PAGE_SIZE/2) + 1) *
sizeof(struct file_desc));
int res, i;
DBUG_ENTER("simple_big_test");
@ -363,6 +363,8 @@ int simple_big_test()
PAGECACHE_WRITE_DELAY,
0);
}
desc[i].length= 0;
desc[i].content= NULL;
ok(1, "Simple big file write");
/* check written pages sequentally read */
for (i= 0; i < PCACHE_SIZE/(PAGE_SIZE/2); i++)
@ -528,7 +530,7 @@ int main(int argc, char **argv __attribute__((unused)))
plan(12);
if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
PAGE_SIZE, 0)) == 0)
PAGE_SIZE)) == 0)
{
fprintf(stderr,"Got error: init_pagecache() (errno: %d)\n",
errno);

View File

@ -7,45 +7,4 @@ LDADD = $(top_builddir)/unittest/mytap/libmytap.a \
$(top_builddir)/dbug/libdbug.a \
$(top_builddir)/strings/libmystrings.a
noinst_PROGRAMS = bitmap-t base64-t my_atomic-t \
mf_pagecache_single_1k-t mf_pagecache_single_8k-t \
mf_pagecache_single_64k-t \
mf_pagecache_consist_1k-t mf_pagecache_consist_64k-t \
mf_pagecache_consist_1kHC-t mf_pagecache_consist_64kHC-t \
mf_pagecache_consist_1kRD-t mf_pagecache_consist_64kRD-t \
mf_pagecache_consist_1kWR-t mf_pagecache_consist_64kWR-t
# tests for mysys/mf_pagecache.c
mf_pagecache_single_src = mf_pagecache_single.c $(top_srcdir)/mysys/mf_pagecache.c test_file.c
mf_pagecache_consist_src = mf_pagecache_consist.c $(top_srcdir)/mysys/mf_pagecache.c test_file.c
mf_pagecache_common_cppflags = -DEXTRA_DEBUG -DPAGECACHE_DEBUG -DMAIN
mf_pagecache_single_1k_t_SOURCES = $(mf_pagecache_single_src)
mf_pagecache_single_8k_t_SOURCES = $(mf_pagecache_single_src)
mf_pagecache_single_64k_t_SOURCES = $(mf_pagecache_single_src)
mf_pagecache_single_1k_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=1024
mf_pagecache_single_8k_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=8192
mf_pagecache_single_64k_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=65536
mf_pagecache_consist_1k_t_SOURCES = $(mf_pagecache_consist_src)
mf_pagecache_consist_1k_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=1024
mf_pagecache_consist_64k_t_SOURCES = $(mf_pagecache_consist_src)
mf_pagecache_consist_64k_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=65536
mf_pagecache_consist_1kHC_t_SOURCES = $(mf_pagecache_consist_src)
mf_pagecache_consist_1kHC_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=1024 -DTEST_HIGH_CONCURENCY
mf_pagecache_consist_64kHC_t_SOURCES = $(mf_pagecache_consist_src)
mf_pagecache_consist_64kHC_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=65536 -DTEST_HIGH_CONCURENCY
mf_pagecache_consist_1kRD_t_SOURCES = $(mf_pagecache_consist_src)
mf_pagecache_consist_1kRD_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=1024 -DTEST_READERS
mf_pagecache_consist_64kRD_t_SOURCES = $(mf_pagecache_consist_src)
mf_pagecache_consist_64kRD_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=65536 -DTEST_READERS
mf_pagecache_consist_1kWR_t_SOURCES = $(mf_pagecache_consist_src)
mf_pagecache_consist_1kWR_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=1024 -DTEST_WRITERS
mf_pagecache_consist_64kWR_t_SOURCES = $(mf_pagecache_consist_src)
mf_pagecache_consist_64kWR_t_CPPFLAGS = $(mf_pagecache_common_cppflags) -DPAGE_SIZE=65536 -DTEST_WRITERS
CLEANFILES = my_pagecache_debug.log page_cache_test_file_1
noinst_PROGRAMS = bitmap-t base64-t my_atomic-t