Skip to content

Commit e6afa57

Browse files
authored
Support for shutdown/startup in DatabaseManager (#56)
1 parent 8522727 commit e6afa57

3 files changed

Lines changed: 220 additions & 0 deletions

File tree

src/fb-cpp/DatabaseManager.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ void DatabaseManager::setProperties(const DatabasePropertiesOptions& options)
4141
if (const auto replicaMode = options.getReplicaMode())
4242
{
4343
std::uint8_t modeVal = 0;
44+
4445
switch (*replicaMode)
4546
{
4647
case ReplicaMode::NONE:
@@ -56,9 +57,66 @@ void DatabaseManager::setProperties(const DatabasePropertiesOptions& options)
5657
assert(false);
5758
break;
5859
}
60+
5961
builder->insertBytes(&statusWrapper, isc_spb_prp_replica_mode, &modeVal, 1u);
6062
}
6163

64+
if (const auto shutdownMode = options.getShutdownMode())
65+
{
66+
std::uint8_t stateVal = 0;
67+
68+
switch (*shutdownMode)
69+
{
70+
case ShutdownMode::NORMAL:
71+
stateVal = isc_spb_prp_sm_normal;
72+
break;
73+
case ShutdownMode::MULTI:
74+
stateVal = isc_spb_prp_sm_multi;
75+
break;
76+
case ShutdownMode::SINGLE:
77+
stateVal = isc_spb_prp_sm_single;
78+
break;
79+
case ShutdownMode::FULL:
80+
stateVal = isc_spb_prp_sm_full;
81+
break;
82+
default:
83+
assert(false);
84+
break;
85+
}
86+
87+
builder->insertBytes(&statusWrapper, isc_spb_prp_shutdown_mode, &stateVal, 1u);
88+
}
89+
90+
if (const auto shutdownType = options.getShutdownType())
91+
{
92+
const auto timeout = options.getShutdownTimeout().value_or(0);
93+
94+
switch (*shutdownType)
95+
{
96+
case ShutdownType::DENY_TRANSACTIONS:
97+
builder->insertInt(&statusWrapper, isc_spb_prp_deny_new_transactions, timeout);
98+
break;
99+
case ShutdownType::DENY_ATTACHMENTS:
100+
builder->insertInt(&statusWrapper, isc_spb_prp_deny_new_attachments, timeout);
101+
break;
102+
case ShutdownType::FORCED:
103+
builder->insertInt(&statusWrapper, isc_spb_prp_force_shutdown, timeout);
104+
break;
105+
default:
106+
assert(false);
107+
break;
108+
}
109+
}
110+
111+
if (const auto online = options.getOnline())
112+
{
113+
if (*online)
114+
{
115+
std::uint8_t stateVal = isc_spb_prp_sm_normal;
116+
builder->insertBytes(&statusWrapper, isc_spb_prp_online_mode, &stateVal, 1u);
117+
}
118+
}
119+
62120
const auto buffer = builder->getBuffer(&statusWrapper);
63121
const auto length = builder->getBufferLength(&statusWrapper);
64122

src/fb-cpp/DatabaseManager.h

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,53 @@
3636
///
3737
namespace fbcpp
3838
{
39+
///
40+
/// Shutdown mode for a Firebird database.
41+
///
42+
enum class ShutdownMode
43+
{
44+
///
45+
/// Normal online state.
46+
///
47+
NORMAL,
48+
49+
///
50+
/// Multi-user shutdown.
51+
///
52+
MULTI,
53+
54+
///
55+
/// Single-user shutdown.
56+
///
57+
SINGLE,
58+
59+
///
60+
/// Full exclusive shutdown.
61+
///
62+
FULL
63+
};
64+
65+
///
66+
/// Shutdown type for a Firebird database.
67+
///
68+
enum class ShutdownType
69+
{
70+
///
71+
/// Forced shutdown: disconnects all users immediately after the timeout.
72+
///
73+
FORCED,
74+
75+
///
76+
/// Deny new transactions: waits for existing transactions to finish.
77+
///
78+
DENY_TRANSACTIONS,
79+
80+
///
81+
/// Deny new attachments: waits for existing connections to finish.
82+
///
83+
DENY_ATTACHMENTS
84+
};
85+
3986
///
4087
/// Represents options used to configure database properties through the service manager.
4188
///
@@ -76,9 +123,81 @@ namespace fbcpp
76123
return *this;
77124
}
78125

126+
///
127+
/// Returns the shutdown mode.
128+
///
129+
const std::optional<ShutdownMode>& getShutdownMode() const
130+
{
131+
return shutdownMode;
132+
}
133+
134+
///
135+
/// Sets the shutdown mode.
136+
///
137+
DatabasePropertiesOptions& setShutdownMode(ShutdownMode value)
138+
{
139+
shutdownMode = value;
140+
return *this;
141+
}
142+
143+
///
144+
/// Returns the shutdown type.
145+
///
146+
const std::optional<ShutdownType>& getShutdownType() const
147+
{
148+
return shutdownType;
149+
}
150+
151+
///
152+
/// Sets the shutdown type.
153+
///
154+
DatabasePropertiesOptions& setShutdownType(ShutdownType value)
155+
{
156+
shutdownType = value;
157+
return *this;
158+
}
159+
160+
///
161+
/// Returns the shutdown timeout in seconds.
162+
///
163+
const std::optional<int>& getShutdownTimeout() const
164+
{
165+
return shutdownTimeout;
166+
}
167+
168+
///
169+
/// Sets the shutdown timeout in seconds.
170+
///
171+
DatabasePropertiesOptions& setShutdownTimeout(int value)
172+
{
173+
shutdownTimeout = value;
174+
return *this;
175+
}
176+
177+
///
178+
/// Returns whether the database should be brought online.
179+
///
180+
const std::optional<bool>& getOnline() const
181+
{
182+
return online;
183+
}
184+
185+
///
186+
/// Sets whether the database should be brought online.
187+
///
188+
DatabasePropertiesOptions& setOnline(bool value)
189+
{
190+
online = value;
191+
return *this;
192+
}
193+
79194
private:
80195
std::string database;
81196
std::optional<ReplicaMode> replicaMode;
197+
std::optional<ShutdownMode> shutdownMode;
198+
std::optional<ShutdownType> shutdownType;
199+
std::optional<int> shutdownTimeout;
200+
std::optional<bool> online;
82201
};
83202

84203
///

src/test/DatabaseManager.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,47 @@ BOOST_AUTO_TEST_CASE(databaseSweepAndValidate)
194194
cleanup.dropDatabase();
195195
}
196196

197+
BOOST_AUTO_TEST_CASE(databaseShutdownAndOnline)
198+
{
199+
const auto databasePath = getTempFile("DatabaseManager-shutdownAndOnline.fdb", false);
200+
const auto databaseUri = getTempFile("DatabaseManager-shutdownAndOnline.fdb");
201+
const auto attachmentOptions = AttachmentOptions().setConnectionCharSet("UTF8");
202+
203+
{ // scope
204+
Attachment attachment{
205+
CLIENT, databaseUri, AttachmentOptions().setCreateDatabase(true).setConnectionCharSet("UTF8")};
206+
Transaction transaction{attachment};
207+
Statement createTable{attachment, transaction, "create table test (id integer)"};
208+
BOOST_REQUIRE(createTable.execute(transaction));
209+
transaction.commit();
210+
}
211+
212+
DatabaseManager manager{CLIENT, makeServiceManagerOptions()};
213+
214+
// Shutdown the database
215+
manager.setProperties(DatabasePropertiesOptions()
216+
.setDatabase(databasePath)
217+
.setShutdownMode(ShutdownMode::FULL)
218+
.setShutdownType(ShutdownType::FORCED)
219+
.setShutdownTimeout(0));
220+
221+
// Attachment should fail when the database is shutdown
222+
BOOST_CHECK_THROW(Attachment(CLIENT, databaseUri, attachmentOptions), DatabaseException);
223+
224+
// Bring the database online
225+
manager.setProperties(DatabasePropertiesOptions().setDatabase(databasePath).setOnline(true));
226+
227+
// Attachment should succeed when online
228+
{ // scope
229+
Attachment attachment{CLIENT, databaseUri, attachmentOptions};
230+
Transaction transaction{attachment};
231+
Statement query{attachment, transaction, "select count(*) from test"};
232+
BOOST_REQUIRE(query.execute(transaction));
233+
BOOST_CHECK_EQUAL(query.getInt32(0).value(), 0);
234+
}
235+
236+
Attachment cleanup{CLIENT, databaseUri, attachmentOptions};
237+
cleanup.dropDatabase();
238+
}
239+
197240
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)