diff --git a/3rdparty/lmdb-safe b/3rdparty/lmdb-safe index 4580d72..95ff695 160000 --- a/3rdparty/lmdb-safe +++ b/3rdparty/lmdb-safe @@ -1 +1 @@ -Subproject commit 4580d7242ad2c1c56582c6ee25e2227bfc6166e7 +Subproject commit 95ff695381c9662ec100697bebc6132bc317c005 diff --git a/librepomgr/buildactions/buildactionmeta.h b/librepomgr/buildactions/buildactionmeta.h index 427c728..94078bf 100644 --- a/librepomgr/buildactions/buildactionmeta.h +++ b/librepomgr/buildactions/buildactionmeta.h @@ -47,6 +47,7 @@ enum class BuildActionType : std::uint64_t { CleanRepository, DummyBuildAction, CustomCommand, + LastType = CustomCommand, }; using BuildActionFlagType = std::uint64_t; diff --git a/librepomgr/serversetup.cpp b/librepomgr/serversetup.cpp index cace8eb..55a24ef 100644 --- a/librepomgr/serversetup.cpp +++ b/librepomgr/serversetup.cpp @@ -357,6 +357,41 @@ std::size_t ServiceSetup::BuildSetup::buildActionCount() return m_storage->buildActions.getROTransaction().size(); } +void ServiceSetup::BuildSetup::rebuildDb() +{ + auto txn = m_storage->buildActions.getRWTransaction(); + auto processed = std::size_t(); + auto ok = std::size_t(); + txn.rebuild([count = txn.size(), &processed, &ok](StorageID id, BuildAction *buildAction) mutable { + std::cerr << "Processing build action " << ++processed << " / " << count << '\n'; + if (!buildAction) { + std::cerr << "Deleting build action " << id << ": unable to deserialize\n"; + return false; + } + if (buildAction->id > std::numeric_limits::max()) { + std::cerr << "Deleting build action " << id << ": object ID " << buildAction->id << " is out of range\n"; + return false; + } + if (buildAction->id != id) { + std::cerr << "Deleting build action " << id << ": ID mismatch (object ID is " << buildAction->id << ")\n"; + return false; + } + if (buildAction->type == BuildActionType::Invalid || buildAction->type > BuildActionType::LastType) { + std::cerr << "Deleting build action " << id << ": type is invalid\n"; + return false; + } + ++ok; + return true; + }); + if (ok < processed) { + std::cerr << "Discarding " << (processed - ok) << " invalid build actions.\n"; + } else { + std::cerr << "All " << ok << " build actions are valid.\n"; + } + std::cerr << "Committing changes.\n"; + txn.commit(); +} + void ServiceSetup::BuildSetup::forEachBuildAction( std::function count, std::function &&func, std::size_t limit, std::size_t start) { @@ -764,6 +799,26 @@ int ServiceSetup::run() return 0; } +int ServiceSetup::fixDb() +{ +#ifndef CPP_UTILITIES_DEBUG_BUILD + try { +#endif + loadConfigFiles(true); + building.initStorage(building.dbPath.data()); + building.rebuildDb(); +#ifndef CPP_UTILITIES_DEBUG_BUILD + } catch (const std::exception &e) { + cerr << Phrases::ErrorMessage << "Exception occurred when terminating server: " << Phrases::End << " " << e.what() << Phrases::EndFlush; + return -5; + } catch (...) { + cerr << Phrases::ErrorMessage << "Unknown error occurred when terminating server." << Phrases::EndFlush; + return -6; + } +#endif + return 0; +} + void ServiceSetup::Locks::clear() { auto log = LogContext(); diff --git a/librepomgr/serversetup.h b/librepomgr/serversetup.h index c720e19..4e2f1e0 100644 --- a/librepomgr/serversetup.h +++ b/librepomgr/serversetup.h @@ -55,6 +55,7 @@ struct LIBREPOMGR_EXPORT ServiceSetup : public LibPkg::Lockable { std::size_t saveState(); void initStorage(); int run(); + int fixDb(); ServiceStatus computeStatus() const; // variables relevant for the web server; only changed when (re)loading config @@ -141,6 +142,7 @@ struct LIBREPOMGR_EXPORT ServiceSetup : public LibPkg::Lockable { void deleteBuildAction(const std::vector> &actions); std::size_t buildActionCount(); std::size_t runningBuildActionCount(); + void rebuildDb(); void forEachBuildAction(std::function count, std::function &&func, std::size_t limit, std::size_t start); void forEachBuildAction(std::function &&func); diff --git a/srv/main.cpp b/srv/main.cpp index 14c0447..dea7188 100644 --- a/srv/main.cpp +++ b/srv/main.cpp @@ -41,9 +41,17 @@ int main(int argc, const char *argv[]) setup.building.forceLoadingDbs = forceLoadingDBsArg.isPresent(); exitCode = setup.run(); }); + OperationArgument fixDb("fix-db", '\0', "fixes the database files"); + fixDb.setSubArguments({ &configFileArg }); + fixDb.setCallback([&setup, &exitCode, &configFileArg](const ArgumentOccurrence &) { + if (const auto configFilePath = configFileArg.firstValue()) { + setup.configFilePath = configFilePath; + } + exitCode = setup.fixDb(); + }); HelpArgument helpArg(parser); NoColorArgument noColorArg; - parser.setMainArguments({ &runArg, &noColorArg, &helpArg }); + parser.setMainArguments({ &runArg, &fixDb, &noColorArg, &helpArg }); parser.setDefaultArgument(&runArg); parser.parseArgs(argc, argv); return exitCode;