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 <my_global.h>
40 #include "logger/log-internal.h"
41 #include "logger/logcursor.h"
42 #include "logger/logfilemgr.h"
43 
44 // for now, implement with singlely-linked-list
45 //   first = oldest  (delete from beginning)
46 //   last  = newest  (add to end)
47 
48 struct lfm_entry {
49     TOKULOGFILEINFO lf_info;
50     struct lfm_entry *next;
51 };
52 
53 struct toku_logfilemgr {
54     struct lfm_entry *first;
55     struct lfm_entry *last;
56     int n_entries;
57 };
58 
toku_logfilemgr_create(TOKULOGFILEMGR * lfm)59 int toku_logfilemgr_create(TOKULOGFILEMGR *lfm) {
60     // malloc a logfilemgr
61     TOKULOGFILEMGR XMALLOC(mgr);
62     mgr->first = NULL;
63     mgr->last = NULL;
64     mgr->n_entries = 0;
65     *lfm = mgr;
66     return 0;
67 }
68 
toku_logfilemgr_destroy(TOKULOGFILEMGR * lfm)69 int toku_logfilemgr_destroy(TOKULOGFILEMGR *lfm) {
70     int r=0;
71     if ( *lfm != NULL ) { // be tolerant of being passed a NULL
72         TOKULOGFILEMGR mgr = *lfm;
73         while ( mgr->n_entries > 0 ) {
74             toku_logfilemgr_delete_oldest_logfile_info(mgr);
75         }
76         toku_free(*lfm);
77         *lfm = NULL;
78     }
79     return r;
80 }
81 
toku_logfilemgr_init(TOKULOGFILEMGR lfm,const char * log_dir,TXNID * last_xid_if_clean_shutdown)82 int toku_logfilemgr_init(TOKULOGFILEMGR lfm, const char *log_dir, TXNID *last_xid_if_clean_shutdown) {
83     invariant_notnull(lfm);
84     invariant_notnull(last_xid_if_clean_shutdown);
85 
86     int r;
87     int n_logfiles;
88     char **logfiles;
89     r = toku_logger_find_logfiles(log_dir, &logfiles, &n_logfiles);
90     if (r!=0)
91         return r;
92 
93     TOKULOGCURSOR cursor;
94     struct log_entry *entry;
95     TOKULOGFILEINFO lf_info;
96     long long index = -1;
97     char *basename;
98     LSN tmp_lsn = {0};
99     TXNID last_xid = TXNID_NONE;
100     for(int i=0;i<n_logfiles;i++){
101         XMALLOC(lf_info);
102         // find the index
103 	// basename is the filename of the i-th logfile
104         basename = strrchr(logfiles[i], '/') + 1;
105         int version;
106         r = sscanf(basename, "log%lld.tokulog%d", &index, &version);
107         assert(r==2);  // found index and version
108         assert(version>=TOKU_LOG_MIN_SUPPORTED_VERSION);
109         assert(version<=TOKU_LOG_VERSION);
110         lf_info->index = index;
111         lf_info->version = version;
112         // find last LSN in logfile
113         r = toku_logcursor_create_for_file(&cursor, log_dir, basename);
114         if (r!=0) {
115             return r;
116         }
117         r = toku_logcursor_last(cursor, &entry);  // set "entry" to last log entry in logfile
118         if (r == 0) {
119             lf_info->maxlsn = toku_log_entry_get_lsn(entry);
120 
121             invariant(lf_info->maxlsn.lsn >= tmp_lsn.lsn);
122             tmp_lsn = lf_info->maxlsn;
123             if (entry->cmd == LT_shutdown) {
124                 last_xid = entry->u.shutdown.last_xid;
125             } else {
126                 last_xid = TXNID_NONE;
127             }
128         }
129         else {
130             lf_info->maxlsn = tmp_lsn; // handle empty logfile (no LSN in file) case
131         }
132 
133         // add to logfilemgr
134         toku_logfilemgr_add_logfile_info(lfm, lf_info);
135         toku_logcursor_destroy(&cursor);
136     }
137     toku_logger_free_logfiles(logfiles, n_logfiles);
138     *last_xid_if_clean_shutdown = last_xid;
139     return 0;
140 }
141 
toku_logfilemgr_num_logfiles(TOKULOGFILEMGR lfm)142 int toku_logfilemgr_num_logfiles(TOKULOGFILEMGR lfm) {
143     assert(lfm);
144     return lfm->n_entries;
145 }
146 
toku_logfilemgr_add_logfile_info(TOKULOGFILEMGR lfm,TOKULOGFILEINFO lf_info)147 int toku_logfilemgr_add_logfile_info(TOKULOGFILEMGR lfm, TOKULOGFILEINFO lf_info) {
148     assert(lfm);
149     struct lfm_entry *XMALLOC(entry);
150     entry->lf_info = lf_info;
151     entry->next = NULL;
152     if ( lfm->n_entries != 0 )
153         lfm->last->next = entry;
154     lfm->last = entry;
155     lfm->n_entries++;
156     if (lfm->n_entries == 1 ) {
157         lfm->first = lfm->last;
158     }
159     return 0;
160 }
161 
toku_logfilemgr_get_oldest_logfile_info(TOKULOGFILEMGR lfm)162 TOKULOGFILEINFO toku_logfilemgr_get_oldest_logfile_info(TOKULOGFILEMGR lfm) {
163     assert(lfm);
164     return lfm->first->lf_info;
165 }
166 
toku_logfilemgr_delete_oldest_logfile_info(TOKULOGFILEMGR lfm)167 void toku_logfilemgr_delete_oldest_logfile_info(TOKULOGFILEMGR lfm) {
168     assert(lfm);
169     if ( lfm->n_entries > 0 ) {
170         struct lfm_entry *entry = lfm->first;
171         toku_free(entry->lf_info);
172         lfm->first = entry->next;
173         toku_free(entry);
174         lfm->n_entries--;
175         if ( lfm->n_entries == 0 ) {
176             lfm->last = lfm->first = NULL;
177         }
178     }
179 }
180 
toku_logfilemgr_get_last_lsn(TOKULOGFILEMGR lfm)181 LSN toku_logfilemgr_get_last_lsn(TOKULOGFILEMGR lfm) {
182     assert(lfm);
183     if ( lfm->n_entries == 0 ) {
184         LSN lsn;
185         lsn.lsn = 0;
186         return lsn;
187     }
188     return lfm->last->lf_info->maxlsn;
189 }
190 
toku_logfilemgr_update_last_lsn(TOKULOGFILEMGR lfm,LSN lsn)191 void toku_logfilemgr_update_last_lsn(TOKULOGFILEMGR lfm, LSN lsn) {
192     assert(lfm);
193     assert(lfm->last!=NULL);
194     lfm->last->lf_info->maxlsn = lsn;
195 }
196 
toku_logfilemgr_print(TOKULOGFILEMGR lfm)197 void toku_logfilemgr_print(TOKULOGFILEMGR lfm) {
198     assert(lfm);
199     printf("toku_logfilemgr_print [%p] : %d entries \n", lfm, lfm->n_entries);
200     struct lfm_entry *entry = lfm->first;
201     for (int i=0;i<lfm->n_entries;i++) {
202         printf("  entry %d : index = %" PRId64 ", maxlsn = %" PRIu64 "\n", i, entry->lf_info->index, entry->lf_info->maxlsn.lsn);
203         entry = entry->next;
204     }
205 }
206