00001 #include "config.h"
00002
00003 #include <iostream>
00004 #include <vector>
00005 #include <map>
00006 #include <string>
00007
00008 #include "asserts.h"
00009 #include "error.h"
00010 #include "rmath.h"
00011 #include "fs.h"
00012 #include "rconfig.h"
00013 #include "logger.h"
00014 #include "timer.h"
00015 #include "estat.h"
00016 #include "reporter.h"
00017 #include "strfmt.h"
00018
00019 #include "vaulter.h"
00020
00021
00022 vault_manager::vault_manager()
00023 {
00024 if (this != &vaulter)
00025 throw(INTERNAL_ERROR(0,"Attempt to allocate multiple vault managers"));
00026 clear();
00027 }
00028
00029
00030 void vault_manager::clear(void)
00031 {
00032 m_selected_vault.erase();
00033 m_deleted_archives.clear();
00034 m_da_err = false;
00035 m_initialized = false;
00036 }
00037
00038
00039 void vault_manager::init(void)
00040 {
00041 clear();
00042 m_initialized = true;
00043 }
00044
00045
00046 const bool vault_manager::initialized(void) const
00047 {
00048 return(m_initialized);
00049 }
00050
00051
00052
00053
00054
00055
00056
00057
00058 void vault_manager::select(void)
00059 {
00060 std::string es;
00061 configuration_manager::vaults_type::const_iterator vi;
00062
00063 if (!initialized())
00064 throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
00065
00066 TRY_nomem(es = "Could not select a vault");
00067 try {
00068
00069
00070 for (
00071 vi = config.vaults().begin();
00072 vi != config.vaults().end();
00073 vi++
00074 )
00075 {
00076 subdirectory subdir;
00077 subdirectory::iterator sdi;
00078
00079 subdir.path(*vi);
00080 for (sdi = subdir.begin(); sdi != subdir.end(); sdi++) {
00081 if (*sdi == config.timestamp().str()) {
00082 TRY_nomem(m_selected_vault = *vi);
00083 return;
00084 }
00085 }
00086 }
00087
00088
00089
00090 if (config.vault_selection_behavior()
00091 == configuration_manager::selection_round_robin)
00092 {
00093 std::pair<std::string,std::string> youngest;
00094
00095 for (
00096 vi = config.vaults().begin();
00097 vi != config.vaults().end();
00098 vi++
00099 )
00100 {
00101 subdirectory subdir;
00102 subdirectory::iterator sdi;
00103
00104 subdir.path(*vi);
00105 for (sdi = subdir.begin(); sdi != subdir.end(); sdi++) {
00106 if ((youngest.first < *sdi) || (youngest.first.size() == 0)) {
00107 TRY_nomem(youngest.first = *sdi);
00108 TRY_nomem(youngest.second = *vi);
00109 }
00110 }
00111 }
00112
00113 TRY_nomem(m_selected_vault = "");
00114 if (youngest.second.size() == 0) {
00115 TRY_nomem(m_selected_vault = config.vaults()[0]);
00116 }
00117 else {
00118 for (
00119 vi = config.vaults().begin();
00120 vi != config.vaults().end();
00121 vi++
00122 )
00123 {
00124 if (*vi == youngest.second) {
00125 if ((vi+1) == config.vaults().end()) {
00126 TRY_nomem(m_selected_vault = config.vaults()[0]);
00127 }
00128 else {
00129 TRY_nomem(m_selected_vault = *(vi+1));
00130 }
00131 }
00132 }
00133 }
00134 }
00135 else {
00136 std::pair<std::string,filesystem::size_type> most_space;
00137 filesystem fsys;
00138
00139 TRY_nomem(most_space.first = config.vaults()[0]);
00140 fsys.path(config.vaults()[0]);
00141 most_space.second = fsys.free_blocks();
00142 for (
00143 vi = (config.vaults().begin()+1);
00144 vi != config.vaults().end();
00145 vi++
00146 )
00147 {
00148 fsys.path(*vi);
00149 if (most_space.second < fsys.free_blocks()) {
00150 TRY_nomem(most_space.first = *vi);
00151 most_space.second = fsys.free_blocks();
00152 }
00153 }
00154 TRY_nomem(m_selected_vault = most_space.first);
00155 }
00156 }
00157 catch(error e) {
00158 e.push_back(es);
00159 throw(e);
00160 }
00161 catch(...) {
00162 error e(0);
00163 if (errno == ENOMEM) {
00164 e = err_nomem;
00165 e.push_back(es);
00166 throw(e);
00167 }
00168 e = err_unknown;
00169 e.push_back(es);
00170 throw(e);
00171 }
00172
00173 if (m_selected_vault.size() == 0)
00174 throw(ERROR(0,es));
00175 }
00176
00177
00178 const subdirectory vault_manager::get_archive_list(void)
00179 {
00180 subdirectory subdir;
00181
00182 if (!initialized())
00183 throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
00184
00185 if (!selected())
00186 throw(INTERNAL_ERROR(0,"No vault selected"));
00187
00188 subdir.path(vault());
00189
00190 return(subdir);
00191 }
00192
00193
00194 const std::string vault_manager::vault(void) const
00195 {
00196 if (!initialized())
00197 throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
00198
00199 if (!selected())
00200 throw(INTERNAL_ERROR(0,"No vault selected"));
00201
00202 return(m_selected_vault);
00203 }
00204
00205
00206 const bool vault_manager::selected(void) const
00207 {
00208 bool value = true;
00209
00210 if (!initialized())
00211 throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
00212
00213 if (m_selected_vault.size() == 0)
00214 value = false;
00215
00216 return(value);
00217 }
00218
00219
00220 void vault_manager::usage(uint16 &a_blocks, uint16 &a_inodes) const
00221 {
00222 filesystem fsys;
00223 safe_num<uint64> blocks, inodes;
00224
00225 if (!initialized())
00226 throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
00227
00228 if (!selected())
00229 throw(INTERNAL_ERROR(0,"No vault selected"));
00230
00231 fsys.path(vault());
00232
00233 if (fsys.total_blocks() == 0)
00234 blocks = 0;
00235 else {
00236 try {
00237 blocks = fsys.free_blocks();
00238 blocks *= 100;
00239 blocks /= fsys.total_blocks();
00240 }
00241 catch(error e) {
00242 logger.write("*** ERROR: Overflow error detected in vault_manager::usage() while calculating percent blocks used\n");
00243 blocks = 0;
00244 }
00245 catch(...) {
00246 logger.write("*** ERROR: Unknown error detected in vault_manager::usage() while calculating percent blocks used\n");
00247 blocks = 0;
00248 }
00249 }
00250
00251 if (fsys.free_inodes() == 0)
00252 inodes = 0;
00253 else {
00254 try {
00255 inodes = fsys.free_inodes();
00256 inodes *= 100;
00257 inodes /= fsys.total_inodes();
00258 }
00259 catch(error e) {
00260 logger.write("*** ERROR: Overflow error detected in vault_manager::usage() while calculating percent inodes used\n");
00261 blocks = 0;
00262 }
00263 catch(...) {
00264 logger.write("*** ERROR: Unknown error detected in vault_manager::usage() while calculating percent inodes used\n");
00265 blocks = 0;
00266 }
00267 }
00268
00269 ASSERT(blocks <= max_limit(blocks));
00270 ASSERT(inodes <= max_limit(inodes));
00271
00272 a_blocks = blocks.value();
00273 a_inodes = inodes.value();
00274 }
00275
00276
00277 const bool vault_manager::overflow(bool a_report)
00278 {
00279 uint16 free_blocks;
00280 uint16 free_inodes;
00281 bool value = false;
00282 std::string lstr;
00283
00284 if (!initialized())
00285 throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
00286
00287 if (!selected())
00288 throw(INTERNAL_ERROR(0,"No vault selected"));
00289
00290 usage(free_blocks, free_inodes);
00291 if (free_blocks < config.vault_overflow_blocks())
00292 value = true;
00293 if (free_inodes < config.vault_overflow_inodes())
00294 value = true;
00295
00296 if (value && a_report) {
00297 TRY_nomem(lstr = "Vault overflow detected: ");
00298 TRY_nomem(lstr += vault());
00299 TRY_nomem(lstr += "\n");
00300 logger.write(lstr);
00301
00302 TRY_nomem(lstr = " Threshold: ");
00303 TRY_nomem(lstr +=
00304 percent_string(config.vault_overflow_blocks(),
00305 static_cast<uint16>(100)));
00306 TRY_nomem(lstr += " free blocks, ");
00307 TRY_nomem(lstr +=
00308 percent_string(config.vault_overflow_inodes(),
00309 static_cast<uint16>(100)));
00310 TRY_nomem(lstr += " free inodes");
00311 TRY_nomem(lstr += "\n");
00312 logger.write(lstr);
00313
00314 TRY_nomem(lstr = "Vault capacity: ");
00315 TRY_nomem(lstr += percent_string(free_blocks,static_cast<uint16>(100)));
00316 TRY_nomem(lstr += " free blocks, ");
00317 TRY_nomem(lstr += percent_string(free_inodes,static_cast<uint16>(100)));
00318 TRY_nomem(lstr += " free inodes");
00319 TRY_nomem(lstr += "\n");
00320 logger.write(lstr);
00321
00322 reporter.vault().add_report(
00323 vault_stats_report(estring("Overflow Detected:"),filesystem(vault()))
00324 );
00325 }
00326
00327 return(value);
00328 }
00329
00330
00331 void vault_manager::delete_oldest_archive(void)
00332 {
00333 std::string es;
00334 std::string lstr;
00335 subdirectory archive_list;
00336 std::string oldest;
00337 std::string dir;
00338 estring estr;
00339 timer t;
00340 uint16 free_blocks, free_inodes;
00341
00342 if (!initialized())
00343 throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
00344
00345 if (!selected())
00346 throw(INTERNAL_ERROR(0,"No vault selected"));
00347
00348 archive_list = get_archive_list();
00349 if (
00350 (archive_list.size() == 0)
00351 || (
00352 (archive_list.size() == 1)
00353 && (archive_list[0] == config.timestamp().str())
00354 )
00355 )
00356 {
00357 TRY_nomem(es = "Vault has insufficient space: \"");
00358 TRY_nomem(es += vault());
00359 TRY_nomem(es += "\"");
00360 exit_manager.assign(exitstat::vault_full);
00361 throw(ERROR(0,es));
00362 }
00363
00364 TRY_nomem(oldest = archive_list[0]);
00365 if (oldest == config.timestamp().str()) {
00366 TRY_nomem(oldest = archive_list[1]);
00367 }
00368
00369 TRY_nomem(lstr = "Deleting oldest archive: \"");
00370 TRY_nomem(lstr += oldest);
00371 TRY_nomem(lstr += "\"\n");
00372 logger.write(lstr);
00373
00374 TRY_nomem(dir = vault());
00375 TRY_nomem(dir += "/");
00376 TRY_nomem(dir += oldest);
00377 t.start();
00378 try {
00379 m_deleted_archives.push_back(oldest);
00380 }
00381 catch(...) {
00382 m_da_err = true;
00383 }
00384 rm_recursive(dir);
00385 t.stop();
00386
00387 TRY_nomem(lstr = "Deletion complete, duration: ");
00388 TRY_nomem(lstr += t.duration());
00389 TRY_nomem(lstr += "\n");
00390 logger.write(lstr);
00391
00392 usage(free_blocks, free_inodes);
00393 TRY_nomem(lstr = "Vault capacity: ");
00394 TRY_nomem(lstr += percent_string(free_blocks,static_cast<uint16>(100)));
00395 TRY_nomem(lstr += " free blocks, ");
00396 TRY_nomem(lstr += percent_string(free_inodes,static_cast<uint16>(100)));
00397 TRY_nomem(lstr += " free inodes");
00398 TRY_nomem(lstr += "\n");
00399 logger.write(lstr);
00400
00401 estr = "Deleted ";
00402 estr += oldest;
00403 estr += ":";
00404 reporter.vault().add_report(vault_stats_report(estr,filesystem(vault())));
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416 void vault_manager::prepare(bool a_assume_overflow)
00417 {
00418 std::string es;
00419 std::string lstr;
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430 if (!initialized())
00431 throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
00432
00433 if (!selected())
00434 throw(INTERNAL_ERROR(0,"No vault selected"));
00435
00436 if (!overflow() && !a_assume_overflow)
00437 return;
00438
00439
00440
00441
00442 if (config.vault_overflow_behavior()
00443 == configuration_manager::overflow_quit)
00444 {
00445 TRY_nomem(es = "Vault has insufficient space: \"");
00446 TRY_nomem(es += vault());
00447 TRY_nomem(es += "\"");
00448 throw(ERROR(0,es));
00449 }
00450
00451 if (config.vault_overflow_behavior()
00452 == configuration_manager::overflow_delete_oldest)
00453 {
00454 if (m_deleted_archives.size() == 0) {
00455 TRY(delete_oldest_archive(),"Failure preparing vault");
00456 a_assume_overflow = false;
00457 }
00458 else {
00459 logger.write("Vault has insufficient space\n");
00460 throw(ERROR(0,"Vault has insufficient space"));
00461 }
00462 }
00463
00464 if (!overflow() && !a_assume_overflow)
00465 return;
00466
00467 if (config.vault_overflow_behavior()
00468 == configuration_manager::overflow_delete_until_free)
00469 {
00470 while (overflow() || a_assume_overflow) {
00471
00472 TRY(delete_oldest_archive(),"Failure preparing vault");
00473 a_assume_overflow = false;
00474 }
00475 }
00476 else {
00477
00478 exit_manager.assign(exitstat::vault_full);
00479
00480 }
00481 }
00482
00483
00484 const std::vector<std::string>& vault_manager::deleted_archives(void) const
00485 {
00486 if (!initialized())
00487 throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
00488
00489 return(m_deleted_archives);
00490 }
00491
00492
00493 const bool vault_manager::err_deleted_archives(void) const
00494 {
00495 if (!initialized())
00496 throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
00497
00498 return(m_da_err);
00499 }
00500
00501
00502 vault_manager vaulter;
00503