1 : /* Copyright (C) 2007 MySQL AB
2 :
3 : This program is free software; you can redistribute it and/or modify
4 : it under the terms of the GNU General Public License as published by
5 : the Free Software Foundation; version 2 of the License.
6 :
7 : This program is distributed in the hope that it will be useful,
8 : but WITHOUT ANY WARRANTY; without even the implied warranty of
9 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 : GNU General Public License for more details.
11 :
12 : You should have received a copy of the GNU General Public License
13 : along with this program; if not, write to the Free Software
14 : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
15 :
16 : #include "maria_def.h"
17 : #include "ma_recovery.h"
18 : #include <my_getopt.h>
19 :
20 : #define LOG_FLAGS 0
21 :
22 : static const char *load_default_groups[]= { "maria_read_log",0 };
23 : static void get_options(int *argc,char * * *argv);
24 : #ifndef DBUG_OFF
25 : #if defined(__WIN__)
26 : const char *default_dbug_option= "d:t:O,\\maria_read_log.trace";
27 : #else
28 : const char *default_dbug_option= "d:t:o,/tmp/maria_read_log.trace";
29 : #endif
30 : #endif /* DBUG_OFF */
31 : static my_bool opt_display_only, opt_apply, opt_apply_undo, opt_silent;
32 : static my_bool opt_check;
33 : static const char *opt_tmpdir;
34 : static ulong opt_page_buffer_size;
35 : static ulonglong opt_start_from_lsn;
36 : static MY_TMPDIR maria_chk_tmpdir;
37 :
38 :
39 : int main(int argc, char **argv)
40 307 : {
41 : LSN lsn;
42 : char **default_argv;
43 : uint warnings_count;
44 307 : MY_INIT(argv[0]);
45 :
46 307 : load_defaults("my", load_default_groups, &argc, &argv);
47 307 : default_argv= argv;
48 307 : maria_data_root= (char *)".";
49 307 : get_options(&argc, &argv);
50 :
51 307 : maria_in_recovery= TRUE;
52 :
53 307 : if (maria_init())
54 : {
55 0 : fprintf(stderr, "Can't init Maria engine (%d)\n", errno);
56 0 : goto err;
57 : }
58 : /* we don't want to create a control file, it MUST exist */
59 307 : if (ma_control_file_open(FALSE, TRUE))
60 : {
61 0 : fprintf(stderr, "Can't open control file (%d)\n", errno);
62 0 : goto err;
63 : }
64 307 : if (last_logno == FILENO_IMPOSSIBLE)
65 : {
66 0 : fprintf(stderr, "Can't find any log\n");
67 0 : goto err;
68 : }
69 307 : if (init_pagecache(maria_pagecache, opt_page_buffer_size, 0, 0,
70 : TRANSLOG_PAGE_SIZE, MY_WME) == 0)
71 : {
72 0 : fprintf(stderr, "Got error in init_pagecache() (errno: %d)\n", errno);
73 0 : goto err;
74 : }
75 : /*
76 : If log handler does not find the "last_logno" log it will return error,
77 : which is good.
78 : But if it finds a log and this log was crashed, it will create a new log,
79 : which is useless. TODO: start log handler in read-only mode.
80 : */
81 307 : if (init_pagecache(maria_log_pagecache,
82 : TRANSLOG_PAGECACHE_SIZE, 0, 0,
83 : TRANSLOG_PAGE_SIZE, MY_WME) == 0 ||
84 : translog_init(maria_data_root, TRANSLOG_FILE_SIZE,
85 : 0, 0, maria_log_pagecache, TRANSLOG_DEFAULT_FLAGS,
86 : opt_display_only))
87 : {
88 0 : fprintf(stderr, "Can't init loghandler (%d)\n", errno);
89 0 : goto err;
90 : }
91 :
92 307 : if (opt_display_only)
93 0 : printf("You are using --display-only, NOTHING will be written to disk\n");
94 :
95 : /* LSN could be also --start-from-lsn=# */
96 307 : lsn= translog_first_lsn_in_log();
97 307 : if (lsn == LSN_ERROR)
98 : {
99 0 : fprintf(stderr, "Opening transaction log failed\n");
100 0 : goto end;
101 : }
102 307 : if (lsn == LSN_IMPOSSIBLE)
103 : {
104 0 : fprintf(stdout, "The transaction log is empty\n");
105 : }
106 307 : fprintf(stdout, "The transaction log starts from lsn (%lu,0x%lx)\n",
107 : LSN_IN_PARTS(lsn));
108 :
109 307 : if (opt_start_from_lsn)
110 : {
111 0 : if (opt_start_from_lsn < (ulonglong) lsn)
112 : {
113 0 : fprintf(stderr, "start_from_lsn is too small. Aborting\n");
114 0 : maria_end();
115 0 : goto err;
116 : }
117 0 : lsn= (LSN) opt_start_from_lsn;
118 0 : fprintf(stdout, "Starting reading log from lsn (%lu,0x%lx)\n",
119 : LSN_IN_PARTS(lsn));
120 : }
121 :
122 307 : fprintf(stdout, "TRACE of the last maria_read_log\n");
123 307 : if (maria_apply_log(lsn, opt_apply ? MARIA_LOG_APPLY :
124 : (opt_check ? MARIA_LOG_CHECK :
125 : MARIA_LOG_DISPLAY_HEADER), opt_silent ? NULL : stdout,
126 : opt_apply_undo, FALSE, FALSE, &warnings_count))
127 307 : goto err;
128 307 : if (warnings_count == 0)
129 307 : fprintf(stdout, "%s: SUCCESS\n", my_progname_short);
130 : else
131 0 : fprintf(stdout, "%s: DOUBTFUL (%u warnings, check previous output)\n",
132 : my_progname_short, warnings_count);
133 :
134 307 : end:
135 307 : maria_end();
136 307 : free_tmpdir(&maria_chk_tmpdir);
137 307 : free_defaults(default_argv);
138 307 : my_end(0);
139 307 : exit(0);
140 : return 0; /* No compiler warning */
141 :
142 0 : err:
143 : /* don't touch anything more, in case we hit a bug */
144 0 : fprintf(stderr, "%s: FAILED\n", my_progname_short);
145 0 : free_tmpdir(&maria_chk_tmpdir);
146 0 : free_defaults(default_argv);
147 0 : exit(1);
148 : }
149 :
150 :
151 : #include "ma_check_standalone.h"
152 :
153 :
154 : static struct my_option my_long_options[] =
155 : {
156 : {"apply", 'a',
157 : "Apply log to tables: modifies tables! you should make a backup first! "
158 : " Displays a lot of information if not run with --silent",
159 : (uchar **) &opt_apply, (uchar **) &opt_apply, 0,
160 : GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
161 : {"check", 'c',
162 : "if --display-only, check if record is fully readable (for debugging)",
163 : (uchar **) &opt_check, (uchar **) &opt_check, 0,
164 : GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
165 : #ifndef DBUG_OFF
166 : {"debug", '#', "Output debug log. Often the argument is 'd:t:o,filename'.",
167 : 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
168 : #endif
169 : {"help", '?', "Display this help and exit.",
170 : 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
171 : {"display-only", 'd', "display brief info read from records' header",
172 : (uchar **) &opt_display_only, (uchar **) &opt_display_only, 0, GET_BOOL,
173 : NO_ARG,0, 0, 0, 0, 0, 0},
174 : {"maria_log_dir_path", 'l',
175 : "Path to the directory where to store transactional log",
176 : (uchar **) &maria_data_root, (uchar **) &maria_data_root, 0,
177 : GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
178 : { "page_buffer_size", 'P', "",
179 : (uchar**) &opt_page_buffer_size, (uchar**) &opt_page_buffer_size, 0,
180 : GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT,
181 : (long) USE_BUFFER_INIT, (long) ~(ulong) 0, (long) MALLOC_OVERHEAD,
182 : (long) IO_SIZE, 0},
183 : { "start_from_lsn", 'o', "Start reading log from this lsn",
184 : (uchar**) &opt_start_from_lsn, (uchar**) &opt_start_from_lsn,
185 : 0, GET_ULL, REQUIRED_ARG, 0, 0, ~(longlong) 0, 0, 0, 0 },
186 : {"silent", 's', "Print less information during apply/undo phase",
187 : (uchar **) &opt_silent, (uchar **) &opt_silent, 0,
188 : GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
189 : {"tmpdir", 't', "Path for temporary files. Multiple paths can be specified, "
190 : "separated by "
191 : #if defined( __WIN__) || defined(__NETWARE__)
192 : "semicolon (;)"
193 : #else
194 : "colon (:)"
195 : #endif
196 : , (uchar**) &opt_tmpdir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
197 : {"undo", 'u', "Apply UNDO records to tables. (disable with --disable-undo)",
198 : (uchar **) &opt_apply_undo, (uchar **) &opt_apply_undo, 0,
199 : GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
200 : {"version", 'V', "Print version and exit.",
201 : 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
202 : { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
203 : };
204 :
205 : #include <help_start.h>
206 :
207 : static void print_version(void)
208 0 : {
209 0 : VOID(printf("%s Ver 1.2 for %s on %s\n",
210 : my_progname_short, SYSTEM_TYPE, MACHINE_TYPE));
211 : NETWARE_SET_SCREEN_MODE(1);
212 : }
213 :
214 :
215 : static void usage(void)
216 0 : {
217 0 : print_version();
218 0 : puts("Copyright (C) 2007 MySQL AB");
219 0 : puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,");
220 0 : puts("and you are welcome to modify and redistribute it under the GPL license\n");
221 :
222 0 : puts("Display and apply log records from a MARIA transaction log");
223 0 : puts("found in the current directory (for now)");
224 : #ifndef IDENTICAL_PAGES_AFTER_RECOVERY
225 0 : puts("\nNote: Maria is compiled without -DIDENTICAL_PAGES_AFTER_RECOVERY\n"
226 : "which means that the table files are not byte-to-byte identical to\n"
227 : "files created during normal execution. This should be ok, except for\n"
228 : "test scripts that tries to compare files before and after recovery.");
229 : #endif
230 0 : VOID(printf("\nUsage: %s OPTIONS\n", my_progname_short));
231 0 : puts("You need to use one of -d or -a");
232 0 : my_print_help(my_long_options);
233 0 : print_defaults("my", load_default_groups);
234 0 : my_print_variables(my_long_options);
235 : }
236 :
237 : #include <help_end.h>
238 :
239 : static my_bool
240 : get_one_option(int optid __attribute__((unused)),
241 : const struct my_option *opt __attribute__((unused)),
242 : char *argument __attribute__((unused)))
243 314 : {
244 314 : switch (optid) {
245 : case '?':
246 0 : usage();
247 0 : exit(0);
248 : case 'V':
249 0 : print_version();
250 0 : exit(0);
251 : #ifndef DBUG_OFF
252 : case '#':
253 0 : DBUG_SET_INITIAL(argument ? argument : default_dbug_option);
254 : break;
255 : #endif
256 : }
257 314 : return 0;
258 : }
259 :
260 : static void get_options(int *argc,char ***argv)
261 307 : {
262 : int ho_error;
263 :
264 307 : if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
265 0 : exit(ho_error);
266 :
267 307 : if (!opt_apply)
268 0 : opt_apply_undo= FALSE;
269 :
270 307 : if (((opt_display_only + opt_apply) != 1) || (*argc > 0))
271 : {
272 0 : usage();
273 0 : exit(1);
274 : }
275 307 : if (init_tmpdir(&maria_chk_tmpdir, opt_tmpdir))
276 0 : exit(1);
277 307 : maria_tmpdir= &maria_chk_tmpdir;
278 : }
|