Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions docs/software/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,12 @@ Command options can only by placed after command.
* **load-xdr <FILE-NAME>**: Load an XDR bucket file, for testing.
* **new-db**: Clears the local database and resets it to the genesis ledger. If
you connect to the network after that it will catch up from scratch.
* **new-hist <HISTORY-LABEL> ...**: Initialize the named history archives
HISTORY-LABEL. HISTORY-LABEL should be one of the history archives you have
specified in the stellar-core.cfg. This will write a
`.well-known/stellar-history.json` file in the archive root.
* **new-hist [--idempotent] <HISTORY-LABEL> ...**: Initialize the named
history archives HISTORY-LABEL. HISTORY-LABEL should be one of the history
archives you have specified in the stellar-core.cfg. This will write a
`.well-known/stellar-history.json` file in the archive root. With
**--idempotent**, the command succeeds even if the archive is already
initialized.
* **offline-info**: Returns an output similar to `--c info` for an offline
instance, but written directly to standard output (ignoring log levels).
* **print-xdr <FILE-NAME>**: Pretty-print a binary file containing an XDR
Expand Down
10 changes: 9 additions & 1 deletion src/history/HistoryArchiveManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,8 @@ HistoryArchiveManager::getCheckLedgerHeaderWork(
}

bool
HistoryArchiveManager::initializeHistoryArchive(std::string const& arch) const
HistoryArchiveManager::initializeHistoryArchive(std::string const& arch,
bool idempotent) const
{
auto archive = getHistoryArchive(arch);
if (!archive)
Expand All @@ -215,6 +216,13 @@ HistoryArchiveManager::initializeHistoryArchive(std::string const& arch) const
ws.executeWork<GetHistoryArchiveStateWork>(0, archive, "hist-init", 0);
if (getHas->getState() == BasicWork::State::WORK_SUCCESS)
{
if (idempotent)
{
CLOG_INFO(History,
"History archive '{}' already initialized; skipping",
arch);
return true;
}
CLOG_ERROR(History, "History archive '{}' already initialized!", arch);
return false;
}
Expand Down
3 changes: 2 additions & 1 deletion src/history/HistoryArchiveManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ class HistoryArchiveManager

// Initialize a named history archive by writing
// .well-known/stellar-history.json to it.
bool initializeHistoryArchive(std::string const& arch) const;
bool initializeHistoryArchive(std::string const& arch,
bool idempotent = false) const;

// Returns whether or not the HistoryManager has any writable history
// archives (those configured with both a `get` and `put` command).
Expand Down
22 changes: 22 additions & 0 deletions src/history/test/HistoryTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2190,6 +2190,28 @@ TEST_CASE("initialize existing history store fails", "[history]")
}
}

TEST_CASE("initialize existing history store idempotently succeeds",
"[history]")
{
Config cfg(getTestConfig(0, Config::TESTDB_BUCKET_DB_PERSISTENT));
TmpDirHistoryConfigurator tcfg;
cfg = tcfg.configure(cfg, true);

{
VirtualClock clock;
Application::pointer app = createTestApplication(clock, cfg);
REQUIRE(app->getHistoryArchiveManager().initializeHistoryArchive(
tcfg.getArchiveDirName()));
}

{
VirtualClock clock;
Application::pointer app = createTestApplication(clock, cfg);
REQUIRE(app->getHistoryArchiveManager().initializeHistoryArchive(
tcfg.getArchiveDirName(), true));
}
}

TEST_CASE("Catchup failure recovery with buffered checkpoint",
"[history][catchup]")
{
Expand Down
6 changes: 4 additions & 2 deletions src/main/ApplicationUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1030,15 +1030,17 @@ genSeed()
}

int
initializeHistories(Config cfg, std::vector<std::string> const& newHistories)
initializeHistories(Config cfg, std::vector<std::string> const& newHistories,
bool idempotent)
{
VirtualClock clock;
cfg.setNoListen();
Application::pointer app = Application::create(clock, cfg, false);

for (auto const& arch : newHistories)
{
if (!app->getHistoryArchiveManager().initializeHistoryArchive(arch))
if (!app->getHistoryArchiveManager().initializeHistoryArchive(
arch, idempotent))
return 1;
}
return 0;
Expand Down
3 changes: 2 additions & 1 deletion src/main/ApplicationUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ int rebuildLedgerFromBuckets(Config cfg);
#endif
void genSeed();
int initializeHistories(Config cfg,
std::vector<std::string> const& newHistories);
std::vector<std::string> const& newHistories,
bool idempotent = false);
void writeCatchupInfo(Json::Value const& catchupInfo,
std::string const& outputFile);
int catchup(Application::pointer app, CatchupConfiguration cc,
Expand Down
7 changes: 6 additions & 1 deletion src/main/CommandLine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1501,13 +1501,18 @@ runNewHist(CommandLineArgs const& args)
{
CommandLine::ConfigOption configOption;
std::vector<std::string> newHistories;
bool idempotent = false;

return runWithHelp(args,
{configurationParser(configOption),
clara::Opt{idempotent}["--idempotent"](
"succeed if the history archive is already "
"initialized"),
requiredArgParser(newHistories, "HISTORY-LABEL")},
[&] {
return initializeHistories(configOption.getConfig(),
newHistories);
newHistories,
idempotent);
});
}

Expand Down
Loading