mirror of
https://github.com/MariaDB/server.git
synced 2025-02-02 03:51:50 +01:00
Implement recover. This version can scan the log, but doesn't actually recover. Addresses #27
git-svn-id: file:///svn/tokudb@727 c7de825b-a66e-492c-adef-691d508d4ae1
This commit is contained in:
parent
85336f49f3
commit
e17f972093
7 changed files with 133 additions and 27 deletions
|
@ -49,6 +49,9 @@ logdump: LDFLAGS+=-lz
|
||||||
logdump: log-internal.h brttypes.h yerror.h log.h kv-pair.h
|
logdump: log-internal.h brttypes.h yerror.h log.h kv-pair.h
|
||||||
logdump: log_code.o memory.o log.o brt-serialize.o hashtable.o pma.o ybt.o fingerprint.o mempool.o primes.o
|
logdump: log_code.o memory.o log.o brt-serialize.o hashtable.o pma.o ybt.o fingerprint.o mempool.o primes.o
|
||||||
|
|
||||||
|
recover: LDFLAGS+=-lz
|
||||||
|
recover: log_code.o memory.o log.o brt-serialize.o hashtable.o pma.o ybt.o fingerprint.o mempool.o primes.o
|
||||||
|
|
||||||
log_code.o: log_header.h
|
log_code.o: log_header.h
|
||||||
log_code.c log_header.h: logformat
|
log_code.c log_header.h: logformat
|
||||||
./logformat
|
./logformat
|
||||||
|
|
|
@ -18,6 +18,7 @@ struct tokulogger {
|
||||||
};
|
};
|
||||||
|
|
||||||
int tokulogger_find_next_unused_log_file(const char *directory, long long *result);
|
int tokulogger_find_next_unused_log_file(const char *directory, long long *result);
|
||||||
|
int tokulogger_find_logfiles (const char *directory, int *n_resultsp, char ***resultp);
|
||||||
|
|
||||||
enum lt_command {
|
enum lt_command {
|
||||||
LT_COMMIT = 'C',
|
LT_COMMIT = 'C',
|
||||||
|
|
50
newbrt/log.c
50
newbrt/log.c
|
@ -33,6 +33,33 @@ int tokulogger_find_next_unused_log_file(const char *directory, long long *resul
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tokulogger_find_logfiles (const char *directory, int *n_resultsp, char ***resultp) {
|
||||||
|
int result_limit=1;
|
||||||
|
int n_results=0;
|
||||||
|
char **MALLOC_N(result_limit, result);
|
||||||
|
struct dirent *de;
|
||||||
|
DIR *d=opendir(directory);
|
||||||
|
if (d==0) return errno;
|
||||||
|
int dirnamelen = strlen(directory);
|
||||||
|
while ((de=readdir(d))) {
|
||||||
|
if (de==0) return errno;
|
||||||
|
long long thisl;
|
||||||
|
int r = sscanf(de->d_name, "log%llu.tokulog", &thisl);
|
||||||
|
if (r!=1) continue; // Skip over non-log files.
|
||||||
|
if (n_results>=result_limit) {
|
||||||
|
result_limit*=2;
|
||||||
|
result = toku_realloc(result, result_limit*sizeof(*result));
|
||||||
|
}
|
||||||
|
int fnamelen = dirnamelen + strlen(de->d_name) + 2; // One for the slash and one for the trailing NUL.
|
||||||
|
char *fname = toku_malloc(fnamelen);
|
||||||
|
snprintf(fname, fnamelen, "%s/%s", directory, de->d_name);
|
||||||
|
result[n_results++] = fname;
|
||||||
|
}
|
||||||
|
*n_resultsp = n_results;
|
||||||
|
*resultp = result;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int tokulogger_create_and_open_logger (const char *directory, TOKULOGGER *resultp) {
|
int tokulogger_create_and_open_logger (const char *directory, TOKULOGGER *resultp) {
|
||||||
TAGMALLOC(TOKULOGGER, result);
|
TAGMALLOC(TOKULOGGER, result);
|
||||||
if (result==0) return -1;
|
if (result==0) return -1;
|
||||||
|
@ -556,3 +583,26 @@ int toku_logprint_LOGGEDBRTHEADER (FILE *outf, FILE *inf, const char *fieldname,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int read_and_print_logmagic (FILE *f, u_int32_t *versionp) {
|
||||||
|
{
|
||||||
|
char magic[8];
|
||||||
|
int r=fread(magic, 1, 8, f);
|
||||||
|
if (r!=8) {
|
||||||
|
return DB_BADFORMAT;
|
||||||
|
}
|
||||||
|
if (memcmp(magic, "tokulogg", 8)!=0) {
|
||||||
|
return DB_BADFORMAT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int version;
|
||||||
|
int r=fread(&version, 1, 4, f);
|
||||||
|
if (r!=4) {
|
||||||
|
return DB_BADFORMAT;
|
||||||
|
}
|
||||||
|
printf("tokulog v.%d\n", ntohl(version));
|
||||||
|
*versionp=ntohl(version);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -49,4 +49,6 @@ int toku_logprint_u_int8_t (FILE *outf, FILE *inf, const char *fieldname,
|
||||||
int toku_logprint_u_int32_t (FILE *outf, FILE *inf, const char *fieldname, u_int32_t *crc, u_int32_t *len);
|
int toku_logprint_u_int32_t (FILE *outf, FILE *inf, const char *fieldname, u_int32_t *crc, u_int32_t *len);
|
||||||
int toku_logprint_LOGGEDBRTHEADER (FILE *outf, FILE *inf, const char *fieldname, u_int32_t *crc, u_int32_t *len);
|
int toku_logprint_LOGGEDBRTHEADER (FILE *outf, FILE *inf, const char *fieldname, u_int32_t *crc, u_int32_t *len);
|
||||||
|
|
||||||
|
int read_and_print_logmagic (FILE *f, u_int32_t *version);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -117,35 +117,13 @@ void transcribe_header (void) {
|
||||||
printf("}");
|
printf("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_and_print_magic (void) {
|
|
||||||
{
|
|
||||||
char magic[8];
|
|
||||||
int r=fread(magic, 1, 8, stdin);
|
|
||||||
if (r!=8) {
|
|
||||||
fprintf(stderr, "Couldn't read the magic\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (memcmp(magic, "tokulogg", 8)!=0) {
|
|
||||||
fprintf(stderr, "Magic is wrong.\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
int version;
|
|
||||||
int r=fread(&version, 1, 4, stdin);
|
|
||||||
if (r!=4) {
|
|
||||||
fprintf(stderr, "Couldn't read the version\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
printf("tokulog v.%d\n", ntohl(version));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void newmain (int count) {
|
static void newmain (int count) {
|
||||||
int i;
|
int i;
|
||||||
read_and_print_magic();
|
u_int32_t version;
|
||||||
|
int r = read_and_print_logmagic(stdin, &version);
|
||||||
|
assert(r==0);
|
||||||
for (i=0; i!=count; i++) {
|
for (i=0; i!=count; i++) {
|
||||||
int r = toku_logprint_one_record(stdout, stdin);
|
r = toku_logprint_one_record(stdout, stdin);
|
||||||
if (r==EOF) break;
|
if (r==EOF) break;
|
||||||
if (r!=0) {
|
if (r!=0) {
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
@ -158,7 +136,9 @@ static void newmain (int count) {
|
||||||
static void oldmain (int count) {
|
static void oldmain (int count) {
|
||||||
int cmd;
|
int cmd;
|
||||||
int i;
|
int i;
|
||||||
read_and_print_magic();
|
u_int32_t version;
|
||||||
|
int r = read_and_print_logmagic(stdin, &version);
|
||||||
|
assert(r==0);
|
||||||
for (i=0;
|
for (i=0;
|
||||||
i!=count && (crc=0,actual_len=0,cmd=get_char())!=EOF;
|
i!=count && (crc=0,actual_len=0,cmd=get_char())!=EOF;
|
||||||
i++) {
|
i++) {
|
||||||
|
|
|
@ -108,6 +108,12 @@ void generate_log_struct (void) {
|
||||||
fprintf(hf, " %-16s len;\n", "u_int32_t");
|
fprintf(hf, " %-16s len;\n", "u_int32_t");
|
||||||
fprintf(hf, "};\n");
|
fprintf(hf, "};\n");
|
||||||
}));
|
}));
|
||||||
|
fprintf(hf, "struct log_entry {\n");
|
||||||
|
fprintf(hf, " enum lt_cmd cmd;\n");
|
||||||
|
fprintf(hf, " union {\n");
|
||||||
|
DO_LOGTYPES(lt, fprintf(hf," struct logtype_%s %s;\n", lt->name, lt->name));
|
||||||
|
fprintf(hf, " } u;\n");
|
||||||
|
fprintf(hf, "};\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_log_writer (void) {
|
void generate_log_writer (void) {
|
||||||
|
@ -166,6 +172,20 @@ void generate_log_reader (void) {
|
||||||
fprintf(cf, " return 0;\n");
|
fprintf(cf, " return 0;\n");
|
||||||
fprintf(cf, "}\n\n");
|
fprintf(cf, "}\n\n");
|
||||||
}));
|
}));
|
||||||
|
fprintf2(cf, hf, "int tokulog_fread (FILE *infile, struct log_entry *le)");
|
||||||
|
fprintf(hf, ";\n");
|
||||||
|
fprintf(cf, " {\n");
|
||||||
|
fprintf(cf, " int cmd=fgetc(infile);\n");
|
||||||
|
fprintf(cf, " if (cmd==EOF) return EOF;\n");
|
||||||
|
fprintf(cf, " le->cmd=cmd;\n");
|
||||||
|
fprintf(cf, " switch ((enum lt_cmd)cmd) {\n");
|
||||||
|
DO_LOGTYPES(lt, ({
|
||||||
|
fprintf(cf, " case LT_%s:\n", lt->name);
|
||||||
|
fprintf(cf, " return tokulog_fread_%s (infile, &le->u.%s, cmd);\n", lt->name, lt->name);
|
||||||
|
}));
|
||||||
|
fprintf(cf, " };\n");
|
||||||
|
fprintf(cf, " return DB_BADFORMAT;\n"); // Should read past the record using the len field.
|
||||||
|
fprintf(cf, "}\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_logprint (void) {
|
void generate_logprint (void) {
|
||||||
|
|
50
newbrt/recover.c
Normal file
50
newbrt/recover.c
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/* Recover an env. The logs are in argv[1]. The new database is created in the cwd. */
|
||||||
|
|
||||||
|
// Test:
|
||||||
|
// cd ../src/tests/tmpdir
|
||||||
|
// ../../../newbrt/recover ../dir.test_log2.c.tdb
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "log_header.h"
|
||||||
|
#include "log-internal.h"
|
||||||
|
|
||||||
|
int main (int argc, char *argv[]) {
|
||||||
|
const char *dir;
|
||||||
|
int r;
|
||||||
|
assert(argc==2);
|
||||||
|
dir = argv[1];
|
||||||
|
int n_logfiles;
|
||||||
|
char **logfiles;
|
||||||
|
r = tokulogger_find_logfiles(dir, &n_logfiles, &logfiles);
|
||||||
|
if (r!=0) exit(1);
|
||||||
|
int i;
|
||||||
|
for (i=0; i<n_logfiles; i++) {
|
||||||
|
fprintf(stderr, "Opening %s\n", logfiles[i]);
|
||||||
|
FILE *f = fopen(logfiles[i], "r");
|
||||||
|
struct log_entry le;
|
||||||
|
u_int32_t version;
|
||||||
|
r=read_and_print_logmagic(f, &version);
|
||||||
|
assert(r==0 && version==0);
|
||||||
|
while ((r = tokulog_fread(f, &le))==0) {
|
||||||
|
printf("Got cmd %c\n", le.cmd);
|
||||||
|
}
|
||||||
|
if (r!=EOF) {
|
||||||
|
if (r==DB_BADFORMAT) {
|
||||||
|
fprintf(stderr, "Bad log format\n");
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Huh? %s\n", strerror(r));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
for (i=0; i<n_logfiles; i++) {
|
||||||
|
toku_free(logfiles[i]);
|
||||||
|
}
|
||||||
|
toku_free(logfiles);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue