2 * Copyright (C) 2018 Cisco Inc.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2,
6 * as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 // @author Shridhar Bhalerao <shbhaler@cisco.com>
24 #include "mb_backup.h"
26 #include "integer_4b_5b.h"
30 DBBackup::DBBackup(const DB &db) : db_ref(db)
32 if(!(db.GetDBOptions() & CONSTS::ACCESS_MODE_WRITER))
33 throw (int) MBError::NOT_ALLOWED;
35 Dict *dict = db_ref.GetDictPtr();
37 throw (int) MBError::NOT_INITIALIZED;
39 header = dict->GetHeaderPtr();
41 throw (int) MBError::NOT_INITIALIZED;
50 void DBBackup::copy_file (const std::string &src_path, const std::string &dest_path,
51 char *buffer, int buffer_size)
53 FILE *fp_read, *fp_write;
55 if ((fp_read = fopen (src_path.c_str(),"rb")) == NULL)
57 Logger::Log(LOG_LEVEL_ERROR, "Backup failed: Could not open file %s", src_path.c_str());
58 throw MBError::OPEN_FAILURE;
60 if ((fp_write = fopen(dest_path.c_str(),"wb")) == NULL)
63 Logger::Log(LOG_LEVEL_ERROR, "Backup failed: Could not open file %s", dest_path.c_str());
64 throw MBError::OPEN_FAILURE;
67 int rval = MBError::SUCCESS;
68 int read_count, write_count;
72 read_count = fread(buffer, buffer_size, 1, fp_read);
74 if(feof(fp_read) && read_count == 0)
78 rval = MBError::READ_ERROR;
82 write_count = fwrite(buffer,buffer_size, 1, fp_write);
85 rval = MBError::WRITE_ERROR;
92 if(rval != MBError::SUCCESS)
94 Logger::Log(LOG_LEVEL_ERROR, "Backup failed %s", MBError::get_error_str(rval));
99 int DBBackup::Backup(const char * bk_dir)
102 throw (int) MBError::INVALID_ARG;
104 std::string bk_header_path = std::string(bk_dir) + "/_mabain_h";
105 if(access(bk_header_path.c_str(), R_OK) == 0)
106 throw (int) MBError::OPEN_FAILURE;
108 if(!db_ref.is_open())
109 throw (int) db_ref.Status();
111 if(header->m_data_offset > MAX_6B_OFFSET || header->m_index_offset > MAX_6B_OFFSET)
112 throw (int) MBError::INVALID_SIZE;
113 if(header->data_block_size == 0 || header->data_block_size % BLOCK_SIZE_ALIGN != 0)
114 throw (int) MBError::INVALID_SIZE;
115 if(header->index_block_size == 0 || header->index_block_size % BLOCK_SIZE_ALIGN != 0)
116 throw (int) MBError::INVALID_SIZE;
120 int num_data_files, num_index_files;
121 // get the number of files from the header: max_bytes/number_of_bytes_per_file
122 num_data_files = (header->m_data_offset/header->data_block_size) + 1;
123 num_index_files = (header->m_index_offset/header->index_block_size) + 1;
125 char *buffer = (char *) malloc(BLOCK_SIZE_ALIGN);
127 throw (int) MBError::NO_MEMORY;
129 // loop through all data files
130 const std::string &orig_dir = db_ref.GetDBDir();
131 std::string read_file_path_base = orig_dir + "/_mabain_d";
132 std::string write_file_path_base = std::string(bk_dir) + "/_mabain_d";
133 std::string read_file_path;
134 std::string write_file_path;
136 for (int i = 0; i < num_data_files; i++)
138 read_file_path = read_file_path_base + std::to_string(i);
139 write_file_path = write_file_path_base + std::to_string(i);
140 copy_file(read_file_path, write_file_path, buffer, BLOCK_SIZE_ALIGN);
143 read_file_path_base = orig_dir + "/_mabain_i";
144 write_file_path_base = std::string(bk_dir) + "/_mabain_i";
145 for (int i = 0; i < num_index_files; i++)
147 read_file_path = read_file_path_base + std::to_string(i);
148 write_file_path = write_file_path_base + std::to_string(i);
149 copy_file(read_file_path, write_file_path, buffer, BLOCK_SIZE_ALIGN);
152 read_file_path = orig_dir + "/_mabain_h";
153 write_file_path = std::string(bk_dir) + "/_mabain_h";
154 //header is size of page_size
155 copy_file(read_file_path, write_file_path, buffer, RollableFile::page_size);
159 //reset number readers/writers in backed up DB.
161 DB db = DB(bk_dir, CONSTS::ACCESS_MODE_READER, 0, 0);
162 rval = db.UpdateNumHandlers(CONSTS::ACCESS_MODE_WRITER, -1);
163 if(rval != MBError::SUCCESS)
164 Logger::Log(LOG_LEVEL_WARN,"failed to reset number of writer for DB %s", bk_dir);
166 rval = db.UpdateNumHandlers(CONSTS::ACCESS_MODE_READER, INT_MIN);
167 if(rval != MBError::SUCCESS)
168 Logger::Log(LOG_LEVEL_WARN,"failed to reset number of writer for DB %s", bk_dir);
170 return MBError::SUCCESS;