Commit 02540092 authored by unknown's avatar unknown

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''
parent 5c796096
......@@ -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);
......
#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
......@@ -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 \
......
......@@ -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
}
......
......@@ -26,7 +26,7 @@
When a new block is required it is first tried to pop one from the stack.
If the stack is empty, it is tried to get a never-used block from the pool.
If this is empty too, then a block is taken from the LRU ring, flushing it
to disk, if necessary. This is handled in find_key_block().
to disk, if necessary. This is handled in find_block().
With the new free list, the blocks can have three temperatures:
hot, warm and cold (which is free). This is remembered in the block header
by the enum BLOCK_TEMPERATURE temperature variable. Remembering the
......@@ -91,13 +91,16 @@
/*
In key cache we have external raw locking here we use
SERIALIZED_READ_FROM_CACHE to avoid problem of reading
not consistent data from te page
not consistent data from the page.
(keycache functions (key_cache_read(), key_cache_insert() and
key_cache_write()) rely on external MyISAM lock, we don't)
*/
#define SERIALIZED_READ_FROM_CACHE yes
#define BLOCK_INFO(B) \
DBUG_PRINT("info", \
("block 0x%lx, file %lu, page %lu, s %0x, hshL 0x%lx, req %u/%u", \
("block 0x%lx file %lu page %lu s %0x hshL 0x%lx req %u/%u " \
"wrlock: %c", \
(ulong)(B), \
(ulong)((B)->hash_link ? \
(B)->hash_link->file.file : \
......@@ -110,7 +113,8 @@
(uint) (B)->requests, \
(uint)((B)->hash_link ? \
(B)->hash_link->requests : \
0)))
0), \
((block->status & BLOCK_WRLOCK)?'Y':'N')))
/* TODO: put it to my_static.c */
my_bool my_disable_flush_pagecache_blocks= 0;
......@@ -138,7 +142,7 @@ typedef pthread_cond_t KEYCACHE_CONDVAR;
struct st_pagecache_page
{
PAGECACHE_FILE file; /* file to which the page belongs to */
maria_page_no_t pageno; /* number of the page in the file */
pgcache_page_no_t pageno; /* number of the page in the file */
};
/* element in the chain of a hash table bucket */
......@@ -149,7 +153,7 @@ struct st_pagecache_hash_link
struct st_pagecache_block_link
*block; /* reference to the block for the page: */
PAGECACHE_FILE file; /* from such a file */
maria_page_no_t pageno; /* this page */
pgcache_page_no_t pageno; /* this page */
uint requests; /* number of requests for the page */
};
......@@ -162,7 +166,7 @@ struct st_pagecache_hash_link
#define BLOCK_CHANGED 32 /* block buffer contains a dirty page */
#define BLOCK_WRLOCK 64 /* write locked block */
/* page status, returned by find_key_block */
/* page status, returned by find_block */
#define PAGE_READ 0
#define PAGE_TO_BE_READ 1
#define PAGE_WAIT_TO_BE_READ 2
......@@ -232,7 +236,7 @@ typedef struct st_pagecache_lock_info
node the node which should be linked
*/
void info_link(PAGECACHE_PIN_INFO **list, PAGECACHE_PIN_INFO *node)
static void info_link(PAGECACHE_PIN_INFO **list, PAGECACHE_PIN_INFO *node)
{
if ((node->next= *list))
node->next->prev= &(node->next);
......@@ -249,7 +253,7 @@ void info_link(PAGECACHE_PIN_INFO **list, PAGECACHE_PIN_INFO *node)
node the node which should be unlinked
*/
void info_unlink(PAGECACHE_PIN_INFO *node)
static void info_unlink(PAGECACHE_PIN_INFO *node)
{
if ((*node->prev= node->next))
node->next->prev= node->prev;
......@@ -271,7 +275,7 @@ void info_unlink(PAGECACHE_PIN_INFO *node)
pointer to the information node of the thread in the list
*/
PAGECACHE_PIN_INFO *info_find(PAGECACHE_PIN_INFO *list,
static PAGECACHE_PIN_INFO *info_find(PAGECACHE_PIN_INFO *list,
struct st_my_thread_var *thread)
{
register PAGECACHE_PIN_INFO *i= list;
......@@ -291,7 +295,7 @@ struct st_pagecache_block_link
*next_changed, **prev_changed; /* for lists of file dirty/clean blocks */
struct st_pagecache_hash_link
*hash_link; /* backward ptr to referring hash_link */
PAGECACHE_WQUEUE
WQUEUE
wqueue[COND_SIZE]; /* queues on waiting requests for new/old pages */
uint requests; /* number of requests for the block */
byte *buffer; /* buffer for the block page */
......@@ -310,7 +314,7 @@ struct st_pagecache_block_link
#ifdef PAGECACHE_DEBUG
/* debug checks */
my_bool info_check_pin(PAGECACHE_BLOCK_LINK *block,
static my_bool info_check_pin(PAGECACHE_BLOCK_LINK *block,
enum pagecache_page_pin mode)
{
struct st_my_thread_var *thread= my_thread_var;
......@@ -367,7 +371,7 @@ my_bool info_check_pin(PAGECACHE_BLOCK_LINK *block,
1 - Error
*/
my_bool info_check_lock(PAGECACHE_BLOCK_LINK *block,
static my_bool info_check_lock(PAGECACHE_BLOCK_LINK *block,
enum pagecache_page_lock lock,
enum pagecache_page_pin pin)
{
......@@ -379,47 +383,47 @@ my_bool info_check_lock(PAGECACHE_BLOCK_LINK *block,
switch(lock)
{
case PAGECACHE_LOCK_LEFT_UNLOCKED:
DBUG_ASSERT(pin == PAGECACHE_PIN_LEFT_UNPINNED);
if (info)
if (pin != PAGECACHE_PIN_LEFT_UNPINNED ||
info)
goto error;
break;
case PAGECACHE_LOCK_LEFT_READLOCKED:
DBUG_ASSERT(pin == PAGECACHE_PIN_LEFT_UNPINNED ||
pin == PAGECACHE_PIN_LEFT_PINNED);
if (info == 0 || info->write_lock)
if ((pin != PAGECACHE_PIN_LEFT_UNPINNED &&
pin != PAGECACHE_PIN_LEFT_PINNED) ||
info == 0 || info->write_lock)
goto error;
break;
case PAGECACHE_LOCK_LEFT_WRITELOCKED:
DBUG_ASSERT(pin == PAGECACHE_PIN_LEFT_PINNED);
if (info == 0 || !info->write_lock)
if (pin != PAGECACHE_PIN_LEFT_PINNED ||
info == 0 || !info->write_lock)
goto error;
break;
case PAGECACHE_LOCK_READ:
DBUG_ASSERT(pin == PAGECACHE_PIN_LEFT_UNPINNED ||
pin == PAGECACHE_PIN);
if (info != 0)
if ((pin != PAGECACHE_PIN_LEFT_UNPINNED &&
pin != PAGECACHE_PIN) ||
info != 0)
goto error;
break;
case PAGECACHE_LOCK_WRITE:
DBUG_ASSERT(pin == PAGECACHE_PIN);
if (info != 0)
if (pin != PAGECACHE_PIN ||
info != 0)
goto error;
break;
case PAGECACHE_LOCK_READ_UNLOCK:
DBUG_ASSERT(pin == PAGECACHE_PIN_LEFT_UNPINNED ||
pin == PAGECACHE_UNPIN);
if (info == 0 || info->write_lock)
if ((pin != PAGECACHE_PIN_LEFT_UNPINNED &&
pin != PAGECACHE_UNPIN) ||
info == 0 || info->write_lock)
goto error;
break;
case PAGECACHE_LOCK_WRITE_UNLOCK:
DBUG_ASSERT(pin == PAGECACHE_UNPIN);
if (info == 0 || !info->write_lock)
if (pin != PAGECACHE_UNPIN ||
info == 0 || !info->write_lock)
goto error;
break;
case PAGECACHE_LOCK_WRITE_TO_READ:
DBUG_ASSERT(pin == PAGECACHE_PIN_LEFT_PINNED ||
pin == PAGECACHE_UNPIN);
if (info == 0 || !info->write_lock)
if ((pin != PAGECACHE_PIN_LEFT_PINNED &&
pin != PAGECACHE_UNPIN) ||
info == 0 || !info->write_lock)
goto error;
break;
}
......@@ -439,12 +443,6 @@ error:
#define FLUSH_CACHE 2000 /* sort this many blocks at once */
static int flush_all_key_blocks(PAGECACHE *pagecache);
#ifdef THREAD
static void link_into_queue(PAGECACHE_WQUEUE *wqueue,
struct st_my_thread_var *thread);
static void unlink_from_queue(PAGECACHE_WQUEUE *wqueue,
struct st_my_thread_var *thread);
#endif
static void free_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block);
static void test_key_cache(PAGECACHE *pagecache,
const char *where, my_bool lock);
......@@ -551,6 +549,7 @@ static int ___pagecache_pthread_cond_signal(pthread_cond_t *cond);
#define pagecache_pthread_cond_signal pthread_cond_signal
#endif /* defined(PAGECACHE_DEBUG) */
extern my_bool translog_flush(LSN *lsn);
/*
Write page to the disk
......@@ -567,18 +566,28 @@ static int ___pagecache_pthread_cond_signal(pthread_cond_t *cond);
0 - OK
!=0 - Error
*/
uint pagecache_fwrite(PAGECACHE *pagecache,
static uint pagecache_fwrite(PAGECACHE *pagecache,
PAGECACHE_FILE *filedesc,
byte *buffer,
maria_page_no_t pageno,
pgcache_page_no_t pageno,
enum pagecache_page_type type,
myf flags)
{
DBUG_ENTER("pagecache_fwrite");
if (type == PAGECACHE_LSN_PAGE)
{
LSN lsn;
DBUG_PRINT("info", ("Log handler call"));
/* TODO: put here loghandler call */
/* TODO: integrate with page format */
#define PAGE_LSN_OFFSET 0
lsn7korr(&lsn, buffer + PAGE_LSN_OFFSET);
/*
check CONTROL_FILE_IMPOSSIBLE_FILENO &
CONTROL_FILE_IMPOSSIBLE_LOG_OFFSET
*/
DBUG_ASSERT(lsn.file_no != 0 && lsn.rec_offset != 0);
translog_flush(&lsn);
}
DBUG_RETURN(my_pwrite(filedesc->file, buffer, pagecache->block_size,
(pageno)<<(pagecache->shift), flags));
......@@ -628,8 +637,6 @@ static uint next_power(uint value)
division_limit division limit (may be zero)
age_threshold age threshold (may be zero)
block_size size of block (should be power of 2)
loghandler logfandler pointer to call it in case of
pages with LSN
RETURN VALUE
number of blocks in the key cache, if successful,
......@@ -647,12 +654,11 @@ static uint next_power(uint value)
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)
{
int blocks, hash_links, length;
uint blocks, hash_links, length;
int error;
DBUG_ENTER("init_key_cache");
DBUG_ENTER("init_pagecache");
DBUG_ASSERT(block_size >= 512);
PAGECACHE_DEBUG_OPEN;
......@@ -662,8 +668,6 @@ int init_pagecache(PAGECACHE *pagecache, my_size_t use_mem,
DBUG_RETURN(0);
}
pagecache->loghandler= loghandler;
pagecache->global_cache_w_requests= pagecache->global_cache_r_requests= 0;
pagecache->global_cache_read= pagecache->global_cache_write= 0;
pagecache->disk_blocks= -1;
......@@ -692,8 +696,8 @@ int init_pagecache(PAGECACHE *pagecache, my_size_t use_mem,
for ( ; ; )
{
/* Set my_hash_entries to the next bigger 2 power */
if ((pagecache->hash_entries= next_power((uint)blocks)) <
((uint)blocks) * 5/4)
if ((pagecache->hash_entries= next_power(blocks)) <
(blocks) * 5/4)
pagecache->hash_entries<<= 1;
hash_links= 2 * blocks;
#if defined(MAX_THREADS)
......@@ -704,7 +708,7 @@ int init_pagecache(PAGECACHE *pagecache, my_size_t use_mem,
ALIGN_SIZE(hash_links * sizeof(PAGECACHE_HASH_LINK)) +
ALIGN_SIZE(sizeof(PAGECACHE_HASH_LINK*) *
pagecache->hash_entries))) +
((ulong) blocks << pagecache->shift) > use_mem)
(((ulong) blocks) << pagecache->shift) > use_mem)
blocks--;
/* Allocate memory for cache page buffers */
if ((pagecache->block_mem=
......@@ -760,10 +764,10 @@ int init_pagecache(PAGECACHE *pagecache, my_size_t use_mem,
pagecache->warm_blocks= 0;
pagecache->min_warm_blocks= (division_limit ?
blocks * division_limit / 100 + 1 :
(ulong)blocks);
blocks);
pagecache->age_threshold= (age_threshold ?
blocks * age_threshold / 100 :
(ulong)blocks);
blocks);
pagecache->cnt_for_resize_op= 0;
pagecache->resize_in_flush= 0;
......@@ -842,7 +846,8 @@ int resize_pagecache(PAGECACHE *pagecache,
{
int blocks;
struct st_my_thread_var *thread;
PAGECACHE_WQUEUE *wqueue;
WQUEUE *wqueue;
DBUG_ENTER("resize_pagecache");
if (!pagecache->inited)
......@@ -859,7 +864,7 @@ int resize_pagecache(PAGECACHE *pagecache,
#ifdef THREAD
wqueue= &pagecache->resize_queue;
thread= my_thread_var;
link_into_queue(wqueue, thread);
wqueue_link_into_queue(wqueue, thread);
while (wqueue->last_thread->next != thread)
{
......@@ -892,12 +897,11 @@ int resize_pagecache(PAGECACHE *pagecache,
end_pagecache(pagecache, 0); /* Don't free mutex */
/* The following will work even if use_mem is 0 */
blocks= init_pagecache(pagecache, pagecache->block_size, use_mem,
division_limit, age_threshold,
pagecache->loghandler);
division_limit, age_threshold);
finish:
#ifdef THREAD
unlink_from_queue(wqueue, thread);
wqueue_unlink_from_queue(wqueue, thread);
/* Signal for the next resize request to proceeed if any */
if (wqueue->last_thread)
{
......@@ -1027,146 +1031,6 @@ void end_pagecache(PAGECACHE *pagecache, my_bool cleanup)
} /* end_pagecache */
#ifdef THREAD
/*
Link a thread into double-linked queue of waiting threads.
SYNOPSIS
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.
*/
static void link_into_queue(PAGECACHE_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;
}
/*
Unlink a thread from double-linked queue of waiting threads
SYNOPSIS
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
*/
static void unlink_from_queue(PAGECACHE_WQUEUE *wqueue,
struct st_my_thread_var *thread)
{
KEYCACHE_DBUG_PRINT("unlink_from_queue", ("thread %ld", thread->id));
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;
}
/*
Add a thread to single-linked queue of waiting threads
SYNOPSIS
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.
*/
static inline void add_to_queue(PAGECACHE_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;
}
/*
Remove all threads from queue signaling them to proceed
SYNOPSIS
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.
*/
static void release_queue(PAGECACHE_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;
KEYCACHE_DBUG_PRINT("release_queue: signal", ("thread %ld", thread->id));
pagecache_pthread_cond_signal(&thread->suspend);
next=thread->next;
thread->next= NULL;
}
while (thread != last);
wqueue->last_thread= NULL;
}
#endif
/*
Unlink a block from the chain of dirty/clean blocks
*/
......@@ -1273,6 +1137,7 @@ static void link_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block,
PAGECACHE_BLOCK_LINK *ins;
PAGECACHE_BLOCK_LINK **ptr_ins;
BLOCK_INFO(block);
KEYCACHE_DBUG_ASSERT(! (block->hash_link && block->hash_link->requests));
#ifdef THREAD
if (!hot && pagecache->waiting_for_block.last_thread)
......@@ -1297,7 +1162,7 @@ static void link_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block,
{
KEYCACHE_DBUG_PRINT("link_block: signal", ("thread %ld", thread->id));
pagecache_pthread_cond_signal(&thread->suspend);
unlink_from_queue(&pagecache->waiting_for_block, thread);
wqueue_unlink_from_queue(&pagecache->waiting_for_block, thread);
block->requests++;
}
}
......@@ -1363,6 +1228,8 @@ static void link_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block,
static void unlink_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block)
{
DBUG_ENTER("unlink_block");
DBUG_PRINT("unlink_block", ("unlink 0x%lx", (ulong)block));
if (block->next_used == block)
/* The list contains only one member */
pagecache->used_last= pagecache->used_ins= NULL;
......@@ -1381,14 +1248,15 @@ static void unlink_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block)
KEYCACHE_THREAD_TRACE("unlink_block");
#if defined(PAGECACHE_DEBUG)
KEYCACHE_DBUG_ASSERT(pagecache->blocks_available != 0);
pagecache->blocks_available--;
KEYCACHE_DBUG_PRINT("unlink_block",
("unlinked block 0x%lx (%u) status=%x #requests=%u #available=%u",
(ulong)block, BLOCK_NUMBER(pagecache, block), block->status,
block->requests, pagecache->blocks_available));
BLOCK_INFO(block);
KEYCACHE_DBUG_ASSERT(pagecache->blocks_available >= 0);
#endif
DBUG_VOID_RETURN;
}
......@@ -1591,7 +1459,7 @@ static void unlink_hash(PAGECACHE *pagecache, PAGECACHE_HASH_LINK *hash_link)
{
KEYCACHE_DBUG_PRINT("unlink_hash: signal", ("thread %ld", thread->id));
pagecache_pthread_cond_signal(&thread->suspend);
unlink_from_queue(&pagecache->waiting_for_hash_link, thread);
wqueue_unlink_from_queue(&pagecache->waiting_for_hash_link, thread);
}
}
while (thread != last_thread);
......@@ -1618,7 +1486,7 @@ static void unlink_hash(PAGECACHE *pagecache, PAGECACHE_HASH_LINK *hash_link)
pagecache Pagecache reference
file file ID
pageno page number in the file
start where to put pointer to found hash link (for
start where to put pointer to found hash bucket (for
direct referring it)
RETURN
......@@ -1627,7 +1495,7 @@ static void unlink_hash(PAGECACHE *pagecache, PAGECACHE_HASH_LINK *hash_link)
static PAGECACHE_HASH_LINK *get_present_hash_link(PAGECACHE *pagecache,
PAGECACHE_FILE *file,
maria_page_no_t pageno,
pgcache_page_no_t pageno,
PAGECACHE_HASH_LINK ***start)
{
reg1 PAGECACHE_HASH_LINK *hash_link;
......@@ -1670,6 +1538,12 @@ static PAGECACHE_HASH_LINK *get_present_hash_link(PAGECACHE *pagecache,
KEYCACHE_DBUG_ASSERT(cnt <= pagecache->hash_links_used);
#endif
}
if (hash_link)
{
/* Register the request for the page */
hash_link->requests++;
}
DBUG_RETURN(hash_link);
}
......@@ -1680,7 +1554,7 @@ static PAGECACHE_HASH_LINK *get_present_hash_link(PAGECACHE *pagecache,
static PAGECACHE_HASH_LINK *get_hash_link(PAGECACHE *pagecache,
PAGECACHE_FILE *file,
maria_page_no_t pageno)
pgcache_page_no_t pageno)
{
reg1 PAGECACHE_HASH_LINK *hash_link;
PAGECACHE_HASH_LINK **start;
......@@ -1693,7 +1567,7 @@ restart:
/* try to find the page in the cache */
hash_link= get_present_hash_link(pagecache, file, pageno,
&start);
if (! hash_link)
if (!hash_link)
{
/* There is no hash link in the hash table for the pair (file, pageno) */
if (pagecache->free_hash_list)
......@@ -1714,7 +1588,7 @@ restart:
page.file= *file;
page.pageno= pageno;
thread->opt_info= (void *) &page;
link_into_queue(&pagecache->waiting_for_hash_link, thread);
wqueue_link_into_queue(&pagecache->waiting_for_hash_link, thread);
KEYCACHE_DBUG_PRINT("get_hash_link: wait",
("suspend thread %ld", thread->id));
pagecache_pthread_cond_wait(&thread->suspend,
......@@ -1723,14 +1597,15 @@ restart:
#else
KEYCACHE_DBUG_ASSERT(0);
#endif
DBUG_PRINT("info", ("restarting..."));
goto restart;
}
hash_link->file= *file;
hash_link->pageno= pageno;
link_hash(start, hash_link);
}
/* Register the request for the page */
hash_link->requests++;
}
return hash_link;
}
......@@ -1743,7 +1618,7 @@ restart:
SYNOPSIS
find_key_block()
find_block()
pagecache pointer to a page cache data structure
file handler for the file to read page from
pageno number of the page in the file
......@@ -1773,9 +1648,9 @@ restart:
waits until first of this operations links any block back.
*/
static PAGECACHE_BLOCK_LINK *find_key_block(PAGECACHE *pagecache,
static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache,
PAGECACHE_FILE *file,
maria_page_no_t pageno,
pgcache_page_no_t pageno,
int init_hits_left,
my_bool wrmode,
my_bool reg_req,
......@@ -1786,16 +1661,16 @@ static PAGECACHE_BLOCK_LINK *find_key_block(PAGECACHE *pagecache,
int error= 0;
int page_status;
DBUG_ENTER("find_key_block");
KEYCACHE_THREAD_TRACE("find_key_block:begin");
DBUG_ENTER("find_block");
KEYCACHE_THREAD_TRACE("find_block:begin");
DBUG_PRINT("enter", ("fd: %u pos %lu wrmode: %lu",
(uint) file->file, (ulong) pageno, (uint) wrmode));
KEYCACHE_DBUG_PRINT("find_key_block", ("fd: %u pos: %lu wrmode: %lu",
KEYCACHE_DBUG_PRINT("find_block", ("fd: %u pos: %lu wrmode: %lu",
(uint) file->file, (ulong) pageno,
(uint) wrmode));
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
DBUG_EXECUTE("check_pagecache",
test_key_cache(pagecache, "start of find_key_block", 0););
test_key_cache(pagecache, "start of find_block", 0););
#endif
restart:
......@@ -1840,10 +1715,10 @@ restart:
{
#ifdef THREAD
struct st_my_thread_var *thread= my_thread_var;
add_to_queue(&block->wqueue[COND_FOR_SAVED], thread);
wqueue_add_to_queue(&block->wqueue[COND_FOR_SAVED], thread);
do
{
KEYCACHE_DBUG_PRINT("find_key_block: wait",
KEYCACHE_DBUG_PRINT("find_block: wait",
("suspend thread %ld", thread->id));
pagecache_pthread_cond_wait(&thread->suspend,
&pagecache->cache_lock);
......@@ -1871,7 +1746,7 @@ restart:
{
/* This is a request for a page to be removed from cache */
KEYCACHE_DBUG_PRINT("find_key_block",
KEYCACHE_DBUG_PRINT("find_block",
("request for old page in block %u "
"wrmode: %d block->status: %d",
BLOCK_NUMBER(pagecache, block), wrmode,
......@@ -1888,17 +1763,17 @@ restart:
else
{
hash_link->requests--;
KEYCACHE_DBUG_PRINT("find_key_block",
KEYCACHE_DBUG_PRINT("find_block",
("request waiting for old page to be saved"));
{
#ifdef THREAD
struct st_my_thread_var *thread= my_thread_var;
/* Put the request into the queue of those waiting for the old page */
add_to_queue(&block->wqueue[COND_FOR_SAVED], thread);
wqueue_add_to_queue(&block->wqueue[COND_FOR_SAVED], thread);
/* Wait until the request can be resubmitted */
do
{
KEYCACHE_DBUG_PRINT("find_key_block: wait",
KEYCACHE_DBUG_PRINT("find_block: wait",
("suspend thread %ld", thread->id));
pagecache_pthread_cond_wait(&thread->suspend,
&pagecache->cache_lock);
......@@ -1909,11 +1784,13 @@ restart:
/* No parallel requests in single-threaded case */
#endif
}
KEYCACHE_DBUG_PRINT("find_key_block",
KEYCACHE_DBUG_PRINT("find_block",
("request for old page resubmitted"));
DBUG_PRINT("info", ("restarting..."));
/* Resubmit the request */
goto restart;
}
block->status&= ~BLOCK_IN_SWITCH;
}
else
{
......@@ -1941,7 +1818,8 @@ restart:
pagecache->blocks_used++;
}
pagecache->blocks_unused--;
DBUG_ASSERT((block->status & BLOCK_WRLOCK) == 0);
DBUG_ASSERT((block->status & BLOCK_WRLOCK));
DBUG_ASSERT(block->pins > 0);
block->status= 0;
#ifndef DBUG_OFF
block->type= PAGECACHE_EMPTY_PAGE;
......@@ -1954,7 +1832,9 @@ restart:
block->hash_link= hash_link;
hash_link->block= block;
page_status= PAGE_TO_BE_READ;
KEYCACHE_DBUG_PRINT("find_key_block",
DBUG_PRINT("info", ("page to be read set for page 0x%lx",
(ulong)block));
KEYCACHE_DBUG_PRINT("find_block",
("got free or never used block %u",
BLOCK_NUMBER(pagecache, block)));
}
......@@ -1973,10 +1853,10 @@ restart:
{
struct st_my_thread_var *thread= my_thread_var;
thread->opt_info= (void *) hash_link;
link_into_queue(&pagecache->waiting_for_block, thread);
wqueue_link_into_queue(&pagecache->waiting_for_block, thread);
do
{
KEYCACHE_DBUG_PRINT("find_key_block: wait",
KEYCACHE_DBUG_PRINT("find_block: wait",
("suspend thread %ld", thread->id));
pagecache_pthread_cond_wait(&thread->suspend,
&pagecache->cache_lock);
......@@ -2001,19 +1881,18 @@ restart:
reg_requests(pagecache, block,1);
hash_link->block= block;
}
else
{
DBUG_ASSERT((block->status & BLOCK_WRLOCK) == 0);
}
DBUG_ASSERT(block->pins > 0);
if (block->hash_link != hash_link &&
! (block->status & BLOCK_IN_SWITCH) )
{
/* this is a primary request for a new page */
DBUG_ASSERT((block->status & BLOCK_WRLOCK) == 0);
DBUG_ASSERT(block->pins > 0);
block->status|= (BLOCK_IN_SWITCH | BLOCK_WRLOCK);
KEYCACHE_DBUG_PRINT("find_key_block",
KEYCACHE_DBUG_PRINT("find_block",
("got block %u for new page",
BLOCK_NUMBER(pagecache, block)));
......@@ -2021,7 +1900,7 @@ restart:
{
/* The block contains a dirty page - push it out of the cache */
KEYCACHE_DBUG_PRINT("find_key_block", ("block is dirty"));
KEYCACHE_DBUG_PRINT("find_block", ("block is dirty"));
pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
/*
......@@ -2054,7 +1933,7 @@ restart:
unlink_hash(pagecache, block->hash_link);
/* All pending requests for this page must be resubmitted */
if (block->wqueue[COND_FOR_SAVED].last_thread)
release_queue(&block->wqueue[COND_FOR_SAVED]);
wqueue_release_queue(&block->wqueue[COND_FOR_SAVED]);
}
link_to_file_list(pagecache, block, file,
(my_bool)(block->hash_link ? 1 : 0));
......@@ -2065,6 +1944,8 @@ restart:
#endif
block->hash_link= hash_link;
page_status= PAGE_TO_BE_READ;
DBUG_PRINT("info", ("page to be read set for page 0x%lx",
(ulong)block));
KEYCACHE_DBUG_ASSERT(block->hash_link->block == block);
KEYCACHE_DBUG_ASSERT(hash_link->block->hash_link == hash_link);
......@@ -2072,7 +1953,7 @@ restart:
else
{
/* This is for secondary requests for a new page only */
KEYCACHE_DBUG_PRINT("find_key_block",
KEYCACHE_DBUG_PRINT("find_block",
("block->hash_link: %p hash_link: %p "
"block->status: %u", block->hash_link,
hash_link, block->status ));
......@@ -2087,7 +1968,7 @@ restart:
{
if (reg_req)
reg_requests(pagecache, block, 1);
KEYCACHE_DBUG_PRINT("find_key_block",
KEYCACHE_DBUG_PRINT("find_block",
("block->hash_link: %p hash_link: %p "
"block->status: %u", block->hash_link,
hash_link, block->status ));
......@@ -2098,12 +1979,12 @@ restart:
}
KEYCACHE_DBUG_ASSERT(page_status != -1);
*page_st=page_status;
*page_st= page_status;
DBUG_PRINT("info",
("block: 0x%lx fd: %u pos %lu block->status %u page_status %lu",
(ulong) block, (uint) file->file,
(ulong) pageno, block->status, (uint) page_status));
KEYCACHE_DBUG_PRINT("find_key_block",
KEYCACHE_DBUG_PRINT("find_block",
("block: 0x%lx fd: %u pos %lu block->status %u page_status %lu",
(ulong) block,
(uint) file->file, (ulong) pageno, block->status,
......@@ -2111,16 +1992,16 @@ restart:
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
DBUG_EXECUTE("check_pagecache",
test_key_cache(pagecache, "end of find_key_block",0););
test_key_cache(pagecache, "end of find_block",0););
#endif
KEYCACHE_THREAD_TRACE("find_key_block:end");
KEYCACHE_THREAD_TRACE("find_block:end");
DBUG_RETURN(block);
}
void pagecache_add_pin(PAGECACHE_BLOCK_LINK *block)
static void add_pin(PAGECACHE_BLOCK_LINK *block)
{
DBUG_ENTER("pagecache_add_pin");
DBUG_ENTER("add_pin");
DBUG_PRINT("enter", ("block 0x%lx pins: %u",
(ulong) block,
block->pins));
......@@ -2137,9 +2018,9 @@ void pagecache_add_pin(PAGECACHE_BLOCK_LINK *block)
DBUG_VOID_RETURN;
}
void pagecache_remove_pin(PAGECACHE_BLOCK_LINK *block)
static void remove_pin(PAGECACHE_BLOCK_LINK *block)
{
DBUG_ENTER("pagecache_remove_pin");
DBUG_ENTER("remove_pin");
DBUG_PRINT("enter", ("block 0x%lx pins: %u",
(ulong) block,
block->pins));
......@@ -2157,7 +2038,7 @@ void pagecache_remove_pin(PAGECACHE_BLOCK_LINK *block)
DBUG_VOID_RETURN;
}
#ifdef PAGECACHE_DEBUG
void pagecache_add_lock(PAGECACHE_BLOCK_LINK *block, my_bool wl)
static void info_add_lock(PAGECACHE_BLOCK_LINK *block, my_bool wl)
{
PAGECACHE_LOCK_INFO *info=
(PAGECACHE_LOCK_INFO *)my_malloc(sizeof(PAGECACHE_LOCK_INFO), MYF(0));
......@@ -2166,7 +2047,7 @@ void pagecache_add_lock(PAGECACHE_BLOCK_LINK *block, my_bool wl)
info_link((PAGECACHE_PIN_INFO **)&block->lock_list,
(PAGECACHE_PIN_INFO *)info);
}
void pagecache_remove_lock(PAGECACHE_BLOCK_LINK *block)
static void info_remove_lock(PAGECACHE_BLOCK_LINK *block)
{
PAGECACHE_LOCK_INFO *info=
(PAGECACHE_LOCK_INFO *)info_find((PAGECACHE_PIN_INFO *)block->lock_list,
......@@ -2175,7 +2056,7 @@ void pagecache_remove_lock(PAGECACHE_BLOCK_LINK *block)
info_unlink((PAGECACHE_PIN_INFO *)info);
my_free((gptr)info, MYF(0));
}
void pagecache_change_lock(PAGECACHE_BLOCK_LINK *block, my_bool wl)
static void info_change_lock(PAGECACHE_BLOCK_LINK *block, my_bool wl)
{
PAGECACHE_LOCK_INFO *info=
(PAGECACHE_LOCK_INFO *)info_find((PAGECACHE_PIN_INFO *)block->lock_list,
......@@ -2184,40 +2065,47 @@ void pagecache_change_lock(PAGECACHE_BLOCK_LINK *block, my_bool wl)
info->write_lock= wl;
}
#else
#define pagecache_add_lock(B,W)
#define pagecache_remove_lock(B)
#define pagecache_change_lock(B,W)
#define info_add_lock(B,W)
#define info_remove_lock(B)
#define info_change_lock(B,W)
#endif
/*
Put on the block "update" type lock
Put on the block write lock
SYNOPSIS
pagecache_lock_block()
get_wrlock()
pagecache pointer to a page cache data structure
block the block to work with
RETURN
0 - OK
1 - Try to lock the block failed
1 - Can't lock this block, need retry
*/
my_bool pagecache_lock_block(PAGECACHE *pagecache,
static my_bool get_wrlock(PAGECACHE *pagecache,
PAGECACHE_BLOCK_LINK *block)
{
DBUG_ENTER("pagecache_lock_block");
PAGECACHE_FILE file= block->hash_link->file;
pgcache_page_no_t pageno= block->hash_link->pageno;
DBUG_ENTER("get_wrlock");
DBUG_PRINT("info", ("the block 0x%lx "
"files %d(%d) pages %d(%d)",
(ulong)block,
file.file, block->hash_link->file.file,
pageno, block->hash_link->pageno));
BLOCK_INFO(block);
while (block->status & BLOCK_WRLOCK)
{
DBUG_PRINT("info", ("fail to lock, waiting..."));
DBUG_PRINT("info", ("fail to lock, waiting... 0x%lx", (ulong)block));
/* Lock failed we will wait */
#ifdef THREAD
struct st_my_thread_var *thread= my_thread_var;
add_to_queue(&block->wqueue[COND_FOR_WRLOCK], thread);
wqueue_add_to_queue(&block->wqueue[COND_FOR_WRLOCK], thread);
dec_counter_for_resize_op(pagecache);
do
{
KEYCACHE_DBUG_PRINT("pagecache_lock_block: wait",
KEYCACHE_DBUG_PRINT("get_wrlock: wait",
("suspend thread %ld", thread->id));
pagecache_pthread_cond_wait(&thread->suspend,
&pagecache->cache_lock);
......@@ -2227,35 +2115,61 @@ my_bool pagecache_lock_block(PAGECACHE *pagecache,
DBUG_ASSERT(0);
#endif
BLOCK_INFO(block);
if ((block->status & (BLOCK_REASSIGNED | BLOCK_IN_SWITCH)) ||
file.file != block->hash_link->file.file ||
pageno != block->hash_link->pageno)
{
DBUG_PRINT("info", ("the block 0x%lx changed => need retry"
"status %x files %d != %d or pages %d !=%d",
(ulong)block, block->status,
file.file, block->hash_link->file.file,
pageno, block->hash_link->pageno));
DBUG_RETURN(1);
}
/* we are doing it by global cache mutex protectio, so it is OK */
}
DBUG_ASSERT(block->pins == 0);
/* we are doing it by global cache mutex protection, so it is OK */
block->status|= BLOCK_WRLOCK;
DBUG_PRINT("info", ("WR lock set, block 0x%lx", (ulong)block));
DBUG_RETURN(0);
}
void pagecache_unlock_block(PAGECACHE_BLOCK_LINK *block)
/*
Remove write lock from the block
SYNOPSIS
release_wrlock()
pagecache pointer to a page cache data structure
block the block to work with
RETURN
0 - OK
*/
static void release_wrlock(PAGECACHE_BLOCK_LINK *block)
{
DBUG_ENTER("pagecache_unlock_block");
DBUG_ENTER("release_wrlock");
BLOCK_INFO(block);
DBUG_ASSERT(block->status & BLOCK_WRLOCK);
DBUG_ASSERT(block->pins > 0);
block->status&= ~BLOCK_WRLOCK;
DBUG_PRINT("info", ("WR lock reset, block 0x%lx", (ulong)block));
#ifdef THREAD
/* release all threads waiting for write lock */
if (block->wqueue[COND_FOR_WRLOCK].last_thread)
release_queue(&block->wqueue[COND_FOR_WRLOCK]);
wqueue_release_queue(&block->wqueue[COND_FOR_WRLOCK]);
#endif
BLOCK_INFO(block);
DBUG_VOID_RETURN;
}
/*
Try to lock/uplock and pin/unpin the block
Try to lock/unlock and pin/unpin the block
SYNOPSIS
pagecache_make_lock_and_pin()
make_lock_and_pin()
pagecache pointer to a page cache data structure
block the block to work with
lock lock change mode
......@@ -2266,12 +2180,12 @@ void pagecache_unlock_block(PAGECACHE_BLOCK_LINK *block)
1 - Try to lock the block failed
*/
my_bool pagecache_make_lock_and_pin(PAGECACHE *pagecache,
static my_bool make_lock_and_pin(PAGECACHE *pagecache,
PAGECACHE_BLOCK_LINK *block,
enum pagecache_page_lock lock,
enum pagecache_page_pin pin)
{
DBUG_ENTER("pagecache_make_lock_and_pin");
DBUG_ENTER("make_lock_and_pin");
DBUG_PRINT("enter", ("block: 0x%lx (%u), wrlock: %c pins: %u, lock %s, pin: %s",
(ulong)block, BLOCK_NUMBER(pagecache, block),
((block->status & BLOCK_WRLOCK)?'Y':'N'),
......@@ -2287,53 +2201,47 @@ my_bool pagecache_make_lock_and_pin(PAGECACHE *pagecache,
{
case PAGECACHE_LOCK_WRITE: /* free -> write */
/* Writelock and pin the buffer */
if (pagecache_lock_block(pagecache, block))
if (get_wrlock(pagecache, block))
{
DBUG_PRINT("info", ("restart"));
/* in case of fail pagecache_lock_block unlock cache */
DBUG_RETURN(1);
/* can't lock => need retry */
goto retry;
}
/* The cache is locked so nothing afraid off */
pagecache_add_pin(block);
pagecache_add_lock(block, 1);
/* The cache is locked so nothing afraid of */
add_pin(block);
info_add_lock(block, 1);
break;
case PAGECACHE_LOCK_WRITE_TO_READ: /* write -> read */
case PAGECACHE_LOCK_WRITE_UNLOCK: /* write -> free */
/*
Removes writelog and puts read lock (which is nothing in our
Removes write lock and puts read lock (which is nothing in our
implementation)
*/
pagecache_unlock_block(block);
release_wrlock(block);
case PAGECACHE_LOCK_READ_UNLOCK: /* read -> free */
case PAGECACHE_LOCK_LEFT_READLOCKED: /* read -> read */
#ifndef DBUG_OFF
if (pin == PAGECACHE_UNPIN)
{
pagecache_remove_pin(block);
remove_pin(block);
}
#endif
#ifdef PAGECACHE_DEBUG
if (lock == PAGECACHE_LOCK_WRITE_TO_READ)
{
pagecache_change_lock(block, 0);
info_change_lock(block, 0);
}
else if (lock == PAGECACHE_LOCK_WRITE_UNLOCK ||
lock == PAGECACHE_LOCK_READ_UNLOCK)
{
pagecache_remove_lock(block);
info_remove_lock(block);
}
#endif
break;
case PAGECACHE_LOCK_READ: /* free -> read */
#ifndef DBUG_OFF
if (pin == PAGECACHE_PIN)
{
/* The cache is locked so nothing afraid off */
pagecache_add_pin(block);
add_pin(block);
}
pagecache_add_lock(block, 0);
info_add_lock(block, 0);
break;
#endif
case PAGECACHE_LOCK_LEFT_UNLOCKED: /* free -> free */
case PAGECACHE_LOCK_LEFT_WRITELOCKED: /* write -> write */
break; /* do nothing */
......@@ -2343,6 +2251,16 @@ my_bool pagecache_make_lock_and_pin(PAGECACHE *pagecache,
BLOCK_INFO(block);
DBUG_RETURN(0);
retry:
DBUG_PRINT("INFO", ("Retry block 0x%lx", (ulong)block));
BLOCK_INFO(block);
DBUG_ASSERT(block->hash_link->requests != 0);
block->hash_link->requests--;
DBUG_ASSERT(block->requests != 0);
unreg_request(pagecache, block, 1);
BLOCK_INFO(block);
DBUG_RETURN(1);
}
......@@ -2355,6 +2273,8 @@ my_bool pagecache_make_lock_and_pin(PAGECACHE *pagecache,
pagecache pointer to a page cache data structure
block block to which buffer the data is to be read
primary <-> the current thread will read the data
validator validator of read from the disk data
validator_data pointer to the data need by the validator
RETURN VALUE
None
......@@ -2368,13 +2288,15 @@ my_bool pagecache_make_lock_and_pin(PAGECACHE *pagecache,
static void read_block(PAGECACHE *pagecache,
PAGECACHE_BLOCK_LINK *block,
my_bool primary)
my_bool primary,
pagecache_disk_read_validator validator,
gptr validator_data)
{
uint got_length;
/* On entry cache_lock is locked */
KEYCACHE_THREAD_TRACE("read_block");
DBUG_ENTER("read_block");
if (primary)
{
/*
......@@ -2382,7 +2304,7 @@ static void read_block(PAGECACHE *pagecache,
that submitted primary requests
*/
KEYCACHE_DBUG_PRINT("read_block",
DBUG_PRINT("read_block",
("page to be read by primary request"));
/* Page is not in buffer yet, is to be read from disk */
......@@ -2400,11 +2322,15 @@ static void read_block(PAGECACHE *pagecache,
else
block->status= (BLOCK_READ | (block->status & BLOCK_WRLOCK));
KEYCACHE_DBUG_PRINT("read_block",
if (validator != NULL &&
(*validator)(block->buffer, validator_data))
block->status|= BLOCK_ERROR;
DBUG_PRINT("read_block",
("primary request: new page in cache"));
/* Signal that all pending requests for this page now can be processed */
if (block->wqueue[COND_FOR_REQUESTED].last_thread)
release_queue(&block->wqueue[COND_FOR_REQUESTED]);
wqueue_release_queue(&block->wqueue[COND_FOR_REQUESTED]);
}
else
{
......@@ -2412,16 +2338,16 @@ static void read_block(PAGECACHE *pagecache,
This code is executed only by threads
that submitted secondary requests
*/
KEYCACHE_DBUG_PRINT("read_block",
DBUG_PRINT("read_block",
("secondary request waiting for new page to be read"));
{
#ifdef THREAD
struct st_my_thread_var *thread= my_thread_var;
/* Put the request into a queue and wait until it can be processed */
add_to_queue(&block->wqueue[COND_FOR_REQUESTED], thread);
wqueue_add_to_queue(&block->wqueue[COND_FOR_REQUESTED], thread);
do
{
KEYCACHE_DBUG_PRINT("read_block: wait",
DBUG_PRINT("read_block: wait",
("suspend thread %ld", thread->id));
pagecache_pthread_cond_wait(&thread->suspend,
&pagecache->cache_lock);
......@@ -2432,9 +2358,10 @@ static void read_block(PAGECACHE *pagecache,
/* No parallel requests in single-threaded case */
#endif
}
KEYCACHE_DBUG_PRINT("read_block",
DBUG_PRINT("read_block",
("secondary request: new page in cache"));
}
DBUG_VOID_RETURN;
}
......@@ -2454,11 +2381,11 @@ static void read_block(PAGECACHE *pagecache,
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)
{
PAGECACHE_BLOCK_LINK *block;
int page_st;
......@@ -2471,24 +2398,6 @@ void pagecache_unlock_page(PAGECACHE *pagecache,
DBUG_ASSERT(pin != PAGECACHE_PIN &&
lock != PAGECACHE_LOCK_READ &&
lock != PAGECACHE_LOCK_WRITE);
if (pin == PAGECACHE_PIN_LEFT_UNPINNED &&
lock == PAGECACHE_LOCK_READ_UNLOCK)
{
#ifndef DBUG_OFF
if (
#endif
/* block do not need here so we do not provide it */
pagecache_make_lock_and_pin(pagecache, 0, lock, pin)
#ifndef DBUG_OFF
)
{
DBUG_ASSERT(0); /* should not happend */
}
#else
;
#endif
DBUG_VOID_RETURN;
}
pagecache_pthread_mutex_lock(&pagecache->cache_lock);
/*
......@@ -2498,7 +2407,7 @@ void pagecache_unlock_page(PAGECACHE *pagecache,
DBUG_ASSERT(pagecache->can_be_used);
inc_counter_for_resize_op(pagecache);
block= find_key_block(pagecache, file, pageno, 0, 0, 0, &page_st);
block= find_block(pagecache, file, pageno, 0, 0, 0, &page_st);
BLOCK_INFO(block);
DBUG_ASSERT(block != 0 && page_st == PAGE_READ);
if (stamp_this_page)
......@@ -2511,7 +2420,7 @@ void pagecache_unlock_page(PAGECACHE *pagecache,
#ifndef DBUG_OFF
if (
#endif
pagecache_make_lock_and_pin(pagecache, block, lock, pin)
make_lock_and_pin(pagecache, block, lock, pin)
#ifndef DBUG_OFF
)
{
......@@ -2549,7 +2458,7 @@ void pagecache_unlock_page(PAGECACHE *pagecache,
void pagecache_unpin_page(PAGECACHE *pagecache,
PAGECACHE_FILE *file,
maria_page_no_t pageno)
pgcache_page_no_t pageno)
{
PAGECACHE_BLOCK_LINK *block;
int page_st;
......@@ -2565,7 +2474,7 @@ void pagecache_unpin_page(PAGECACHE *pagecache,
DBUG_ASSERT(pagecache->can_be_used);
inc_counter_for_resize_op(pagecache);
block= find_key_block(pagecache, file, pageno, 0, 0, 0, &page_st);
block= find_block(pagecache, file, pageno, 0, 0, 0, &page_st);
DBUG_ASSERT(block != 0 && page_st == PAGE_READ);
#ifndef DBUG_OFF
......@@ -2576,7 +2485,7 @@ void pagecache_unpin_page(PAGECACHE *pagecache,
a) we can't pin without any lock
b) we can't unpin keeping write lock
*/
pagecache_make_lock_and_pin(pagecache, block,
make_lock_and_pin(pagecache, block,
PAGECACHE_LOCK_LEFT_READLOCKED,
PAGECACHE_UNPIN)
#ifndef DBUG_OFF
......@@ -2622,7 +2531,7 @@ void pagecache_unlock(PAGECACHE *pagecache,
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)
{
PAGECACHE_BLOCK_LINK *block= (PAGECACHE_BLOCK_LINK *)link;
DBUG_ENTER("pagecache_unlock");
......@@ -2643,7 +2552,7 @@ void pagecache_unlock(PAGECACHE *pagecache,
if (
#endif
/* block do not need here so we do not provide it */
pagecache_make_lock_and_pin(pagecache, 0, lock, pin)
make_lock_and_pin(pagecache, 0, lock, pin)
#ifndef DBUG_OFF
)
{
......@@ -2673,7 +2582,7 @@ void pagecache_unlock(PAGECACHE *pagecache,
#ifndef DBUG_OFF
if (
#endif
pagecache_make_lock_and_pin(pagecache, block, lock, pin)
make_lock_and_pin(pagecache, block, lock, pin)
#ifndef DBUG_OFF
)
{
......@@ -2736,7 +2645,7 @@ void pagecache_unpin(PAGECACHE *pagecache,
a) we can't pin without any lock
b) we can't unpin keeping write lock
*/
pagecache_make_lock_and_pin(pagecache, block,
make_lock_and_pin(pagecache, block,
PAGECACHE_LOCK_LEFT_READLOCKED,
PAGECACHE_UNPIN)
#ifndef DBUG_OFF
......@@ -2767,7 +2676,7 @@ void pagecache_unpin(PAGECACHE *pagecache,
Read a block of data from a cached file into a buffer;
SYNOPSIS
pagecache_read()
pagecache_valid_read()
pagecache pointer to a page cache data structure
file handler for the file for the block of data to be read
pageno number of the block of data in the file
......@@ -2776,16 +2685,12 @@ void pagecache_unpin(PAGECACHE *pagecache,
type type of the page
lock lock change
link link to the page if we pin it
validator validator of read from the disk data
validator_data pointer to the data need by the validator
RETURN VALUE
Returns address from where the data is placed if sucessful, 0 - otherwise.
NOTES.
The function ensures that a block of data of size length from file
positioned at pageno is in the buffers for some key cache blocks.
Then the function copies the data into the buffer buff.
Pin will be choosen according to lock parameter (see lock_to_pin)
*/
static enum pagecache_page_pin lock_to_pin[]=
......@@ -2800,19 +2705,21 @@ static enum pagecache_page_pin lock_to_pin[]=
PAGECACHE_UNPIN /*PAGECACHE_LOCK_WRITE_TO_READ*/
};
byte *pagecache_read(PAGECACHE *pagecache,
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)
{
int error= 0;
enum pagecache_page_pin pin= lock_to_pin[lock];
PAGECACHE_PAGE_LINK fake_link;
DBUG_ENTER("page_cache_read");
DBUG_ENTER("pagecache_valid_read");
DBUG_PRINT("enter", ("fd: %u page: %lu level: %u t:%s l%s p%s",
(uint) file->file, (ulong) pageno, level,
page_cache_page_type_str[type],
......@@ -2829,7 +2736,7 @@ restart:
if (pagecache->can_be_used)
{
/* Key cache is used */
reg1 PAGECACHE_BLOCK_LINK *block;
PAGECACHE_BLOCK_LINK *block;
uint status;
int page_st;
......@@ -2842,29 +2749,33 @@ restart:
inc_counter_for_resize_op(pagecache);
pagecache->global_cache_r_requests++;
block= find_key_block(pagecache, file, pageno, level,
((lock == PAGECACHE_LOCK_WRITE) ? 1 : 0),
(((pin == PAGECACHE_PIN_LEFT_PINNED) ||
(pin == PAGECACHE_UNPIN)) ? 0 : 1),
block= find_block(pagecache, file, pageno, level,
test(lock == PAGECACHE_LOCK_WRITE),
test((pin == PAGECACHE_PIN_LEFT_PINNED) ||
(pin == PAGECACHE_UNPIN)),
&page_st);
DBUG_ASSERT(block->type == PAGECACHE_EMPTY_PAGE ||
block->type == type);
block->type= type;
if (pagecache_make_lock_and_pin(pagecache, block, lock, pin))
if (block->status != BLOCK_ERROR && page_st != PAGE_READ)
{
DBUG_PRINT("info", ("read block 0x%lx", (ulong)block));
/* The requested page is to be read into the block buffer */
read_block(pagecache, block,
(my_bool)(page_st == PAGE_TO_BE_READ),
validator, validator_data);
DBUG_PRINT("info", ("read is done"));
}
if (make_lock_and_pin(pagecache, block, lock, pin))
{
/*
We failed to write lock the block, cache is unlocked, and last write
lock is released, we will try to get the block again.
We failed to write lock the block, cache is unlocked,
we will try to get the block again.
*/
pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
DBUG_PRINT("info", ("restarting..."));
goto restart;
}
if (block->status != BLOCK_ERROR && page_st != PAGE_READ)
{
/* The requested page is to be read into the block buffer */
read_block(pagecache, block,
(my_bool)(page_st == PAGE_TO_BE_READ));
}
if (! ((status= block->status) & BLOCK_ERROR))
{
......@@ -2933,7 +2844,7 @@ no_key_cache: /* Key cache is not used */
*/
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)
{
......@@ -2969,13 +2880,14 @@ restart:
}
block= link->block;
DBUG_ASSERT(block != 0);
if (pagecache_make_lock_and_pin(pagecache, block, lock, pin))
if (make_lock_and_pin(pagecache, block, lock, pin))
{
/*
We failed to writelock the block, cache is unlocked, and last write
lock is released, we will try to get the block again.
*/
pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
DBUG_PRINT("info", ("restarting..."));
goto restart;
}
......@@ -2983,7 +2895,7 @@ restart:
{
/* The block contains a dirty page - push it out of the cache */
KEYCACHE_DBUG_PRINT("find_key_block", ("block is dirty"));
KEYCACHE_DBUG_PRINT("find_block", ("block is dirty"));
pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
/*
......@@ -3015,9 +2927,10 @@ restart:
}
/* Cache is locked, so we can relese page before freeing it */
pagecache_make_lock_and_pin(pagecache, block,
make_lock_and_pin(pagecache, block,
PAGECACHE_LOCK_WRITE_UNLOCK,
PAGECACHE_UNPIN);
link->requests--;
if (pin == PAGECACHE_PIN_LEFT_PINNED)
unreg_request(pagecache, block, 1);
free_block(pagecache, block);
......@@ -3053,11 +2966,12 @@ end:
0 if a success, 1 - otherwise.
*/
/* description of how to change lock before and after write */
struct write_lock_change
{
int need_lock_change;
enum pagecache_page_lock new_lock;
enum pagecache_page_lock unlock_lock;
int need_lock_change; /* need changing of lock at the end of write */
enum pagecache_page_lock new_lock; /* lock at the beginning */
enum pagecache_page_lock unlock_lock; /* lock at the end */
};
static struct write_lock_change write_lock_change_table[]=
......@@ -3084,10 +2998,11 @@ static struct write_lock_change write_lock_change_table[]=
PAGECACHE_LOCK_WRITE_TO_READ}/*PAGECACHE_LOCK_WRITE_TO_READ*/
};
/* description of how to change pin before and after write */
struct write_pin_change
{
enum pagecache_page_pin new_pin;
enum pagecache_page_pin unlock_pin;
enum pagecache_page_pin new_pin; /* pin status at the beginning */
enum pagecache_page_pin unlock_pin; /* pin status at the end */
};
static struct write_pin_change write_pin_change_table[]=
......@@ -3104,7 +3019,7 @@ static struct write_pin_change write_pin_change_table[]=
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,
......@@ -3113,7 +3028,7 @@ my_bool pagecache_write(PAGECACHE *pagecache,
enum pagecache_write_mode write_mode,
PAGECACHE_PAGE_LINK *link)
{
reg1 PAGECACHE_BLOCK_LINK *block;
reg1 PAGECACHE_BLOCK_LINK *block= NULL;
PAGECACHE_PAGE_LINK fake_link;
int error= 0;
int need_lock_change= write_lock_change_table[lock].need_lock_change;
......@@ -3133,7 +3048,7 @@ my_bool pagecache_write(PAGECACHE *pagecache,
if (write_mode == PAGECACHE_WRITE_NOW)
{
/* we allow direct write if wwe do not use long term lockings */
/* we allow direct write if we do not use long term lockings */
DBUG_ASSERT(lock == PAGECACHE_LOCK_LEFT_UNLOCKED);
/* Force writing from buff into disk */
pagecache->global_cache_write++;
......@@ -3167,7 +3082,7 @@ restart:
lock != PAGECACHE_LOCK_LEFT_WRITELOCKED &&
lock != PAGECACHE_LOCK_WRITE_UNLOCK &&
lock != PAGECACHE_LOCK_WRITE_TO_READ);
block= find_key_block(pagecache, file, pageno, level,
block= find_block(pagecache, file, pageno, level,
(need_wrlock ? 1 : 0),
(need_wrlock ? 1 : 0),
&page_st);
......@@ -3186,7 +3101,7 @@ restart:
block->type == type);
block->type= type;
if (pagecache_make_lock_and_pin(pagecache, block,
if (make_lock_and_pin(pagecache, block,
write_lock_change_table[lock].new_lock,
(need_lock_change ?
write_pin_change_table[pin].new_pin :
......@@ -3197,13 +3112,14 @@ restart:
lock is released, we will try to get the block again.
*/
pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
DBUG_PRINT("info", ("restarting..."));
goto restart;
}
if (write_mode == PAGECACHE_WRITE_DONE)
{
if (block->status != BLOCK_ERROR && page_st != PAGE_READ)
if ((block->status & BLOCK_ERROR) && page_st != PAGE_READ)
{
/* Copy data from buff */
bmove512(block->buffer, buff, pagecache->block_size);
......@@ -3212,7 +3128,7 @@ restart:
("primary request: new page in cache"));
/* Signal that all pending requests for this now can be processed. */
if (block->wqueue[COND_FOR_REQUESTED].last_thread)
release_queue(&block->wqueue[COND_FOR_REQUESTED]);
wqueue_release_queue(&block->wqueue[COND_FOR_REQUESTED]);
}
}
else
......@@ -3220,7 +3136,8 @@ restart:
if (write_mode == PAGECACHE_WRITE_NOW)
{
/* buff has been written to disk at start */
if (block->status & BLOCK_CHANGED)
if ((block->status & BLOCK_CHANGED) &&
!(block->status & BLOCK_ERROR))
link_to_file_list(pagecache, block, &block->hash_link->file, 1);
}
else
......@@ -3231,9 +3148,9 @@ restart:
if (! (block->status & BLOCK_ERROR))
{
bmove512(block->buffer, buff, pagecache->block_size);
}
block->status|= BLOCK_READ;
}
}
if (need_lock_change)
......@@ -3242,7 +3159,7 @@ restart:
int rc=
#endif
#warning we are doing an unlock here, so need to give the page its rec_lsn!
pagecache_make_lock_and_pin(pagecache, block,
make_lock_and_pin(pagecache, block,
write_lock_change_table[lock].unlock_lock,
write_pin_change_table[pin].unlock_pin);
#ifndef DBUG_OFF
......@@ -3254,12 +3171,9 @@ restart:
block->hash_link->requests--;
if (pin != PAGECACHE_PIN_LEFT_PINNED && pin != PAGECACHE_PIN)
{
if (write_mode != PAGECACHE_WRITE_DONE)
{
unreg_request(pagecache, block, 1);
}
}
else
*link= (PAGECACHE_PAGE_LINK)block;
......@@ -3290,6 +3204,7 @@ end:
DBUG_EXECUTE("exec",
test_key_cache(pagecache, "end of key_cache_write", 1););
#endif
BLOCK_INFO(block);
DBUG_RETURN(error);
}
......@@ -3321,6 +3236,7 @@ static void free_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block)
unlink_changed(block);
DBUG_ASSERT((block->status & BLOCK_WRLOCK) == 0);
DBUG_ASSERT(block->pins > 0);
block->status= 0;
#ifndef DBUG_OFF
block->type= PAGECACHE_EMPTY_PAGE;
......@@ -3344,7 +3260,7 @@ static void free_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block)
/* All pending requests for this page must be resubmitted. */
if (block->wqueue[COND_FOR_SAVED].last_thread)
release_queue(&block->wqueue[COND_FOR_SAVED]);
wqueue_release_queue(&block->wqueue[COND_FOR_SAVED]);
}
......@@ -3398,11 +3314,12 @@ static int flush_cached_blocks(PAGECACHE *pagecache,
}
/* if the block is not pinned then it is not write locked */
DBUG_ASSERT((block->status & BLOCK_WRLOCK) == 0);
DBUG_ASSERT(block->pins > 0);
#ifndef DBUG_OFF
{
int rc=
#endif
pagecache_make_lock_and_pin(pagecache, block,
make_lock_and_pin(pagecache, block,
PAGECACHE_LOCK_WRITE, PAGECACHE_PIN);
#ifndef DBUG_OFF
DBUG_ASSERT(rc == 0);
......@@ -3427,7 +3344,7 @@ static int flush_cached_blocks(PAGECACHE *pagecache,
MYF(MY_NABP | MY_WAIT_IF_FULL));
pagecache_pthread_mutex_lock(&pagecache->cache_lock);
pagecache_make_lock_and_pin(pagecache, block,
make_lock_and_pin(pagecache, block,
PAGECACHE_LOCK_WRITE_UNLOCK,
PAGECACHE_UNPIN);
......@@ -3443,7 +3360,7 @@ static int flush_cached_blocks(PAGECACHE *pagecache,
It might happen only during an operation to resize the key cache.
*/
if (block->wqueue[COND_FOR_SAVED].last_thread)
release_queue(&block->wqueue[COND_FOR_SAVED]);
wqueue_release_queue(&block->wqueue[COND_FOR_SAVED]);
/* type will never be FLUSH_IGNORE_CHANGED here */
if (! (type == FLUSH_KEEP || type == FLUSH_FORCE_WRITE))
{
......@@ -3577,6 +3494,7 @@ restart:
if ((error= flush_cached_blocks(pagecache, file, cache,
end,type)))
last_errno=error;
DBUG_PRINT("info", ("restarting..."));
/*
Restart the scan as some other thread might have changed
the changed blocks chain: the blocks that were in switch
......@@ -3622,7 +3540,7 @@ removes a page from the list of dirty pages, while it's still dirty. A \
{
#ifdef THREAD
struct st_my_thread_var *thread= my_thread_var;
add_to_queue(&block->wqueue[COND_FOR_SAVED], thread);
wqueue_add_to_queue(&block->wqueue[COND_FOR_SAVED], thread);
do
{
KEYCACHE_DBUG_PRINT("flush_pagecache_blocks_int: wait",
......@@ -3761,7 +3679,7 @@ static int flush_all_key_blocks(PAGECACHE *pagecache)
0 on success (always because it can't fail)
*/
int reset_key_cache_counters(const char *name, PAGECACHE *key_cache)
static int reset_key_cache_counters(const char *name, PAGECACHE *key_cache)
{
DBUG_ENTER("reset_key_cache_counters");
if (!key_cache->inited)
......
#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;
}
......@@ -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
......
......@@ -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"
/*
......
This source diff could not be displayed because it is too large. You can view the blob instead.
#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
#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
......@@ -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 */
......
......@@ -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
......@@ -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];
......
#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));
}
#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));
}
#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));
}
#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);
}
......@@ -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);
......
......@@ -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);
......
......@@ -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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment