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/*======
5This file is part of PerconaFT.
6
7
8Copyright (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
48struct lfm_entry {
49 TOKULOGFILEINFO lf_info;
50 struct lfm_entry *next;
51};
52
53struct toku_logfilemgr {
54 struct lfm_entry *first;
55 struct lfm_entry *last;
56 int n_entries;
57};
58
59int 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
69int 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
82int 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
142int toku_logfilemgr_num_logfiles(TOKULOGFILEMGR lfm) {
143 assert(lfm);
144 return lfm->n_entries;
145}
146
147int 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
162TOKULOGFILEINFO toku_logfilemgr_get_oldest_logfile_info(TOKULOGFILEMGR lfm) {
163 assert(lfm);
164 return lfm->first->lf_info;
165}
166
167void 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
181LSN 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
191void 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
197void 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