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