Skip to content
Merged
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
58 changes: 58 additions & 0 deletions src/fb-cpp/DatabaseManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ void DatabaseManager::setProperties(const DatabasePropertiesOptions& options)
if (const auto replicaMode = options.getReplicaMode())
{
std::uint8_t modeVal = 0;

switch (*replicaMode)
{
case ReplicaMode::NONE:
Expand All @@ -56,9 +57,66 @@ void DatabaseManager::setProperties(const DatabasePropertiesOptions& options)
assert(false);
break;
}

builder->insertBytes(&statusWrapper, isc_spb_prp_replica_mode, &modeVal, 1u);
}

if (const auto shutdownMode = options.getShutdownMode())
{
std::uint8_t stateVal = 0;

switch (*shutdownMode)
{
case ShutdownMode::NORMAL:
stateVal = isc_spb_prp_sm_normal;
break;
case ShutdownMode::MULTI:
stateVal = isc_spb_prp_sm_multi;
break;
case ShutdownMode::SINGLE:
stateVal = isc_spb_prp_sm_single;
break;
case ShutdownMode::FULL:
stateVal = isc_spb_prp_sm_full;
break;
default:
assert(false);
break;
}

builder->insertBytes(&statusWrapper, isc_spb_prp_shutdown_mode, &stateVal, 1u);
}

if (const auto shutdownType = options.getShutdownType())
{
const auto timeout = options.getShutdownTimeout().value_or(0);

switch (*shutdownType)
{
case ShutdownType::DENY_TRANSACTIONS:
builder->insertInt(&statusWrapper, isc_spb_prp_deny_new_transactions, timeout);
break;
case ShutdownType::DENY_ATTACHMENTS:
builder->insertInt(&statusWrapper, isc_spb_prp_deny_new_attachments, timeout);
break;
case ShutdownType::FORCED:
builder->insertInt(&statusWrapper, isc_spb_prp_force_shutdown, timeout);
break;
default:
assert(false);
break;
}
}

if (const auto online = options.getOnline())
{
if (*online)
{
std::uint8_t stateVal = isc_spb_prp_sm_normal;
builder->insertBytes(&statusWrapper, isc_spb_prp_online_mode, &stateVal, 1u);
}
}

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

Expand Down
119 changes: 119 additions & 0 deletions src/fb-cpp/DatabaseManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,53 @@
///
namespace fbcpp
{
///
/// Shutdown mode for a Firebird database.
///
enum class ShutdownMode
{
///
/// Normal online state.
///
NORMAL,

///
/// Multi-user shutdown.
///
MULTI,

///
/// Single-user shutdown.
///
SINGLE,

///
/// Full exclusive shutdown.
///
FULL
};

///
/// Shutdown type for a Firebird database.
///
enum class ShutdownType
{
///
/// Forced shutdown: disconnects all users immediately after the timeout.
///
FORCED,

///
/// Deny new transactions: waits for existing transactions to finish.
///
DENY_TRANSACTIONS,

///
/// Deny new attachments: waits for existing connections to finish.
///
DENY_ATTACHMENTS
};

///
/// Represents options used to configure database properties through the service manager.
///
Expand Down Expand Up @@ -76,9 +123,81 @@ namespace fbcpp
return *this;
}

///
/// Returns the shutdown mode.
///
const std::optional<ShutdownMode>& getShutdownMode() const
{
return shutdownMode;
}

///
/// Sets the shutdown mode.
///
DatabasePropertiesOptions& setShutdownMode(ShutdownMode value)
{
shutdownMode = value;
return *this;
}

///
/// Returns the shutdown type.
///
const std::optional<ShutdownType>& getShutdownType() const
{
return shutdownType;
}

///
/// Sets the shutdown type.
///
DatabasePropertiesOptions& setShutdownType(ShutdownType value)
{
shutdownType = value;
return *this;
}

///
/// Returns the shutdown timeout in seconds.
///
const std::optional<int>& getShutdownTimeout() const
{
return shutdownTimeout;
}

///
/// Sets the shutdown timeout in seconds.
///
DatabasePropertiesOptions& setShutdownTimeout(int value)
{
shutdownTimeout = value;
return *this;
}

///
/// Returns whether the database should be brought online.
///
const std::optional<bool>& getOnline() const
{
return online;
}

///
/// Sets whether the database should be brought online.
///
DatabasePropertiesOptions& setOnline(bool value)
{
online = value;
return *this;
}

private:
std::string database;
std::optional<ReplicaMode> replicaMode;
std::optional<ShutdownMode> shutdownMode;
std::optional<ShutdownType> shutdownType;
std::optional<int> shutdownTimeout;
std::optional<bool> online;
};

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

BOOST_AUTO_TEST_CASE(databaseShutdownAndOnline)
{
const auto databasePath = getTempFile("DatabaseManager-shutdownAndOnline.fdb", false);
const auto databaseUri = getTempFile("DatabaseManager-shutdownAndOnline.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();
}

DatabaseManager manager{CLIENT, makeServiceManagerOptions()};

// Shutdown the database
manager.setProperties(DatabasePropertiesOptions()
.setDatabase(databasePath)
.setShutdownMode(ShutdownMode::FULL)
.setShutdownType(ShutdownType::FORCED)
.setShutdownTimeout(0));

// Attachment should fail when the database is shutdown
BOOST_CHECK_THROW(Attachment(CLIENT, databaseUri, attachmentOptions), DatabaseException);

// Bring the database online
manager.setProperties(DatabasePropertiesOptions().setDatabase(databasePath).setOnline(true));

// Attachment should succeed when online
{ // scope
Attachment attachment{CLIENT, databaseUri, attachmentOptions};
Transaction transaction{attachment};
Statement query{attachment, transaction, "select count(*) from test"};
BOOST_REQUIRE(query.execute(transaction));
BOOST_CHECK_EQUAL(query.getInt32(0).value(), 0);
}

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

BOOST_AUTO_TEST_SUITE_END()
Loading