bool HistoryManager::initializeHistoryArchive(Application& app, std::string arch) { auto const& cfg = app.getConfig(); auto i = cfg.HISTORY.find(arch); if (i == cfg.HISTORY.end()) { CLOG(FATAL, "History") << "Can't initialize unknown history archive '" << arch << "'"; return false; } auto& wm = app.getWorkManager(); // First check that there's no existing HAS in the archive HistoryArchiveState existing; CLOG(INFO, "History") << "Probing history archive '" << arch << "' for existing state"; auto getHas = wm.addWork<GetHistoryArchiveStateWork>(existing, 0, std::chrono::seconds(0), i->second, 0); wm.advanceChildren(); while (!wm.allChildrenDone()) { app.getClock().crank(false); } if (getHas->getState() == Work::WORK_SUCCESS) { CLOG(ERROR, "History") << "History archive '" << arch << "' already initialized!"; return false; } CLOG(INFO, "History") << "History archive '" << arch << "' appears uninitialized"; HistoryArchiveState has; CLOG(INFO, "History") << "Initializing history archive '" << arch << "'"; has.resolveAllFutures(); auto putHas = wm.addWork<PutHistoryArchiveStateWork>(has, i->second); wm.advanceChildren(); while (!wm.allChildrenDone()) { app.getClock().crank(false); } if (putHas->getState() == Work::WORK_SUCCESS) { CLOG(INFO, "History") << "Initialized history archive '" << arch << "'"; return true; } else { CLOG(FATAL, "History") << "Failed to initialize history archive '" << arch << "'"; return false; } }
size_t HistoryManagerImpl::publishQueuedHistory() { std::string state; auto prep = mApp.getDatabase().getPreparedStatement( "SELECT state FROM publishqueue" " ORDER BY ledger ASC LIMIT 1;"); auto& st = prep.statement(); soci::indicator stateIndicator; st.exchange(soci::into(state, stateIndicator)); st.define_and_bind(); st.execute(true); if (st.got_data() && stateIndicator == soci::indicator::i_ok) { HistoryArchiveState has; has.fromString(state); takeSnapshotAndPublish(has); return 1; } return 0; }
std::vector<std::string> BucketManagerImpl::checkForMissingBucketsFiles(HistoryArchiveState const& has) { std::vector<std::string> buckets = has.allBuckets(); std::vector<std::string> result; std::copy_if(buckets.begin(), buckets.end(), std::back_inserter(result), [&](std::string b) { auto filename = bucketFilename(b); return !isZero(hexToBin256(b)) && !fs::exists(filename); }); return result; }
void LedgerManagerImpl::loadLastKnownLedger( function<void(asio::error_code const& ec)> handler) { auto ledgerTime = mLedgerClose.TimeScope(); string lastLedger = mApp.getPersistentState().getState(PersistentState::kLastClosedLedger); if (lastLedger.empty()) { throw std::runtime_error("No ledger in the DB"); } else { LOG(INFO) << "Loading last known ledger"; Hash lastLedgerHash = hexToBin256(lastLedger); mCurrentLedger = LedgerHeaderFrame::loadByHash(lastLedgerHash, getDatabase()); if (!mCurrentLedger) { throw std::runtime_error("Could not load ledger from database"); } if (handler) { string hasString = mApp.getPersistentState().getState( PersistentState::kHistoryArchiveState); HistoryArchiveState has; has.fromString(hasString); auto continuation = [this, handler, has](asio::error_code const& ec) { if (ec) { handler(ec); } else { mApp.getBucketManager().assumeState(has); CLOG(INFO, "Ledger") << "Loaded last known ledger: " << ledgerAbbrev(mCurrentLedger); advanceLedgerPointers(); handler(ec); } }; auto missing = mApp.getBucketManager().checkForMissingBucketsFiles(has); if (!missing.empty()) { CLOG(WARNING, "Ledger") << "Some buckets are missing in '" << mApp.getBucketManager().getBucketDir() << "'."; CLOG(WARNING, "Ledger") << "Attempting to recover from the history store."; mApp.getHistoryManager().downloadMissingBuckets(has, continuation); } else { continuation(asio::error_code()); } } else { advanceLedgerPointers(); } } }