Skip to content

Commit 5a5f158

Browse files
committed
Parallel backup/restore support (#833).
1 parent 22746fa commit 5a5f158

9 files changed

Lines changed: 96 additions & 65 deletions

File tree

src/FirebirdSql.Data.FirebirdClient/Common/IscCodes.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,11 @@ internal static class IscCodes
522522
public const int isc_spb_bkp_length = 7;
523523
public const int isc_spb_bkp_skip_data = 8;
524524
public const int isc_spb_bkp_stat = 15;
525+
public const int isc_spb_bkp_keyholder = 16;
526+
public const int isc_spb_bkp_keyname = 17;
527+
public const int isc_spb_bkp_crypt = 18;
528+
public const int isc_spb_bkp_include_data = 19;
529+
public const int isc_spb_bkp_parallel_workers = 21;
525530
public const int isc_spb_bkp_ignore_checksums = 0x01;
526531
public const int isc_spb_bkp_ignore_limbo = 0x02;
527532
public const int isc_spb_bkp_metadata_only = 0x04;
@@ -531,19 +536,26 @@ internal static class IscCodes
531536
public const int isc_spb_bkp_convert = 0x40;
532537
public const int isc_spb_bkp_expand = 0x80;
533538
public const int isc_spb_bkp_no_triggers = 0x8000;
539+
public const int isc_spb_bkp_zip = 0x010000;
540+
public const int isc_spb_bkp_direct_io = 0x020000;
534541

535542
#endregion
536543

537544
#region Restore Service
538545

539546
public const int isc_spb_res_skip_data = isc_spb_bkp_skip_data;
547+
public const int isc_spb_res_include_data = isc_spb_bkp_include_data;
540548
public const int isc_spb_res_buffers = 9;
541549
public const int isc_spb_res_page_size = 10;
542550
public const int isc_spb_res_length = 11;
543551
public const int isc_spb_res_access_mode = 12;
544552
public const int isc_spb_res_fix_fss_data = 13;
545553
public const int isc_spb_res_fix_fss_metadata = 14;
554+
public const int isc_spb_res_keyholder = isc_spb_bkp_keyholder;
555+
public const int isc_spb_res_keyname = isc_spb_bkp_keyname;
556+
public const int isc_spb_res_crypt = isc_spb_bkp_crypt;
546557
public const int isc_spb_res_stat = isc_spb_bkp_stat;
558+
public const int isc_spb_res_parallel_workers = isc_spb_bkp_parallel_workers;
547559
public const int isc_spb_res_metadata_only = isc_spb_bkp_metadata_only;
548560
public const int isc_spb_res_deactivate_idx = 0x0100;
549561
public const int isc_spb_res_no_shadow = 0x0200;
@@ -552,6 +564,8 @@ internal static class IscCodes
552564
public const int isc_spb_res_replace = 0x1000;
553565
public const int isc_spb_res_create = 0x2000;
554566
public const int isc_spb_res_use_all_space = 0x4000;
567+
public const int isc_spb_res_direct_io = isc_spb_bkp_direct_io;
568+
public const int isc_spb_res_replica_mode = 20;
555569

556570
public const int isc_spb_res_am_readonly = isc_spb_prp_am_readonly;
557571
public const int isc_spb_res_am_readwrite = isc_spb_prp_am_readwrite;

src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbConnectionInternal.cs

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ internal class FbConnectionInternal
3737
private DatabaseBase _db;
3838
private FbTransaction _activeTransaction;
3939
private HashSet<IFbPreparedCommand> _preparedCommands;
40-
private ConnectionString _options;
40+
private ConnectionString _connectionStringOptions;
4141
private FbConnection _owningConnection;
4242
private FbEnlistmentNotification _enlistmentNotification;
4343

@@ -76,9 +76,9 @@ public bool IsEnlisted
7676
}
7777
}
7878

79-
public ConnectionString Options
79+
public ConnectionString ConnectionStringOptions
8080
{
81-
get { return _options; }
81+
get { return _connectionStringOptions; }
8282
}
8383

8484
public bool CancelDisabled { get; private set; }
@@ -91,7 +91,7 @@ public FbConnectionInternal(ConnectionString options)
9191
{
9292
_preparedCommands = new HashSet<IFbPreparedCommand>();
9393

94-
_options = options;
94+
_connectionStringOptions = options;
9595
}
9696

9797
#endregion
@@ -100,7 +100,7 @@ public FbConnectionInternal(ConnectionString options)
100100

101101
public void CreateDatabase(int pageSize, bool forcedWrites, bool overwrite)
102102
{
103-
var db = ClientFactory.CreateDatabase(_options);
103+
var db = ClientFactory.CreateDatabase(_connectionStringOptions);
104104

105105
var dpb = db.CreateDatabaseParameterBuffer();
106106

@@ -109,14 +109,14 @@ public void CreateDatabase(int pageSize, bool forcedWrites, bool overwrite)
109109
dpb.Append(IscCodes.isc_dpb_utf8_filename, 0);
110110
}
111111
dpb.Append(IscCodes.isc_dpb_dummy_packet_interval, new byte[] { 120, 10, 0, 0 });
112-
dpb.Append(IscCodes.isc_dpb_sql_dialect, new byte[] { (byte)_options.Dialect, 0, 0, 0 });
113-
if (!string.IsNullOrEmpty(_options.UserID))
112+
dpb.Append(IscCodes.isc_dpb_sql_dialect, new byte[] { (byte)_connectionStringOptions.Dialect, 0, 0, 0 });
113+
if (!string.IsNullOrEmpty(_connectionStringOptions.UserID))
114114
{
115-
dpb.Append(IscCodes.isc_dpb_user_name, _options.UserID);
115+
dpb.Append(IscCodes.isc_dpb_user_name, _connectionStringOptions.UserID);
116116
}
117-
if (_options.Charset.Length > 0)
117+
if (_connectionStringOptions.Charset.Length > 0)
118118
{
119-
if (!Charset.TryGetByName(_options.Charset, out var charset))
119+
if (!Charset.TryGetByName(_connectionStringOptions.Charset, out var charset))
120120
throw new ArgumentException("Invalid character set specified.");
121121
dpb.Append(IscCodes.isc_dpb_set_db_charset, charset.Name);
122122
}
@@ -131,13 +131,13 @@ public void CreateDatabase(int pageSize, bool forcedWrites, bool overwrite)
131131

132132
try
133133
{
134-
if (string.IsNullOrEmpty(_options.UserID) && string.IsNullOrEmpty(_options.Password))
134+
if (string.IsNullOrEmpty(_connectionStringOptions.UserID) && string.IsNullOrEmpty(_connectionStringOptions.Password))
135135
{
136-
db.CreateDatabaseWithTrustedAuth(dpb, _options.Database, _options.CryptKey);
136+
db.CreateDatabaseWithTrustedAuth(dpb, _connectionStringOptions.Database, _connectionStringOptions.CryptKey);
137137
}
138138
else
139139
{
140-
db.CreateDatabase(dpb, _options.Database, _options.CryptKey);
140+
db.CreateDatabase(dpb, _connectionStringOptions.Database, _connectionStringOptions.CryptKey);
141141
}
142142
}
143143
finally
@@ -147,7 +147,7 @@ public void CreateDatabase(int pageSize, bool forcedWrites, bool overwrite)
147147
}
148148
public async Task CreateDatabaseAsync(int pageSize, bool forcedWrites, bool overwrite, CancellationToken cancellationToken = default)
149149
{
150-
var db = await ClientFactory.CreateDatabaseAsync(_options, cancellationToken).ConfigureAwait(false);
150+
var db = await ClientFactory.CreateDatabaseAsync(_connectionStringOptions, cancellationToken).ConfigureAwait(false);
151151

152152
var dpb = db.CreateDatabaseParameterBuffer();
153153

@@ -156,14 +156,14 @@ public async Task CreateDatabaseAsync(int pageSize, bool forcedWrites, bool over
156156
dpb.Append(IscCodes.isc_dpb_utf8_filename, 0);
157157
}
158158
dpb.Append(IscCodes.isc_dpb_dummy_packet_interval, new byte[] { 120, 10, 0, 0 });
159-
dpb.Append(IscCodes.isc_dpb_sql_dialect, new byte[] { (byte)_options.Dialect, 0, 0, 0 });
160-
if (!string.IsNullOrEmpty(_options.UserID))
159+
dpb.Append(IscCodes.isc_dpb_sql_dialect, new byte[] { (byte)_connectionStringOptions.Dialect, 0, 0, 0 });
160+
if (!string.IsNullOrEmpty(_connectionStringOptions.UserID))
161161
{
162-
dpb.Append(IscCodes.isc_dpb_user_name, _options.UserID);
162+
dpb.Append(IscCodes.isc_dpb_user_name, _connectionStringOptions.UserID);
163163
}
164-
if (_options.Charset.Length > 0)
164+
if (_connectionStringOptions.Charset.Length > 0)
165165
{
166-
if (!Charset.TryGetByName(_options.Charset, out var charset))
166+
if (!Charset.TryGetByName(_connectionStringOptions.Charset, out var charset))
167167
throw new ArgumentException("Invalid character set specified.");
168168
dpb.Append(IscCodes.isc_dpb_set_db_charset, charset.Name);
169169
}
@@ -178,13 +178,13 @@ public async Task CreateDatabaseAsync(int pageSize, bool forcedWrites, bool over
178178

179179
try
180180
{
181-
if (string.IsNullOrEmpty(_options.UserID) && string.IsNullOrEmpty(_options.Password))
181+
if (string.IsNullOrEmpty(_connectionStringOptions.UserID) && string.IsNullOrEmpty(_connectionStringOptions.Password))
182182
{
183-
await db.CreateDatabaseWithTrustedAuthAsync(dpb, _options.Database, _options.CryptKey, cancellationToken).ConfigureAwait(false);
183+
await db.CreateDatabaseWithTrustedAuthAsync(dpb, _connectionStringOptions.Database, _connectionStringOptions.CryptKey, cancellationToken).ConfigureAwait(false);
184184
}
185185
else
186186
{
187-
await db.CreateDatabaseAsync(dpb, _options.Database, _options.CryptKey, cancellationToken).ConfigureAwait(false);
187+
await db.CreateDatabaseAsync(dpb, _connectionStringOptions.Database, _connectionStringOptions.CryptKey, cancellationToken).ConfigureAwait(false);
188188
}
189189
}
190190
finally
@@ -195,16 +195,16 @@ public async Task CreateDatabaseAsync(int pageSize, bool forcedWrites, bool over
195195

196196
public void DropDatabase()
197197
{
198-
var db = ClientFactory.CreateDatabase(_options);
198+
var db = ClientFactory.CreateDatabase(_connectionStringOptions);
199199
try
200200
{
201-
if (string.IsNullOrEmpty(_options.UserID) && string.IsNullOrEmpty(_options.Password))
201+
if (string.IsNullOrEmpty(_connectionStringOptions.UserID) && string.IsNullOrEmpty(_connectionStringOptions.Password))
202202
{
203-
db.AttachWithTrustedAuth(BuildDpb(db, _options), _options.Database, _options.CryptKey);
203+
db.AttachWithTrustedAuth(BuildDpb(db, _connectionStringOptions), _connectionStringOptions.Database, _connectionStringOptions.CryptKey);
204204
}
205205
else
206206
{
207-
db.Attach(BuildDpb(db, _options), _options.Database, _options.CryptKey);
207+
db.Attach(BuildDpb(db, _connectionStringOptions), _connectionStringOptions.Database, _connectionStringOptions.CryptKey);
208208
}
209209
db.DropDatabase();
210210
}
@@ -215,16 +215,16 @@ public void DropDatabase()
215215
}
216216
public async Task DropDatabaseAsync(CancellationToken cancellationToken = default)
217217
{
218-
var db = await ClientFactory.CreateDatabaseAsync(_options, cancellationToken).ConfigureAwait(false);
218+
var db = await ClientFactory.CreateDatabaseAsync(_connectionStringOptions, cancellationToken).ConfigureAwait(false);
219219
try
220220
{
221-
if (string.IsNullOrEmpty(_options.UserID) && string.IsNullOrEmpty(_options.Password))
221+
if (string.IsNullOrEmpty(_connectionStringOptions.UserID) && string.IsNullOrEmpty(_connectionStringOptions.Password))
222222
{
223-
await db.AttachWithTrustedAuthAsync(BuildDpb(db, _options), _options.Database, _options.CryptKey, cancellationToken).ConfigureAwait(false);
223+
await db.AttachWithTrustedAuthAsync(BuildDpb(db, _connectionStringOptions), _connectionStringOptions.Database, _connectionStringOptions.CryptKey, cancellationToken).ConfigureAwait(false);
224224
}
225225
else
226226
{
227-
await db.AttachAsync(BuildDpb(db, _options), _options.Database, _options.CryptKey, cancellationToken).ConfigureAwait(false);
227+
await db.AttachAsync(BuildDpb(db, _connectionStringOptions), _connectionStringOptions.Database, _connectionStringOptions.CryptKey, cancellationToken).ConfigureAwait(false);
228228
}
229229
await db.DropDatabaseAsync(cancellationToken).ConfigureAwait(false);
230230
}
@@ -240,20 +240,20 @@ public async Task DropDatabaseAsync(CancellationToken cancellationToken = defaul
240240

241241
public void Connect()
242242
{
243-
if (!Charset.TryGetByName(_options.Charset, out var charset))
243+
if (!Charset.TryGetByName(_connectionStringOptions.Charset, out var charset))
244244
throw new ArgumentException("Invalid character set specified.");
245245

246246
try
247247
{
248-
_db = ClientFactory.CreateDatabase(_options);
249-
var dpb = BuildDpb(_db, _options);
250-
if (string.IsNullOrEmpty(_options.UserID) && string.IsNullOrEmpty(_options.Password))
248+
_db = ClientFactory.CreateDatabase(_connectionStringOptions);
249+
var dpb = BuildDpb(_db, _connectionStringOptions);
250+
if (string.IsNullOrEmpty(_connectionStringOptions.UserID) && string.IsNullOrEmpty(_connectionStringOptions.Password))
251251
{
252-
_db.AttachWithTrustedAuth(dpb, _options.Database, _options.CryptKey);
252+
_db.AttachWithTrustedAuth(dpb, _connectionStringOptions.Database, _connectionStringOptions.CryptKey);
253253
}
254254
else
255255
{
256-
_db.Attach(dpb, _options.Database, _options.CryptKey);
256+
_db.Attach(dpb, _connectionStringOptions.Database, _connectionStringOptions.CryptKey);
257257
}
258258
}
259259
catch (IscException ex)
@@ -263,20 +263,20 @@ public void Connect()
263263
}
264264
public async Task ConnectAsync(CancellationToken cancellationToken = default)
265265
{
266-
if (!Charset.TryGetByName(_options.Charset, out var charset))
266+
if (!Charset.TryGetByName(_connectionStringOptions.Charset, out var charset))
267267
throw new ArgumentException("Invalid character set specified.");
268268

269269
try
270270
{
271-
_db = await ClientFactory.CreateDatabaseAsync(_options, cancellationToken).ConfigureAwait(false);
272-
var dpb = BuildDpb(_db, _options);
273-
if (string.IsNullOrEmpty(_options.UserID) && string.IsNullOrEmpty(_options.Password))
271+
_db = await ClientFactory.CreateDatabaseAsync(_connectionStringOptions, cancellationToken).ConfigureAwait(false);
272+
var dpb = BuildDpb(_db, _connectionStringOptions);
273+
if (string.IsNullOrEmpty(_connectionStringOptions.UserID) && string.IsNullOrEmpty(_connectionStringOptions.Password))
274274
{
275-
await _db.AttachWithTrustedAuthAsync(dpb, _options.Database, _options.CryptKey, cancellationToken).ConfigureAwait(false);
275+
await _db.AttachWithTrustedAuthAsync(dpb, _connectionStringOptions.Database, _connectionStringOptions.CryptKey, cancellationToken).ConfigureAwait(false);
276276
}
277277
else
278278
{
279-
await _db.AttachAsync(dpb, _options.Database, _options.CryptKey, cancellationToken).ConfigureAwait(false);
279+
await _db.AttachAsync(dpb, _connectionStringOptions.Database, _connectionStringOptions.CryptKey, cancellationToken).ConfigureAwait(false);
280280
}
281281
}
282282
catch (IscException ex)
@@ -299,7 +299,7 @@ public void Disconnect()
299299
{
300300
_db = null;
301301
_owningConnection = null;
302-
_options = null;
302+
_connectionStringOptions = null;
303303
}
304304
}
305305
}
@@ -317,7 +317,7 @@ public async Task DisconnectAsync(CancellationToken cancellationToken = default)
317317
{
318318
_db = null;
319319
_owningConnection = null;
320-
_options = null;
320+
_connectionStringOptions = null;
321321
}
322322
}
323323
}

src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbConnectionPoolManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ internal void Release(FbConnectionInternal connection, bool returnToAvailable)
197197
{
198198
CheckDisposed();
199199

200-
if (_pools.TryGetValue(connection.Options.NormalizedConnectionString, out var pool))
200+
if (_pools.TryGetValue(connection.ConnectionStringOptions.NormalizedConnectionString, out var pool))
201201
{
202202
pool.ReleaseConnection(connection, returnToAvailable);
203203
}

src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbEnlistmentNotification.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public void Commit(Enlistment enlistment)
7878

7979
if (_connection != null)
8080
{
81-
if (!_connection.Options.Pooling && (_connection.OwningConnection == null || _connection.OwningConnection.IsClosed))
81+
if (!_connection.ConnectionStringOptions.Pooling && (_connection.OwningConnection == null || _connection.OwningConnection.IsClosed))
8282
{
8383
_connection.Disconnect();
8484
}
@@ -112,7 +112,7 @@ public void Rollback(Enlistment enlistment)
112112

113113
if (_connection != null)
114114
{
115-
if (!_connection.Options.Pooling && (_connection.OwningConnection == null || _connection.OwningConnection.IsClosed))
115+
if (!_connection.ConnectionStringOptions.Pooling && (_connection.OwningConnection == null || _connection.OwningConnection.IsClosed))
116116
{
117117
_connection.Disconnect();
118118
}

src/FirebirdSql.Data.FirebirdClient/Services/FbBackup.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ public void Execute()
6565
startSpb.Append2(IscCodes.isc_spb_bkp_skip_data, SkipData);
6666
startSpb.Append(IscCodes.isc_spb_options, (int)Options);
6767
startSpb.Append2(IscCodes.isc_spb_bkp_stat, Statistics.BuildConfiguration());
68+
if (ConnectionStringOptions.ParallelWorkers > 0)
69+
startSpb.Append(IscCodes.isc_spb_bkp_parallel_workers, ConnectionStringOptions.ParallelWorkers);
6870
StartTask(startSpb);
6971
if (Verbose)
7072
{
@@ -107,6 +109,8 @@ public async Task ExecuteAsync(CancellationToken cancellationToken = default)
107109
startSpb.Append2(IscCodes.isc_spb_bkp_skip_data, SkipData);
108110
startSpb.Append(IscCodes.isc_spb_options, (int)Options);
109111
startSpb.Append2(IscCodes.isc_spb_bkp_stat, Statistics.BuildConfiguration());
112+
if (ConnectionStringOptions.ParallelWorkers > 0)
113+
startSpb.Append(IscCodes.isc_spb_bkp_parallel_workers, ConnectionStringOptions.ParallelWorkers);
110114
await StartTaskAsync(startSpb, cancellationToken).ConfigureAwait(false);
111115
if (Verbose)
112116
{

src/FirebirdSql.Data.FirebirdClient/Services/FbRestore.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ public void Execute()
8080
startSpb.Append2(IscCodes.isc_spb_res_skip_data, SkipData);
8181
startSpb.Append(IscCodes.isc_spb_options, (int)Options);
8282
startSpb.Append2(IscCodes.isc_spb_res_stat, Statistics.BuildConfiguration());
83+
if (ConnectionStringOptions.ParallelWorkers > 0)
84+
startSpb.Append(IscCodes.isc_spb_bkp_parallel_workers, ConnectionStringOptions.ParallelWorkers);
8385
StartTask(startSpb);
8486
if (Verbose)
8587
{
@@ -123,6 +125,8 @@ public async Task ExecuteAsync(CancellationToken cancellationToken = default)
123125
startSpb.Append2(IscCodes.isc_spb_res_skip_data, SkipData);
124126
startSpb.Append(IscCodes.isc_spb_options, (int)Options);
125127
startSpb.Append2(IscCodes.isc_spb_res_stat, Statistics.BuildConfiguration());
128+
if (ConnectionStringOptions.ParallelWorkers > 0)
129+
startSpb.Append(IscCodes.isc_spb_bkp_parallel_workers, ConnectionStringOptions.ParallelWorkers);
126130
await StartTaskAsync(startSpb, cancellationToken).ConfigureAwait(false);
127131
if (Verbose)
128132
{

0 commit comments

Comments
 (0)