restore.cc
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "restore.h"
00023 #include "tarfile.h"
00024 #include "error.h"
00025 #include <sstream>
00026 #include <iomanip>
00027 #include <iostream>
00028 #include <string.h>
00029 #include <algorithm>
00030
00031 using namespace std;
00032
00033 namespace Barry {
00034
00035 namespace {
00036
00037 int CountFiles(reuse::TarFile &tar,
00038 const Barry::Restore::DBListType &restoreList,
00039 bool default_all_db)
00040 {
00041 int count = 0;
00042 std::string name, last_name;
00043 bool good = false;
00044
00045 while( tar.ReadNextFilenameOnly(name) ) {
00046 std::string::size_type pos = name.rfind('/');
00047 if( pos == std::string::npos )
00048 continue;
00049 std::string dbname = name.substr(0, pos);
00050
00051 if( dbname != last_name ) {
00052 last_name = dbname;
00053 good = (default_all_db && restoreList.size() == 0) ||
00054 restoreList.IsSelected(dbname);
00055 }
00056 if( good )
00057 count++;
00058 }
00059 return count;
00060 }
00061
00062 }
00063
00064
00065
00066
00067
00068
00069 bool Restore::SplitTarPath(const std::string &tarpath,
00070 std::string &dbname,
00071 std::string &dbid_text,
00072 uint8_t &dbrectype,
00073 uint32_t &dbid)
00074 {
00075 std::string::size_type pos = tarpath.rfind('/');
00076 if( pos == std::string::npos )
00077 return false;
00078
00079 dbname = tarpath.substr(0, pos);
00080 dbid_text = tarpath.substr(pos + 1);
00081 if( dbname.size() == 0 || dbid_text.size() == 0 )
00082 return false;
00083
00084 std::istringstream iss(dbid_text);
00085 unsigned int temp;
00086 iss >> std::hex >> dbid >> temp;
00087 dbrectype = (uint8_t) temp;
00088
00089 return true;
00090 }
00091
00092
00093
00094
00095
00096 Restore::Restore(const std::string &tarpath, bool default_all_db)
00097 : m_tarpath(tarpath)
00098 , m_default_all_db(default_all_db)
00099 , m_tar_record_state(RS_EMPTY)
00100 , m_rec_type(0)
00101 , m_unique_id(0)
00102 {
00103 try {
00104 m_tar.reset( new reuse::TarFile(tarpath.c_str(), false,
00105 &reuse::gztar_ops_nonthread, true) );
00106 }
00107 catch( reuse::TarFile::TarError &te ) {
00108 throw Barry::RestoreError(te.what());
00109 }
00110 }
00111
00112 Restore::~Restore()
00113 {
00114 }
00115
00116
00117
00118
00119
00120 bool Restore::IsSelected(const std::string &dbName) const
00121 {
00122
00123 if( m_dbList.size() == 0 )
00124 return m_default_all_db;
00125 else
00126 return m_dbList.IsSelected(dbName);
00127 }
00128
00129
00130
00131
00132
00133 void Restore::AddDB(const std::string &dbName)
00134 {
00135 if( find(m_dbList.begin(), m_dbList.end(), dbName) == m_dbList.end() ) {
00136
00137 m_dbList.push_back(dbName);
00138 }
00139 }
00140
00141 void Restore::Add(const DBListType &dbList)
00142 {
00143 for( DBListType::const_iterator i = dbList.begin();
00144 i != dbList.end();
00145 ++i )
00146 {
00147 AddDB(*i);
00148 }
00149 }
00150
00151 void Restore::SkipCurrentDB()
00152 {
00153
00154 try {
00155 while( Retrieve(m_record_data) == RS_NEXT ) {
00156 std::cerr << "Skipping: "
00157 << m_current_dbname << "/"
00158 << m_tar_id_text << std::endl;
00159 m_tar_record_state = RS_EMPTY;
00160 }
00161 }
00162 catch( reuse::TarFile::TarError & ) {
00163 m_tar_record_state = RS_EOF;
00164 }
00165 }
00166
00167 unsigned int Restore::GetRecordTotal() const
00168 {
00169 return GetRecordTotal(m_tarpath, m_dbList, m_default_all_db);
00170 }
00171
00172 unsigned int Restore::GetRecordTotal(const std::string &tarpath,
00173 const DBListType &dbList,
00174 bool default_all_db)
00175 {
00176 unsigned int count = 0;
00177
00178 std::auto_ptr<reuse::TarFile> tar;
00179
00180 try {
00181
00182 tar.reset( new reuse::TarFile(tarpath.c_str(), false,
00183 &reuse::gztar_ops_nonthread, true) );
00184 count = CountFiles(*tar, dbList, default_all_db);
00185 }
00186 catch( reuse::TarFile::TarError &te ) {
00187 throw Barry::RestoreError(te.what());
00188 }
00189 return count;
00190 }
00191
00192 bool Restore::GetNextMeta(DBData &data)
00193 {
00194
00195
00196
00197 if( m_tar_record_state == RS_EMPTY ) {
00198 Retrieve(m_record_data);
00199 }
00200
00201
00202
00203
00204 switch( m_tar_record_state )
00205 {
00206 case RS_NEXT:
00207 data.SetVersion(Barry::DBData::REC_VERSION_1);
00208 data.SetDBName(m_current_dbname);
00209 data.SetIds(m_rec_type, m_unique_id);
00210 data.SetOffset(0);
00211 return true;
00212
00213 default:
00214 return false;
00215 }
00216 }
00217
00218
00219
00220
00221
00222 Restore::RetrievalState Restore::Retrieve(Data &record_data)
00223 {
00224
00225 if( m_tar_record_state != RS_EMPTY )
00226 return m_tar_record_state;
00227
00228
00229 for(;;) {
00230
00231 std::string filename;
00232 if( !m_tar->ReadNextFile(filename, record_data) ) {
00233
00234 return m_tar_record_state = RS_EOF;
00235 }
00236 m_tar_record_state = RS_UNKNOWN;
00237
00238
00239 std::string dbname;
00240 if( !SplitTarPath(filename, dbname, m_tar_id_text, m_rec_type, m_unique_id) ) {
00241
00242 std::cerr << "Skipping invalid tar record: " << filename << std::endl;
00243 continue;
00244 }
00245
00246
00247
00248 if( m_current_dbname == dbname ) {
00249 return m_tar_record_state = RS_NEXT;
00250 }
00251
00252
00253 m_tar_record_state = RS_DBEND;
00254
00255
00256
00257 if( !IsSelected(dbname) ) {
00258 continue;
00259 }
00260
00261
00262
00263 if( m_current_dbname.size() == 0 ) {
00264
00265 m_tar_record_state = RS_NEXT;
00266 }
00267
00268 m_current_dbname = dbname;
00269 return m_tar_record_state;
00270 }
00271 }
00272
00273 bool Restore::BuildRecord(Barry::DBData &data,
00274 size_t &offset,
00275 const Barry::IConverter *ic)
00276 {
00277
00278
00279 switch( Retrieve(m_record_data) )
00280 {
00281 case RS_NEXT:
00282 {
00283 data.SetVersion(Barry::DBData::REC_VERSION_1);
00284 data.SetDBName(m_current_dbname);
00285 data.SetIds(m_rec_type, m_unique_id);
00286 data.SetOffset(offset);
00287
00288 int packet_size = offset + m_record_data.GetSize();
00289 unsigned char *buf = data.UseData().GetBuffer(packet_size);
00290 memcpy(buf + offset, m_record_data.GetData(), m_record_data.GetSize());
00291 offset += m_record_data.GetSize();
00292 data.UseData().ReleaseBuffer(packet_size);
00293
00294
00295 m_tar_record_state = RS_EMPTY;
00296 return true;
00297 }
00298
00299 case RS_EMPTY:
00300 case RS_UNKNOWN:
00301 default:
00302 throw std::logic_error("Invalid state in Restore::BuildRecord()");
00303
00304 case RS_DBEND:
00305
00306
00307 m_tar_record_state = RS_NEXT;
00308 return false;
00309
00310 case RS_EOF:
00311
00312 return false;
00313 }
00314 }
00315
00316 bool Restore::FetchRecord(Barry::DBData &data, const Barry::IConverter *ic)
00317 {
00318
00319
00320
00321
00322
00323
00324
00325 if( m_tar_record_state == RS_EMPTY ) {
00326
00327
00328
00329 if( Retrieve(data.UseData()) == RS_DBEND ) {
00330 m_record_data = data.GetData();
00331 m_tar_record_state = RS_NEXT;
00332 return false;
00333 }
00334 }
00335 else {
00336 data.UseData() = m_record_data;
00337 }
00338
00339 switch( m_tar_record_state )
00340 {
00341 case RS_NEXT:
00342 data.SetVersion(Barry::DBData::REC_VERSION_1);
00343 data.SetDBName(m_current_dbname);
00344 data.SetIds(m_rec_type, m_unique_id);
00345 data.SetOffset(0);
00346
00347
00348 m_tar_record_state = RS_EMPTY;
00349 return true;
00350
00351 case RS_EMPTY:
00352 case RS_UNKNOWN:
00353 default:
00354 throw std::logic_error("Invalid state in Restore::FetchRecord()");
00355
00356 case RS_DBEND:
00357
00358
00359 m_tar_record_state = RS_NEXT;
00360 return false;
00361
00362 case RS_EOF:
00363
00364 return false;
00365 }
00366 }
00367
00368 bool Restore::EndOfFile() const
00369 {
00370 return m_tar_record_state == RS_EOF;
00371 }
00372
00373 }
00374