Commit 4cf6756e authored by unknown's avatar unknown

First LSN calls added for transaction log.


storage/maria/ma_checkpoint.c:
  Definitions of LSN should be collected in
  the one file (ma_loghandler_lsn.h)
storage/maria/ma_loghandler.c:
  New calls to get first theoretical and first real LSN.
storage/maria/ma_loghandler.h:
  New calls to get first theoretical and first real LSN.
storage/maria/ma_loghandler_lsn.h:
  Defined yet another impossible LSN to indicate error.
storage/maria/ma_recovery.c:
  The first LSN call changed.
storage/maria/maria_read_log.c:
  The first LSN call changed.
storage/maria/unittest/Makefile.am:
  New unittest added.
storage/maria/unittest/ma_test_loghandler_first_lsn-t.c:
  New BitKeeper file ``storage/maria/unittest/ma_test_loghandler_first_lsn-t.c''
parent fddf5050
......@@ -38,8 +38,8 @@
#include "transaction.h"
#include "share.h"
#include "log.h"
#include "ma_loghandler_lsn.h"
#define LSN_IMPOSSIBLE ((LSN)0) /* could also be called LSN_ERROR */
#define LSN_MAX ((LSN)ULONGLONG_MAX)
/*
......
......@@ -5976,13 +5976,127 @@ void translog_deassign_id_from_share(MARIA_SHARE *share)
}
/**
@brief check if such log file exists
@param file_no number of the file to test
@retval 0 no such file
@retval 1 there is file with such number
*/
my_bool translog_is_file(uint file_no)
{
MY_STAT stat_buff;
char path[FN_REFLEN];
return (test(my_stat(translog_filename_by_fileno(file_no, path),
&stat_buff, MYF(MY_WME))));
}
/**
@brief returns the LSN of the first record starting in this log
@note so far works only for the very first log created on this system
@retval LSN_ERROR Error
@retval LSN_IMPOSSIBLE no log
@retval # LSN of the first record
*/
LSN first_lsn_in_log()
LSN translog_first_lsn_in_log()
{
return MAKE_LSN(1, TRANSLOG_PAGE_SIZE + log_descriptor.page_overhead);
TRANSLOG_ADDRESS addr, horizon= translog_get_horizon();
TRANSLOG_VALIDATOR_DATA data;
uint min_file= 1, max_file= LSN_FILE_NO(horizon);
uint chunk_type;
uint16 chunk_offset;
uchar *page;
TRANSLOG_SCANNER_DATA scanner;
DBUG_ENTER("translog_first_lsn_in_log");
DBUG_PRINT("info", ("Horizon: (%lu,0x%lx)",
LSN_FILE_NO(addr), LSN_OFFSET(addr)));
if (addr == MAKE_LSN(1, TRANSLOG_PAGE_SIZE))
{
/* there is no first page yet */
DBUG_RETURN(LSN_IMPOSSIBLE);
}
/*TODO: lock loghandler purger when it will be created */
/* binary search for last file */
while (min_file != max_file && min_file != (max_file - 1))
{
uint test= (min_file + max_file) / 2;
DBUG_PRINT("info", ("min_file: %u test: %u max_file: %u",
min_file, test, max_file));
if (test == max_file)
test--;
if (translog_is_file(test))
max_file= test;
else
min_file= test;
}
addr= MAKE_LSN(max_file, TRANSLOG_PAGE_SIZE); /* the first page of the file */
data.addr= &addr;
if ((page= translog_get_page(&data, scanner.buffer)) == NULL ||
(chunk_offset= translog_get_first_chunk_offset(page)) == 0)
DBUG_RETURN(LSN_ERROR);
addr+= chunk_offset;
if (addr == horizon)
DBUG_RETURN(LSN_IMPOSSIBLE);
translog_init_scanner(addr, 0, &scanner);
chunk_type= scanner.page[scanner.page_offset] & TRANSLOG_CHUNK_TYPE;
DBUG_PRINT("info", ("type: %x byte: %x", (uint) chunk_type,
(uint) scanner.page[scanner.page_offset]));
while (chunk_type != TRANSLOG_CHUNK_LSN &&
chunk_type != TRANSLOG_CHUNK_FIXED &&
scanner.page[scanner.page_offset] != 0)
{
if (translog_get_next_chunk(&scanner))
DBUG_RETURN(LSN_ERROR);
chunk_type= scanner.page[scanner.page_offset] & TRANSLOG_CHUNK_TYPE;
DBUG_PRINT("info", ("type: %x byte: %x", (uint) chunk_type,
(uint) scanner.page[scanner.page_offset]));
}
if (scanner.page[scanner.page_offset] == 0)
DBUG_RETURN(LSN_IMPOSSIBLE); /* reached page filler */
DBUG_RETURN(scanner.page_addr + scanner.page_offset);
}
/**
@brief returns theoretical first LSN if first log is present
@retval LSN_ERROR Error
@retval LSN_IMPOSSIBLE no log
@retval # LSN of the first record
*/
LSN translog_first_theoretical_lsn()
{
TRANSLOG_ADDRESS addr= translog_get_horizon();
uchar buffer[TRANSLOG_PAGE_SIZE], *page;
TRANSLOG_VALIDATOR_DATA data;
DBUG_ENTER("translog_first_theoretical_lsn");
DBUG_PRINT("info", ("Horizon: (%lu,0x%lx)",
LSN_FILE_NO(addr), LSN_OFFSET(addr)));
if (!translog_is_file(1))
DBUG_RETURN(LSN_IMPOSSIBLE);
if (addr == MAKE_LSN(1, TRANSLOG_PAGE_SIZE))
{
/* there is no first page yet */
DBUG_RETURN(MAKE_LSN(1, TRANSLOG_PAGE_SIZE +
log_descriptor.page_overhead));
}
addr= MAKE_LSN(1, TRANSLOG_PAGE_SIZE); /* the first page of the file */
data.addr= &addr;
if ((page= translog_get_page(&data, buffer)) == NULL)
DBUG_RETURN(LSN_ERROR);
DBUG_RETURN(MAKE_LSN(1, TRANSLOG_PAGE_SIZE +
page_overhead[page[TRANSLOG_PAGE_FLAGS]]));
}
......@@ -266,7 +266,8 @@ extern my_bool translog_inited;
#define SHARE_ID_MAX 65535 /* array's size */
extern LSN first_lsn_in_log();
extern LSN translog_first_lsn_in_log();
extern LSN translog_first_theoretical_lsn();
/* record parts descriptor */
struct st_translog_parts
......
......@@ -81,6 +81,8 @@ typedef LSN LSN_WITH_FLAGS;
#define FILENO_IMPOSSIBLE 0 /**< log file's numbering starts at 1 */
#define LOG_OFFSET_IMPOSSIBLE 0 /**< log always has a header */
#define LSN_IMPOSSIBLE 0
/* following LSN also is impossible */
#define LSN_ERROR 1
/**
@brief the maximum valid LSN.
......
......@@ -96,7 +96,19 @@ int maria_recover()
maria_in_recovery= TRUE;
if (last_checkpoint_lsn == LSN_IMPOSSIBLE)
from_lsn= first_lsn_in_log();
{
from_lsn= translog_first_theoretical_lsn();
/*
as far as we have not yet any checkpoint then the very first
log file should be present.
*/
DBUG_ASSERT(from_lsn != LSN_IMPOSSIBLE);
/*
@todo process eroror of getting checkpoint
if (from_lsn == ERROR_LSN)
...
*/
}
else
{
DBUG_ASSERT(0); /* not yet implemented */
......
......@@ -85,7 +85,12 @@ int main(int argc, char **argv)
if (opt_only_display)
printf("You are using --only-display, NOTHING will be written to disk\n");
lsn= first_lsn_in_log(); /* LSN could be also --start-from-lsn=# */
/* LSN could be also --start-from-lsn=# */
lsn= translog_first_theoretical_lsn();
/*
@todo process LSN_IMPOSSIBLE and LSN_ERROR values of
translog_first_theoretical_lsn()
*/
fprintf(stdout, "TRACE of the last maria_read_log\n");
if (maria_apply_log(lsn, opt_display_and_apply, stdout))
......
......@@ -43,7 +43,8 @@ noinst_PROGRAMS = ma_control_file-t trnman-t lockman2-t \
ma_test_loghandler_multithread-t \
ma_test_loghandler_pagecache-t \
ma_test_loghandler_long-t-big \
ma_test_loghandler_noflush-t
ma_test_loghandler_noflush-t \
ma_test_loghandler_first_lsn-t
ma_test_loghandler_t_SOURCES = ma_test_loghandler-t.c ma_maria_log_cleanup.c
ma_test_loghandler_multigroup_t_SOURCES = ma_test_loghandler_multigroup-t.c ma_maria_log_cleanup.c
......@@ -52,6 +53,7 @@ ma_test_loghandler_pagecache_t_SOURCES = ma_test_loghandler_pagecache-t.c ma_mar
ma_test_loghandler_long_t_big_SOURCES = ma_test_loghandler-t.c ma_maria_log_cleanup.c
ma_test_loghandler_long_t_big_CPPFLAGS = -DLONG_LOG_TEST
ma_test_loghandler_noflush_t_SOURCES = ma_test_loghandler_noflush-t.c ma_maria_log_cleanup.c
ma_test_loghandler_first_lsn_t_SOURCES = ma_test_loghandler_first_lsn-t.c ma_maria_log_cleanup.c
ma_pagecache_single_src = ma_pagecache_single.c test_file.c
ma_pagecache_consist_src = ma_pagecache_consist.c test_file.c
......
#include "../maria_def.h"
#include <stdio.h>
#include <errno.h>
#include <tap.h>
#include "../trnman.h"
extern my_bool maria_log_remove();
#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";
int main(int argc __attribute__((unused)), char *argv[])
{
uint pagen;
uchar long_tr_id[6];
PAGECACHE pagecache;
LSN lsn, first_lsn, theor_lsn;
MY_STAT st;
LEX_STRING parts[TRANSLOG_INTERNAL_PARTS + 1];
MY_INIT(argv[0]);
plan(2);
bzero(&pagecache, sizeof(pagecache));
maria_data_root= ".";
if (maria_log_remove())
exit(1);
/* 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.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(TRUE))
{
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);
}
example_loghandler_init();
theor_lsn= translog_first_theoretical_lsn();
if (theor_lsn == 1)
{
fprintf(stderr, "Error reading the first log file.");
translog_destroy();
exit(1);
}
if (theor_lsn == LSN_IMPOSSIBLE)
{
fprintf(stderr, "There is no first log file.");
translog_destroy();
exit(1);
}
first_lsn= translog_first_lsn_in_log();
if (first_lsn != LSN_IMPOSSIBLE)
{
fprintf(stderr, "Incorrect first lsn responce (%lu,0x%lx).",
(ulong) LSN_FILE_NO(first_lsn),
(ulong) LSN_OFFSET(first_lsn));
translog_destroy();
exit(1);
}
ok(1, "Empty log response");
int4store(long_tr_id, 0);
parts[TRANSLOG_INTERNAL_PARTS + 0].str= (char*)long_tr_id;
parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
if (translog_write_record(&lsn,
LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
&dummy_transaction_object, NULL, 6,
TRANSLOG_INTERNAL_PARTS + 1,
parts, NULL))
{
fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
translog_destroy();
exit(1);
}
theor_lsn= translog_first_theoretical_lsn();
if (theor_lsn == 1)
{
fprintf(stderr, "Error reading the first log file\n");
translog_destroy();
exit(1);
}
if (theor_lsn == LSN_IMPOSSIBLE)
{
fprintf(stderr, "There is no first log file\n");
translog_destroy();
exit(1);
}
first_lsn= translog_first_lsn_in_log();
if (first_lsn != theor_lsn)
{
fprintf(stderr, "Incorrect first lsn: (%lu,0x%lx) "
" theoretical first: (%lu,0x%lx)\n",
(ulong) LSN_FILE_NO(first_lsn),
(ulong) LSN_OFFSET(first_lsn),
(ulong) LSN_FILE_NO(theor_lsn),
(ulong) LSN_OFFSET(theor_lsn));
translog_destroy();
exit(1);
}
ok(1, "Full log response");
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));
exit(0);
}
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