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 | |
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 | |
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 | |
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 | |
142 | int toku_logfilemgr_num_logfiles(TOKULOGFILEMGR lfm) { |
143 | assert(lfm); |
144 | return lfm->n_entries; |
145 | } |
146 | |
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 | |
162 | TOKULOGFILEINFO toku_logfilemgr_get_oldest_logfile_info(TOKULOGFILEMGR lfm) { |
163 | assert(lfm); |
164 | return lfm->first->lf_info; |
165 | } |
166 | |
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 | |
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 | |
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 | |
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 | |