Skip to content
Merged
43 changes: 43 additions & 0 deletions src/fb-cpp/DatabaseManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,46 @@ void DatabaseManager::execute(const DatabaseManagerOptions& options)
startAction(std::vector<std::uint8_t>(buffer, buffer + length));
waitForCompletion();
}


void DatabaseManager::execute(const MaintenanceOptions& options)
Comment thread
mariuz marked this conversation as resolved.
Outdated
{
StatusWrapper statusWrapper{getClient()};
auto builder =
fbUnique(getClient().getUtil()->getXpbBuilder(&statusWrapper, fb::IXpbBuilder::SPB_START, nullptr, 0));

builder->insertTag(&statusWrapper, isc_action_svc_repair);
builder->insertString(&statusWrapper, isc_spb_dbname, options.getDatabase().c_str());

int optionsVal = 0;
if (options.getSweep())
optionsVal |= isc_spb_rpr_sweep_db;
if (options.getValidate())
optionsVal |= isc_spb_rpr_validate_db;
if (options.getMend())
optionsVal |= isc_spb_rpr_mend_db;
if (options.getIgnoreChecksum())
optionsVal |= isc_spb_rpr_ignore_checksum;
if (options.getKillShadows())
optionsVal |= isc_spb_rpr_kill_shadows;
if (options.getFull())
optionsVal |= isc_spb_rpr_full;
if (options.getCheckDb())
optionsVal |= isc_spb_rpr_check_db;
if (options.getIcu())
optionsVal |= isc_spb_rpr_icu;
if (options.getUpgradeDb())
optionsVal |= isc_spb_rpr_upgrade_db;

if (optionsVal != 0)
builder->insertInt(&statusWrapper, isc_spb_options, optionsVal);

if (const auto parallelWorkers = options.getParallelWorkers())
builder->insertInt(&statusWrapper, isc_spb_rpr_par_workers, static_cast<int>(*parallelWorkers));

const auto buffer = builder->getBuffer(&statusWrapper);
const auto length = builder->getBufferLength(&statusWrapper);

startAction(std::vector<std::uint8_t>(buffer, buffer + length));
waitForCompletion(options.getVerboseOutput());
}
231 changes: 231 additions & 0 deletions src/fb-cpp/DatabaseManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#define FBCPP_DATABASE_MANAGER_H

#include "ServiceManager.h"
#include <cstdint>
#include <optional>
#include <string>

Expand Down Expand Up @@ -80,6 +81,231 @@ namespace fbcpp
std::optional<ReplicaMode> replicaMode;
};

///
/// Represents options used to run a database maintenance operation through the service manager.
///
class MaintenanceOptions final
{
public:
///
/// Returns the database path to be maintained.
///
const std::string& getDatabase() const
{
return database;
}

///
/// Sets the database path to be maintained.
///
MaintenanceOptions& setDatabase(const std::string& value)
{
database = value;
return *this;
}

///
/// Returns the verbose output callback.
///
const ServiceManager::VerboseOutput& getVerboseOutput() const
{
return verboseOutput;
}

///
/// Sets the verbose output callback.
///
MaintenanceOptions& setVerboseOutput(ServiceManager::VerboseOutput value)
{
verboseOutput = std::move(value);
return *this;
}

///
/// Returns the requested number of parallel workers.
///
const std::optional<std::uint32_t>& getParallelWorkers() const
{
return parallelWorkers;
}

///
/// Sets the requested number of parallel workers.
///
MaintenanceOptions& setParallelWorkers(std::uint32_t value)
{
parallelWorkers = value;
return *this;
}

///
/// Returns whether database sweep is enabled.
///
bool getSweep() const
{
return sweep;
}

///
/// Sets whether database sweep is enabled.
///
MaintenanceOptions& setSweep(bool value)
{
sweep = value;
return *this;
}

///
/// Returns whether database validation is enabled.
///
bool getValidate() const
{
return validate;
}

///
/// Sets whether database validation is enabled.
///
MaintenanceOptions& setValidate(bool value)
{
validate = value;
return *this;
}

///
/// Returns whether database mending is enabled.
///
bool getMend() const
{
return mend;
}

///
/// Sets whether database mending is enabled.
///
MaintenanceOptions& setMend(bool value)
{
mend = value;
return *this;
}

///
/// Returns whether checksum verification is ignored.
///
bool getIgnoreChecksum() const
{
return ignoreChecksum;
}

///
/// Sets whether checksum verification is ignored.
///
MaintenanceOptions& setIgnoreChecksum(bool value)
{
ignoreChecksum = value;
return *this;
}

///
/// Returns whether killing database shadows is enabled.
///
bool getKillShadows() const
{
return killShadows;
}

///
/// Sets whether killing database shadows is enabled.
///
MaintenanceOptions& setKillShadows(bool value)
{
killShadows = value;
return *this;
}

///
/// Returns whether full validation is enabled.
///
bool getFull() const
{
return full;
}

///
/// Sets whether full validation is enabled.
///
MaintenanceOptions& setFull(bool value)
{
full = value;
return *this;
}

///
/// Returns whether checking only metadata/structure is enabled.
///
bool getCheckDb() const
{
return checkDb;
}

///
/// Sets whether checking only metadata/structure is enabled.
///
MaintenanceOptions& setCheckDb(bool value)
{
checkDb = value;
return *this;
}

///
/// Returns whether recreating ICU indexes is enabled.
///
bool getIcu() const
{
return icu;
}

///
/// Sets whether recreating ICU indexes is enabled.
///
MaintenanceOptions& setIcu(bool value)
{
icu = value;
return *this;
}

///
/// Returns whether database upgrade is enabled.
///
bool getUpgradeDb() const
{
return upgradeDb;
}

///
/// Sets whether database upgrade is enabled.
///
MaintenanceOptions& setUpgradeDb(bool value)
{
upgradeDb = value;
return *this;
}

private:
std::string database;
ServiceManager::VerboseOutput verboseOutput;
std::optional<std::uint32_t> parallelWorkers;
bool sweep = false;
bool validate = false;
bool mend = false;
bool ignoreChecksum = false;
bool killShadows = false;
bool full = false;
bool checkDb = false;
bool icu = false;
bool upgradeDb = false;
};

///
/// Executes configuration and maintenance operations through the Firebird service manager.
///
Expand All @@ -93,6 +319,11 @@ namespace fbcpp
/// Configures database properties using the provided options.
///
void execute(const DatabaseManagerOptions& options);

///
/// Runs a maintenance or repair operation using the provided options.
///
void execute(const MaintenanceOptions& options);
};
} // namespace fbcpp

Expand Down
45 changes: 45 additions & 0 deletions src/test/DatabaseManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,49 @@ BOOST_AUTO_TEST_CASE(restoreWithReplicaMode)
cleanup.dropDatabase();
}

BOOST_AUTO_TEST_CASE(databaseSweepAndValidate)
{
const auto databasePath = getTempFile("DatabaseManager-sweepAndValidate.fdb", false);
const auto databaseUri = getTempFile("DatabaseManager-sweepAndValidate.fdb");
const auto attachmentOptions = AttachmentOptions().setConnectionCharSet("UTF8");

{ // scope
Attachment attachment{
CLIENT, databaseUri, AttachmentOptions().setCreateDatabase(true).setConnectionCharSet("UTF8")};
Transaction transaction{attachment};

Statement createTable{attachment, transaction, "create table test (id integer)"};
BOOST_REQUIRE(createTable.execute(transaction));
transaction.commit();
}

{ // scope
Attachment attachment{CLIENT, databaseUri, attachmentOptions};
Transaction transaction{attachment};

Statement insertData{attachment, transaction, "insert into test (id) values (1)"};
BOOST_REQUIRE(insertData.execute(transaction));
transaction.commit();
}

DatabaseManager manager{CLIENT, makeServiceManagerOptions()};

// 1. Run database sweep
BOOST_CHECK_NO_THROW(manager.execute(MaintenanceOptions().setDatabase(databasePath).setSweep(true)));

// 2. Run multi-threaded database sweep
BOOST_CHECK_NO_THROW(
manager.execute(MaintenanceOptions().setDatabase(databasePath).setSweep(true).setParallelWorkers(4)));

// 3. Run database validation
BOOST_CHECK_NO_THROW(
manager.execute(MaintenanceOptions().setDatabase(databasePath).setValidate(true).setFull(true)));

// 4. Run database upgrade (minor ODS upgrade)
BOOST_CHECK_NO_THROW(manager.execute(MaintenanceOptions().setDatabase(databasePath).setUpgradeDb(true)));

Attachment cleanup{CLIENT, databaseUri, attachmentOptions};
cleanup.dropDatabase();
}

BOOST_AUTO_TEST_SUITE_END()
Loading