summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorunknown <bell@desktop.sanja.is.com.ua>2007-08-13 22:54:29 +0300
committerunknown <bell@desktop.sanja.is.com.ua>2007-08-13 22:54:29 +0300
commit4cf6756eb0f29618646e2eadbd62804d81ff6a79 (patch)
tree4b5edc3771ab3f311a2bcb4094379f7d4e1d222e /storage
parentfddf505081ac6984bbf8f7b1fd7a4bbc890ad35a (diff)
downloadmariadb-git-4cf6756eb0f29618646e2eadbd62804d81ff6a79.tar.gz
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''
Diffstat (limited to 'storage')
-rw-r--r--storage/maria/ma_checkpoint.c2
-rw-r--r--storage/maria/ma_loghandler.c120
-rw-r--r--storage/maria/ma_loghandler.h3
-rw-r--r--storage/maria/ma_loghandler_lsn.h2
-rw-r--r--storage/maria/ma_recovery.c14
-rw-r--r--storage/maria/maria_read_log.c7
-rw-r--r--storage/maria/unittest/Makefile.am4
-rw-r--r--storage/maria/unittest/ma_test_loghandler_first_lsn-t.c150
8 files changed, 294 insertions, 8 deletions
diff --git a/storage/maria/ma_checkpoint.c b/storage/maria/ma_checkpoint.c
index b23d077897f..42b6c961b41 100644
--- a/storage/maria/ma_checkpoint.c
+++ b/storage/maria/ma_checkpoint.c
@@ -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)
/*
diff --git a/storage/maria/ma_loghandler.c b/storage/maria/ma_loghandler.c
index 22c49d61c91..1bd6d803064 100644
--- a/storage/maria/ma_loghandler.c
+++ b/storage/maria/ma_loghandler.c
@@ -5977,12 +5977,126 @@ 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]]));
}
diff --git a/storage/maria/ma_loghandler.h b/storage/maria/ma_loghandler.h
index db3d43e39f4..4bc4ed1fff9 100644
--- a/storage/maria/ma_loghandler.h
+++ b/storage/maria/ma_loghandler.h
@@ -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
diff --git a/storage/maria/ma_loghandler_lsn.h b/storage/maria/ma_loghandler_lsn.h
index 9e1c4632fb0..df41ceec7c8 100644
--- a/storage/maria/ma_loghandler_lsn.h
+++ b/storage/maria/ma_loghandler_lsn.h
@@ -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.
diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c
index 6ed47533fef..5ad8115be46 100644
--- a/storage/maria/ma_recovery.c
+++ b/storage/maria/ma_recovery.c
@@ -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 */
diff --git a/storage/maria/maria_read_log.c b/storage/maria/maria_read_log.c
index c594fe20490..7c344d5f25d 100644
--- a/storage/maria/maria_read_log.c
+++ b/storage/maria/maria_read_log.c
@@ -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))
diff --git a/storage/maria/unittest/Makefile.am b/storage/maria/unittest/Makefile.am
index 2110a7a5d04..d544ecadb7f 100644
--- a/storage/maria/unittest/Makefile.am
+++ b/storage/maria/unittest/Makefile.am
@@ -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
diff --git a/storage/maria/unittest/ma_test_loghandler_first_lsn-t.c b/storage/maria/unittest/ma_test_loghandler_first_lsn-t.c
new file mode 100644
index 00000000000..6f9354ec94b
--- /dev/null
+++ b/storage/maria/unittest/ma_test_loghandler_first_lsn-t.c
@@ -0,0 +1,150 @@
+#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);
+}