1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3 #ident "$Id$"
4 /*======
5 This file is part of PerconaFT.
6
7
8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
9
10 PerconaFT is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License, version 2,
12 as published by the Free Software Foundation.
13
14 PerconaFT is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>.
21
22 ----------------------------------------
23
24 PerconaFT is free software: you can redistribute it and/or modify
25 it under the terms of the GNU Affero General Public License, version 3,
26 as published by the Free Software Foundation.
27
28 PerconaFT is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU Affero General Public License for more details.
32
33 You should have received a copy of the GNU Affero General Public License
34 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>.
35 ======= */
36
37 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
38
39 #include <toku_portability.h>
40 #include <string.h>
41
42 #include "logger/logcursor.h"
43 #include "test.h"
44
45 #if defined(HAVE_LIMITS_H)
46 # include <limits.h>
47 #endif
48 #if defined(HAVE_SYS_SYSLIMITS_H)
49 # include <sys/syslimits.h>
50 #endif
51
52 const char LOGDIR[100] = "./dir.test_logcursor";
53 const int FSYNC = 1;
54 const int NO_FSYNC = 0;
55
56 const char *namea="a.db";
57 const char *nameb="b.db";
58 const char *a="a";
59 const char *b="b";
60
61 const FILENUM fn_aname = {0};
62 const FILENUM fn_bname = {1};
63 BYTESTRING bs_aname, bs_bname;
64 BYTESTRING bs_a, bs_b;
65 BYTESTRING bs_empty;
66
67 static int create_logfiles(void);
68
69 static int test_0 (void);
70 static int test_1 (void);
usage(void)71 static void usage(void) {
72 printf("test_logcursors [OPTIONS]\n");
73 printf("[-v]\n");
74 printf("[-q]\n");
75 }
76
test_main(int argc,const char * argv[])77 int test_main(int argc, const char *argv[]) {
78 int i;
79 for (i=1; i<argc; i++) {
80 const char *arg = argv[i];
81 if (arg[0] != '-')
82 break;
83 if (strcmp(arg, "-v")==0) {
84 verbose++;
85 } else if (strcmp(arg, "-q")==0) {
86 verbose = 0;
87 } else {
88 usage();
89 return 1;
90 }
91 }
92
93 int r = 0;
94 // start from a clean directory
95 char rmrf_msg[100];
96 sprintf(rmrf_msg, "rm -rf %s", LOGDIR);
97 r = system(rmrf_msg);
98 CKERR(r);
99 toku_os_mkdir(LOGDIR, S_IRWXU+S_IRWXG+S_IRWXO);
100 if ( (r=create_logfiles()) !=0 ) return r;
101
102 if ( (r=test_0()) !=0 ) return r;
103 if ( (r=test_1()) !=0 ) return r;
104
105 r = system(rmrf_msg);
106 CKERR(r);
107 return r;
108 }
109
test_0(void)110 int test_0 (void) {
111 int r=0;
112 struct toku_logcursor *cursor;
113 struct log_entry *entry;
114
115 r = toku_logcursor_create(&cursor, LOGDIR); if (verbose) printf("create returns %d\n", r); assert(r==0);
116 r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
117 r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
118 r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
119 r = toku_logcursor_destroy(&cursor); if (verbose) printf("destroy returns %d\n", r); assert(r==0);
120
121 r = toku_logcursor_create(&cursor, LOGDIR); if (verbose) printf("create returns %d\n", r); assert(r==0);
122 r = toku_logcursor_first(cursor, &entry); if (verbose) printf("First Entry = %c\n", entry->cmd); assert(r==0);
123 r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
124 r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
125 r = toku_logcursor_destroy(&cursor); if (verbose) printf("destroy returns %d\n", r); assert(r==0);
126
127 r = toku_logcursor_create(&cursor, LOGDIR); if (verbose) printf("create returns %d\n", r); assert(r==0);
128 r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
129 r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
130 r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
131 r = toku_logcursor_destroy(&cursor); if (verbose) printf("destroy returns %d\n", r); assert(r==0);
132
133 r = toku_logcursor_create(&cursor, LOGDIR); if (verbose) printf("create returns %d\n", r); assert(r==0);
134 r = toku_logcursor_last(cursor, &entry); if (verbose) printf("Last Entry = %c\n", entry->cmd); assert(r==0);
135 r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
136 r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
137 r = toku_logcursor_destroy(&cursor); if (verbose) printf("destroy returns %d\n", r); assert(r==0);
138
139 r = toku_logcursor_create(&cursor, LOGDIR); if (verbose) printf("create returns %d\n", r); assert(r==0);
140 r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
141 r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
142 r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
143 r = toku_logcursor_next(cursor, &entry); assert(r==DB_NOTFOUND);
144 r = toku_logcursor_destroy(&cursor); if (verbose) printf("destroy returns %d\n", r); assert(r==0);
145
146 r = toku_logcursor_create(&cursor, LOGDIR); if (verbose) printf("create returns %d\n", r); assert(r==0);
147 r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
148 r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
149 r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
150 r = toku_logcursor_prev(cursor, &entry); assert(r==DB_NOTFOUND);
151 r = toku_logcursor_destroy(&cursor); if (verbose) printf("destroy returns %d\n", r); assert(r==0);
152
153 r = toku_logcursor_create(&cursor, LOGDIR); if (verbose) printf("create returns %d\n", r); assert(r==0);
154 r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
155 r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
156 r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
157 r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
158 r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0);
159 r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd);
160 if ( verbose) {
161 if ( r == DB_NOTFOUND ) printf("PASS\n");
162 else printf("FAIL\n");
163 }
164 assert(r==DB_NOTFOUND);
165 r = toku_logcursor_destroy(&cursor); if (verbose) printf("destroy returns %d\n", r); assert(r==0);
166
167 return 0;
168 }
169
170 // test per-file version
test_1()171 int test_1 () {
172 int r=0;
173 char logfile[PATH_MAX];
174 sprintf(logfile, "log000000000000.tokulog%d", TOKU_LOG_VERSION);
175
176 struct toku_logcursor *cursor;
177 struct log_entry *entry;
178
179 r = toku_logcursor_create_for_file(&cursor, LOGDIR, logfile);
180 if (verbose) printf("create returns %d\n", r);
181 assert(r==0);
182
183 r = toku_logcursor_last(cursor, &entry);
184 if (verbose) printf("entry = %c\n", entry->cmd);
185 assert(r==0);
186 assert(entry->cmd =='C');
187
188 r = toku_logcursor_destroy(&cursor);
189 if (verbose) printf("destroy returns %d\n", r);
190 assert(r==0);
191
192 return 0;
193 }
194
create_logfiles()195 int create_logfiles() {
196 int r = 0;
197
198 TOKULOGGER logger;
199
200 LSN lsn = {0};
201 TXNID_PAIR txnid = {.parent_id64 = TXNID_NONE, .child_id64 = TXNID_NONE};
202 LSN begin_checkpoint_lsn;
203
204 uint32_t num_fassociate = 0;
205 uint32_t num_xstillopen = 0;
206
207 bs_aname.len = 4; bs_aname.data=(char *)"a.db";
208 bs_bname.len = 4; bs_bname.data=(char *)"b.db";
209 bs_a.len = 2; bs_a.data=(char *)"a";
210 bs_b.len = 2; bs_b.data=(char *)"b";
211 bs_empty.len = 0; bs_empty.data = NULL;
212
213
214 // create and open logger
215 r = toku_logger_create(&logger); assert(r==0);
216 r = toku_logger_open(LOGDIR, logger); assert(r==0);
217
218 // use old x1.tdb test log as basis
219 //xbegin 'b': lsn=1 parenttxnid=0 crc=00005f1f len=29
220 txnid.parent_id64 = 1;
221 toku_log_xbegin(logger, &lsn, NO_FSYNC, txnid, TXNID_PAIR_NONE);
222 //fcreate 'F': lsn=2 txnid=1 filenum=0 fname={len=4 data="a.db"} mode=0777 treeflags=0 crc=18a3d525 len=49
223 toku_log_fcreate(logger, &lsn, NO_FSYNC, NULL, txnid, fn_aname, bs_aname, 0x0777, 0, 0, TOKU_DEFAULT_COMPRESSION_METHOD, 0);
224 //commit 'C': lsn=3 txnid=1 crc=00001f1e len=29
225 toku_log_xcommit(logger, &lsn, FSYNC, NULL, txnid);
226 //xbegin 'b': lsn=4 parenttxnid=0 crc=00000a1f len=29
227 txnid.parent_id64 = 4; // Choosing ids based on old test instead of what should happen now.
228 toku_log_xbegin(logger, &lsn, NO_FSYNC, txnid, TXNID_PAIR_NONE);
229 //fcreate 'F': lsn=5 txnid=4 filenum=1 fname={len=4 data="b.db"} mode=0777 treeflags=0 crc=14a47925 len=49
230 toku_log_fcreate(logger, &lsn, NO_FSYNC, NULL, txnid, fn_bname, bs_bname, 0x0777, 0, 0, TOKU_DEFAULT_COMPRESSION_METHOD, 0);
231 //commit 'C': lsn=6 txnid=4 crc=0000c11e len=29
232 toku_log_xcommit(logger, &lsn, FSYNC, NULL, txnid);
233 //xbegin 'b': lsn=7 parenttxnid=0 crc=0000f91f len=29
234 txnid.parent_id64 = 7; // Choosing ids based on old test instead of what should happen now.
235 toku_log_xbegin(logger, &lsn, NO_FSYNC, txnid, TXNID_PAIR_NONE);
236 //enq_insert 'I': lsn=8 filenum=0 xid=7 key={len=2 data="a\000"} value={len=2 data="b\000"} crc=40b863e4 len=45
237 toku_log_enq_insert(logger, &lsn, NO_FSYNC, NULL, fn_aname, txnid, bs_a, bs_b);
238 //begin_checkpoint 'x': lsn=9 timestamp=1251309957584197 crc=cd067878 len=29
239 toku_log_begin_checkpoint(logger, &begin_checkpoint_lsn, NO_FSYNC, 1251309957584197, 0);
240 //fassociate 'f': lsn=11 filenum=1 fname={len=4 data="b.db"} crc=a7126035 len=33
241 toku_log_fassociate(logger, &lsn, NO_FSYNC, fn_bname, 0, bs_bname, 0);
242 num_fassociate++;
243 //fassociate 'f': lsn=12 filenum=0 fname={len=4 data="a.db"} crc=a70c5f35 len=33
244 toku_log_fassociate(logger, &lsn, NO_FSYNC, fn_aname, 0, bs_aname, 0);
245 num_fassociate++;
246 //xstillopen 's': lsn=10 txnid=7 parent=0 crc=00061816 len=37 <- obsolete
247 {
248 FILENUMS filenums = {0, NULL};
249 toku_log_xstillopen(logger, &lsn, NO_FSYNC, NULL, txnid, TXNID_PAIR_NONE,
250 0, filenums, 0, 0, 0,
251 ROLLBACK_NONE, ROLLBACK_NONE, ROLLBACK_NONE);
252 }
253 num_xstillopen++;
254 //end_checkpoint 'X': lsn=13 txnid=9 timestamp=1251309957586872 crc=cd285c30 len=37
255 toku_log_end_checkpoint(logger, &lsn, FSYNC, begin_checkpoint_lsn, 1251309957586872, num_fassociate, num_xstillopen);
256 //enq_insert 'I': lsn=14 filenum=1 xid=7 key={len=2 data="b\000"} value={len=2 data="a\000"} crc=40388be4 len=45
257 toku_log_enq_insert(logger, &lsn, NO_FSYNC, NULL, fn_bname, txnid, bs_b, bs_a);
258 //commit 'C': lsn=15 txnid=7 crc=00016d1e len=29
259 toku_log_xcommit(logger, &lsn, FSYNC, NULL, txnid);
260
261 // close logger
262 r = toku_logger_close(&logger); assert(r==0);
263 return r;
264 }
265
266