Commit 1e73169a authored by unknown's avatar unknown

WL#3072 - Maria recovery

fixes for build failures; copyrights; small bugfixes and comments


mysys/Makefile.am:
  missing .h breaks building from tarball
storage/maria/ma_loghandler.c:
  applying Serg's bugfix of trnman_new_trid() to translog_assign_id_to_share()
storage/maria/ma_loghandler.h:
  copyright
storage/maria/ma_loghandler_lsn.h:
  copyright
storage/maria/maria_read_log.c:
  fix for compiler warnings. Comments.
  Close tables when program ends.
parent 79672e8c
...@@ -20,7 +20,7 @@ INCLUDES = @ZLIB_INCLUDES@ -I$(top_builddir)/include \ ...@@ -20,7 +20,7 @@ INCLUDES = @ZLIB_INCLUDES@ -I$(top_builddir)/include \
-I$(top_srcdir)/include -I$(srcdir) -I$(top_srcdir)/include -I$(srcdir)
pkglib_LIBRARIES = libmysys.a pkglib_LIBRARIES = libmysys.a
LDADD = libmysys.a $(top_builddir)/strings/libmystrings.a $(top_builddir)/dbug/libdbug.a LDADD = libmysys.a $(top_builddir)/strings/libmystrings.a $(top_builddir)/dbug/libdbug.a
noinst_HEADERS = mysys_priv.h my_static.h noinst_HEADERS = mysys_priv.h my_static.h my_safehash.h
libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \
mf_path.c mf_loadpath.c my_file.c \ mf_path.c mf_loadpath.c my_file.c \
my_open.c my_create.c my_dup.c my_seek.c my_read.c \ my_open.c my_create.c my_dup.c my_seek.c my_read.c \
......
...@@ -177,7 +177,6 @@ my_bool translog_inited= 0; ...@@ -177,7 +177,6 @@ my_bool translog_inited= 0;
#include <my_atomic.h> #include <my_atomic.h>
/* an array that maps id of a MARIA_SHARE to this MARIA_SHARE */ /* an array that maps id of a MARIA_SHARE to this MARIA_SHARE */
static MARIA_SHARE **id_to_share= NULL; static MARIA_SHARE **id_to_share= NULL;
#define SHARE_ID_MAX 65535 /* array's size */
/* lock for id_to_share */ /* lock for id_to_share */
static my_atomic_rwlock_t LOCK_id_to_share; static my_atomic_rwlock_t LOCK_id_to_share;
...@@ -2282,8 +2281,8 @@ my_bool translog_init(const char *directory, ...@@ -2282,8 +2281,8 @@ my_bool translog_init(const char *directory,
structures for generating 2-byte ids: structures for generating 2-byte ids:
*/ */
my_atomic_rwlock_init(&LOCK_id_to_share); my_atomic_rwlock_init(&LOCK_id_to_share);
id_to_share= (MARIA_SHARE **) my_malloc(SHARE_ID_MAX*sizeof(MARIA_SHARE*), id_to_share= (MARIA_SHARE **) my_malloc(SHARE_ID_MAX * sizeof(MARIA_SHARE*),
MYF(MY_WME|MY_ZEROFILL)); MYF(MY_WME | MY_ZEROFILL));
if (unlikely(!id_to_share)) if (unlikely(!id_to_share))
DBUG_RETURN(1); DBUG_RETURN(1);
id_to_share--; /* min id is 1 */ id_to_share--; /* min id is 1 */
...@@ -5682,21 +5681,23 @@ int translog_assign_id_to_share(MARIA_SHARE *share, TRN *trn) ...@@ -5682,21 +5681,23 @@ int translog_assign_id_to_share(MARIA_SHARE *share, TRN *trn)
if (likely(share->id == 0)) if (likely(share->id == 0))
{ {
/* Inspired by set_short_trid() of trnman.c */ /* Inspired by set_short_trid() of trnman.c */
int i= share->kfile.file % SHARE_ID_MAX + 1; uint i= share->kfile.file % SHARE_ID_MAX + 1;
do
{
my_atomic_rwlock_wrlock(&LOCK_id_to_share); my_atomic_rwlock_wrlock(&LOCK_id_to_share);
/** for ( ; i <= SHARE_ID_MAX ; i++) /* the range is [1..SHARE_ID_MAX] */
@todo RECOVERY BUG: if all slots are used, and we're using rwlocks
above, we will never exit the loop. To be discussed with Serg.
*/
for ( ; ; i= i % SHARE_ID_MAX + 1) /* the range is [1..SHARE_ID_MAX] */
{ {
void *tmp= NULL; void *tmp= NULL;
if (id_to_share[i] == NULL && if (id_to_share[i] == NULL &&
my_atomic_casptr((void **)&id_to_share[i], &tmp, share)) my_atomic_casptr((void **)&id_to_share[i], &tmp, share))
{
share->id= (uint16)i;
break; break;
} }
}
my_atomic_rwlock_wrunlock(&LOCK_id_to_share); my_atomic_rwlock_wrunlock(&LOCK_id_to_share);
share->id= (uint16)i; i= 1; /* scan the whole array */
} while (share->id == 0);
DBUG_PRINT("info", ("id_to_share: 0x%lx -> %u", (ulong)share, i)); DBUG_PRINT("info", ("id_to_share: 0x%lx -> %u", (ulong)share, i));
LSN lsn; LSN lsn;
LEX_STRING log_array[TRANSLOG_INTERNAL_PARTS + 2]; LEX_STRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
......
// TODO copyright /* Copyright (C) 2007 MySQL AB & Sanja Belkin
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef _ma_loghandler_h #ifndef _ma_loghandler_h
#define _ma_loghandler_h #define _ma_loghandler_h
...@@ -251,6 +264,9 @@ extern my_bool translog_inited; ...@@ -251,6 +264,9 @@ extern my_bool translog_inited;
all the rest added because of recovery; should we make all the rest added because of recovery; should we make
ma_loghandler_for_recovery.h ? ma_loghandler_for_recovery.h ?
*/ */
#define SHARE_ID_MAX 65535 /* array's size */
extern LSN first_lsn_in_log(); extern LSN first_lsn_in_log();
/* record parts descriptor */ /* record parts descriptor */
......
/* Copyright (C) 2007 MySQL AB & Sanja Belkin
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef _ma_loghandler_lsn_h #ifndef _ma_loghandler_lsn_h
#define _ma_loghandler_lsn_h #define _ma_loghandler_lsn_h
......
...@@ -48,7 +48,9 @@ static int display_and_apply_record(const LOG_DESC *log_desc, ...@@ -48,7 +48,9 @@ static int display_and_apply_record(const LOG_DESC *log_desc,
#define prototype_exec_hook(R) \ #define prototype_exec_hook(R) \
static int exec_LOGREC_ ## R(const TRANSLOG_HEADER_BUFFER *rec) static int exec_LOGREC_ ## R(const TRANSLOG_HEADER_BUFFER *rec)
prototype_exec_hook(LONG_TRANSACTION_ID); prototype_exec_hook(LONG_TRANSACTION_ID);
#ifdef MARIA_CHECKPOINT
prototype_exec_hook(CHECKPOINT); prototype_exec_hook(CHECKPOINT);
#endif
prototype_exec_hook(REDO_CREATE_TABLE); prototype_exec_hook(REDO_CREATE_TABLE);
prototype_exec_hook(FILE_ID); prototype_exec_hook(FILE_ID);
prototype_exec_hook(REDO_INSERT_ROW_HEAD); prototype_exec_hook(REDO_INSERT_ROW_HEAD);
...@@ -128,7 +130,9 @@ int main(int argc, char **argv) ...@@ -128,7 +130,9 @@ int main(int argc, char **argv)
log_record_type_descriptor[LOGREC_ ## R].record_execute_in_redo_phase= \ log_record_type_descriptor[LOGREC_ ## R].record_execute_in_redo_phase= \
exec_LOGREC_ ## R; exec_LOGREC_ ## R;
install_exec_hook(LONG_TRANSACTION_ID); install_exec_hook(LONG_TRANSACTION_ID);
#ifdef MARIA_CHECKPOINT
install_exec_hook(CHECKPOINT); install_exec_hook(CHECKPOINT);
#endif
install_exec_hook(REDO_CREATE_TABLE); install_exec_hook(REDO_CREATE_TABLE);
install_exec_hook(FILE_ID); install_exec_hook(FILE_ID);
install_exec_hook(REDO_INSERT_ROW_HEAD); install_exec_hook(REDO_INSERT_ROW_HEAD);
...@@ -337,10 +341,11 @@ static void display_record_position(const LOG_DESC *log_desc, ...@@ -337,10 +341,11 @@ static void display_record_position(const LOG_DESC *log_desc,
if number==0, we're going over records which we had already seen and which if number==0, we're going over records which we had already seen and which
form a group, so we indent below the group's end record form a group, so we indent below the group's end record
*/ */
printf("%sRecord #%u LSN (%lu,0x%lx) short_trid %u %s(num_type:%u)\n", printf("%sRec#%u LSN (%lu,0x%lx) short_trid %u %s(num_type:%u) len %lu\n",
number ? "" : " ", number, number ? "" : " ", number,
(ulong) LSN_FILE_NO(rec->lsn), (ulong) LSN_OFFSET(rec->lsn), (ulong) LSN_FILE_NO(rec->lsn), (ulong) LSN_OFFSET(rec->lsn),
rec->short_trid, log_desc->name, rec->type); rec->short_trid, log_desc->name, rec->type,
(ulong)rec->record_length);
} }
...@@ -367,6 +372,7 @@ prototype_exec_hook(LONG_TRANSACTION_ID) ...@@ -367,6 +372,7 @@ prototype_exec_hook(LONG_TRANSACTION_ID)
TrID long_trid= all_active_trans[sid].long_trid; TrID long_trid= all_active_trans[sid].long_trid;
/* abort group of this trn (must be of before a crash) */ /* abort group of this trn (must be of before a crash) */
LSN gslsn= all_active_trans[sid].group_start_lsn; LSN gslsn= all_active_trans[sid].group_start_lsn;
char llbuf[22];
if (gslsn != LSN_IMPOSSIBLE) if (gslsn != LSN_IMPOSSIBLE)
{ {
printf("Group at LSN (%lu,0x%lx) short_trid %u aborted\n", printf("Group at LSN (%lu,0x%lx) short_trid %u aborted\n",
...@@ -378,16 +384,18 @@ prototype_exec_hook(LONG_TRANSACTION_ID) ...@@ -378,16 +384,18 @@ prototype_exec_hook(LONG_TRANSACTION_ID)
LSN ulsn= all_active_trans[sid].undo_lsn; LSN ulsn= all_active_trans[sid].undo_lsn;
if (ulsn != LSN_IMPOSSIBLE) if (ulsn != LSN_IMPOSSIBLE)
{ {
fprintf(stderr, "Found an old transaction long_trid %llu short_trid %u" llstr(long_trid, llbuf);
fprintf(stderr, "Found an old transaction long_trid %s short_trid %u"
" with same short id as this new transaction, and has neither" " with same short id as this new transaction, and has neither"
" committed nor rollback (undo_lsn: (%lu,0x%lx))\n", long_trid, " committed nor rollback (undo_lsn: (%lu,0x%lx))\n", llbuf,
sid, (ulong) LSN_FILE_NO(ulsn), (ulong) LSN_OFFSET(ulsn)); sid, (ulong) LSN_FILE_NO(ulsn), (ulong) LSN_OFFSET(ulsn));
goto err; goto err;
} }
} }
long_trid= uint6korr(rec->header); long_trid= uint6korr(rec->header);
all_active_trans[sid].long_trid= long_trid; all_active_trans[sid].long_trid= long_trid;
printf("Transaction long_trid %lu short_trid %u starts\n", long_trid, sid); llstr(long_trid, llbuf);
printf("Transaction long_trid %s short_trid %u starts\n", llbuf, sid);
goto end; goto end;
err: err:
DBUG_ASSERT(0); DBUG_ASSERT(0);
...@@ -396,11 +404,14 @@ end: ...@@ -396,11 +404,14 @@ end:
return 0; return 0;
} }
#ifdef MARIA_CHECKPOINT
prototype_exec_hook(CHECKPOINT) prototype_exec_hook(CHECKPOINT)
{ {
/* the only checkpoint we care about was found via control file, ignore */ /* the only checkpoint we care about was found via control file, ignore */
return 0; return 0;
} }
#endif
prototype_exec_hook(REDO_CREATE_TABLE) prototype_exec_hook(REDO_CREATE_TABLE)
...@@ -600,9 +611,11 @@ prototype_exec_hook(REDO_INSERT_ROW_HEAD) ...@@ -600,9 +611,11 @@ prototype_exec_hook(REDO_INSERT_ROW_HEAD)
uint16 sid; uint16 sid;
ulonglong page; ulonglong page;
MARIA_HA *info; MARIA_HA *info;
char llbuf[22];
sid= fileid_korr(rec->header); sid= fileid_korr(rec->header);
page= page_korr(rec->header + FILEID_STORE_SIZE); page= page_korr(rec->header + FILEID_STORE_SIZE);
printf("For page %llu of table of short id %u", page, sid); llstr(page, llbuf);
printf("For page %s of table of short id %u", llbuf, sid);
info= all_tables[sid]; info= all_tables[sid];
if (info == NULL) if (info == NULL)
{ {
...@@ -623,6 +636,16 @@ prototype_exec_hook(REDO_INSERT_ROW_HEAD) ...@@ -623,6 +636,16 @@ prototype_exec_hook(REDO_INSERT_ROW_HEAD)
assume we have made no checkpoint). assume we have made no checkpoint).
*/ */
printf(", applying record\n"); printf(", applying record\n");
/*
If REDO's LSN is > page's LSN (read from disk), we are going to modify the
page and change its LSN. The normal runtime code stores the UNDO's LSN
into the page; but here storing the REDO's LSN (rec->lsn) is more
straightforward and should not cause any problem (we are not writing to
the log here, so don't have to "flush up to UNDO's LSN").
If the UNDO's LSN is desired, it can be found, as we saw the UNDO record
before deciding to execute this REDO; UNDO's LSN could simply be stored in
all_trans[rec->short_trid].group_end_lsn for this.
*/
DBUG_ASSERT("Monty" == "this is the place"); DBUG_ASSERT("Monty" == "this is the place");
end: end:
/* as we don't have apply working: */ /* as we don't have apply working: */
...@@ -635,14 +658,15 @@ prototype_exec_hook(COMMIT) ...@@ -635,14 +658,15 @@ prototype_exec_hook(COMMIT)
uint16 sid= rec->short_trid; uint16 sid= rec->short_trid;
TrID long_trid= all_active_trans[sid].long_trid; TrID long_trid= all_active_trans[sid].long_trid;
LSN gslsn= all_active_trans[sid].group_start_lsn; LSN gslsn= all_active_trans[sid].group_start_lsn;
char llbuf[22];
if (long_trid == 0) if (long_trid == 0)
{ {
printf("We don't know about transaction short_trid %u;" printf("We don't know about transaction short_trid %u;"
"it probably committed long ago, forget it\n", sid); "it probably committed long ago, forget it\n", sid);
return 0; return 0;
} }
printf("Transaction long_trid %lu short_trid %u committed", long_trid, sid); llstr(long_trid, llbuf);
printf("Transaction long_trid %s short_trid %u committed", llbuf, sid);
if (gslsn != LSN_IMPOSSIBLE) if (gslsn != LSN_IMPOSSIBLE)
{ {
/* /*
...@@ -671,7 +695,7 @@ prototype_exec_hook(COMMIT) ...@@ -671,7 +695,7 @@ prototype_exec_hook(COMMIT)
/* Just to inform about any aborted groups or unfinished transactions */ /* Just to inform about any aborted groups or unfinished transactions */
static void end_of_redo_phase() static void end_of_redo_phase()
{ {
uint sid; uint sid, unfinished= 0;
for (sid= 0; sid <= SHORT_TRID_MAX; sid++) for (sid= 0; sid <= SHORT_TRID_MAX; sid++)
{ {
TrID long_trid= all_active_trans[sid].long_trid; TrID long_trid= all_active_trans[sid].long_trid;
...@@ -679,8 +703,12 @@ static void end_of_redo_phase() ...@@ -679,8 +703,12 @@ static void end_of_redo_phase()
if (long_trid == 0) if (long_trid == 0)
continue; continue;
if (all_active_trans[sid].undo_lsn != LSN_IMPOSSIBLE) if (all_active_trans[sid].undo_lsn != LSN_IMPOSSIBLE)
printf("Transaction long_trid %lu short_trid %u unfinished\n", {
long_trid, sid); char llbuf[22];
llstr(long_trid, llbuf);
printf("Transaction long_trid %s short_trid %u unfinished\n",
llbuf, sid);
}
if (gslsn != LSN_IMPOSSIBLE) if (gslsn != LSN_IMPOSSIBLE)
{ {
printf("Group at LSN (%lu,0x%lx) short_trid %u aborted\n", printf("Group at LSN (%lu,0x%lx) short_trid %u aborted\n",
...@@ -694,4 +722,20 @@ static void end_of_redo_phase() ...@@ -694,4 +722,20 @@ static void end_of_redo_phase()
*/ */
#endif #endif
} }
/*
We don't close tables if there are some unfinished transactions, because
closing tables normally requires that all unfinished transactions on them
be rolled back.
For example, closing will soon write the state to disk and when doing that
it will think this is a committed state, but it may not be.
*/
if (unfinished == 0)
{
for (sid= 0; sid <= SHORT_TRID_MAX; sid++)
{
MARIA_HA *info= all_tables[sid];
if (info != NULL)
maria_close(info);
}
}
} }
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