Skip to content

Commit 19596af

Browse files
dangershonysondreb
andauthored
Make sure that each query against database uses a new connection object (#300)
* Make sure that each query against database uses a new connection object - This is the smallest impact and quickest way to fix the issue with connections against sqlite database. - Closes #299 * fix memory conn * Ensure all calls to GetDbConnection is wrapped with using clause * Update version for release 20 * Minor additional improvements on connection usage Co-authored-by: SondreB <sondre@outlook.com>
1 parent 6a743e0 commit 19596af

2 files changed

Lines changed: 66 additions & 35 deletions

File tree

src/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<Version>1.0.19</Version>
3+
<Version>1.0.20</Version>
44
<RuntimeFrameworkVersion>3.1.11</RuntimeFrameworkVersion>
55
<TargetFramework>netcoreapp3.1</TargetFramework>
66
<IsPackable>false</IsPackable>

src/Features/Blockcore.Features.Wallet/Database/WalletStore.cs

Lines changed: 65 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ namespace Blockcore.Features.Wallet.Database
2121
{
2222
public class WalletStore : IWalletStore, IDisposable
2323
{
24-
private readonly SqliteConnection sqliteConnection;
25-
2624
private const int WalletVersion = 1;
2725

2826
/// <summary>
@@ -34,6 +32,9 @@ public class WalletStore : IWalletStore, IDisposable
3432

3533
private readonly Network network;
3634

35+
private readonly string dbPath;
36+
private readonly string dbConnection;
37+
3738
public WalletData WalletData { get; private set; }
3839

3940
/// <summary>
@@ -42,10 +43,10 @@ public class WalletStore : IWalletStore, IDisposable
4243
public WalletStore(Network network, Types.Wallet wallet)
4344
{
4445
var tmpconn = Guid.NewGuid().ToString();
45-
this.inmemorySqliteConnection = new SqliteConnection($"Data Source={tmpconn};Mode=Memory;Cache=Shared");
46-
this.inmemorySqliteConnection.Open();
4746

48-
this.sqliteConnection = new SqliteConnection($"Data Source={tmpconn};Mode=Memory;Cache=Shared");
47+
this.dbConnection = $"Data Source={tmpconn};Mode=Memory;Cache=Shared";
48+
this.inmemorySqliteConnection = new SqliteConnection(this.dbConnection);
49+
this.inmemorySqliteConnection.Open();
4950

5051
this.CreateDatabase();
5152

@@ -55,16 +56,15 @@ public WalletStore(Network network, Types.Wallet wallet)
5556

5657
public WalletStore(Network network, DataFolder dataFolder, Types.Wallet wallet)
5758
{
58-
var dbPath = Path.Combine(dataFolder.WalletFolderPath, $"{wallet.Name}.db");
59+
this.dbPath = Path.Combine(dataFolder.WalletFolderPath, $"{wallet.Name}.db");
60+
this.dbConnection = "Data Source=" + this.dbPath;
5961

6062
if (!Directory.Exists(dataFolder.WalletFolderPath))
6163
{
6264
Directory.CreateDirectory(dataFolder.WalletFolderPath);
6365
}
6466

65-
this.sqliteConnection = new SqliteConnection("Data Source=" + dbPath);
66-
67-
if (!File.Exists(dbPath))
67+
if (!File.Exists(this.dbPath))
6868
{
6969
this.CreateDatabase();
7070
}
@@ -73,7 +73,12 @@ public WalletStore(Network network, DataFolder dataFolder, Types.Wallet wallet)
7373
// Attempt to access the user version, this will crash if the loaded database is V5 and we use V4 packages.
7474
try
7575
{
76-
var walletVersion = this.sqliteConnection.QueryFirst<int>("SELECT WalletVersion FROM WalletData");
76+
var walletVersion = -1;
77+
78+
using (var conn = this.GetDbConnection())
79+
{
80+
walletVersion = conn.QueryFirst<int>("SELECT WalletVersion FROM WalletData");
81+
}
7782

7883
if (walletVersion != WalletVersion)
7984
{
@@ -92,7 +97,7 @@ public WalletStore(Network network, DataFolder dataFolder, Types.Wallet wallet)
9297
var dbBackupPath = Path.Combine(dataFolder.WalletFolderPath, $"{wallet.Name}.error.db");
9398

9499
// Move the problematic database file, which might be a V5 database.
95-
File.Move(dbPath, dbBackupPath);
100+
File.Move(this.dbPath, dbBackupPath);
96101

97102
this.CreateDatabase();
98103
}
@@ -103,6 +108,11 @@ public WalletStore(Network network, DataFolder dataFolder, Types.Wallet wallet)
103108
this.Init(wallet);
104109
}
105110

111+
protected SqliteConnection GetDbConnection()
112+
{
113+
return new SqliteConnection(this.dbConnection);
114+
}
115+
106116
private void Init(Types.Wallet wallet)
107117
{
108118
SqlMapper.AddTypeHandler(new DateTimeOffsetHandler());
@@ -141,7 +151,8 @@ public WalletData GetData()
141151
{
142152
if (this.WalletData == null)
143153
{
144-
this.WalletData = this.sqliteConnection.QueryFirstOrDefault<WalletData>("SELECT *, Id AS Key FROM WalletData WHERE Id = 'Key'");
154+
using var conn = this.GetDbConnection();
155+
this.WalletData = conn.QueryFirstOrDefault<WalletData>("SELECT *, Id AS Key FROM WalletData WHERE Id = 'Key'");
145156
}
146157

147158
return this.WalletData;
@@ -155,7 +166,8 @@ public void SetData(WalletData data)
155166
ON CONFLICT(Id) DO UPDATE SET
156167
EncryptedSeed = @EncryptedSeed, WalletTip = @WalletTip, BlockLocator = @BlockLocator;";
157168

158-
this.sqliteConnection.Execute(sql, data);
169+
using var conn = this.GetDbConnection();
170+
conn.Execute(sql, data);
159171

160172
this.WalletData = data;
161173
}
@@ -170,12 +182,14 @@ public void InsertOrUpdate(TransactionOutputData item)
170182
ON CONFLICT(OutPoint) DO UPDATE SET
171183
IndexInTransaction = @IndexInTransaction, BlockHeight = @BlockHeight, BlockHash = @BlockHash, BlockIndex = @BlockIndex, CreationTime = @CreationTime, IsPropagated = @IsPropagated, IsColdCoinStake = @IsColdCoinStake, AccountIndex = @AccountIndex, MerkleProof = @MerkleProof, Hex = @Hex, SpendingDetailsTransactionId = @SpendingDetailsTransactionId, SpendingDetailsBlockHeight = @SpendingDetailsBlockHeight, SpendingDetailsBlockIndex = @SpendingDetailsBlockIndex, SpendingDetailsIsCoinStake = @SpendingDetailsIsCoinStake, SpendingDetailsCreationTime = @SpendingDetailsCreationTime, SpendingDetailsPayments = @SpendingDetailsPayments, SpendingDetailsHex = @SpendingDetailsHex;";
172184

173-
this.sqliteConnection.Execute(sql, insert);
185+
using var conn = this.GetDbConnection();
186+
conn.Execute(sql, insert);
174187
}
175188

176189
public int CountForAddress(string address)
177190
{
178-
var count = this.sqliteConnection.ExecuteScalar<int>("SELECT COUNT(*) FROM TransactionData WHERE Address = @address", new { address });
191+
using var conn = this.GetDbConnection();
192+
var count = conn.ExecuteScalar<int>("SELECT COUNT(*) FROM TransactionData WHERE Address = @address", new { address });
179193

180194
return count;
181195
}
@@ -185,6 +199,8 @@ public IEnumerable<WalletHistoryData> GetAccountHistory(int accountIndex, bool e
185199
// The result of this method is not guaranteed to be the length
186200
// of the 'take' param. In case some of the inputs we have are
187201
// in the same trx they will be grouped in to a single entry.
202+
using var conn = this.GetDbConnection();
203+
conn.Open();
188204

189205
var sql = @$"SELECT * FROM TransactionData
190206
WHERE AccountIndex == @accountIndex
@@ -193,7 +209,7 @@ AND SpendingDetailsTransactionId IS NOT NULL
193209
ORDER BY SpendingDetailsCreationTime DESC
194210
LIMIT @take OFFSET @skip ";
195211

196-
var historySpentResult = this.sqliteConnection.Query<TransactionData>(sql, new { accountIndex, skip, take }).ToList();
212+
var historySpentResult = conn.Query<TransactionData>(sql, new { accountIndex, skip, take }).ToList();
197213
var historySpent = historySpentResult.Select(this.Convert);
198214

199215
sql = @$"SELECT * FROM TransactionData
@@ -202,7 +218,10 @@ ORDER BY SpendingDetailsCreationTime DESC
202218
ORDER BY CreationTime DESC
203219
LIMIT @take OFFSET @skip";
204220

205-
var historyUnspentResult = this.sqliteConnection.Query<TransactionData>(sql, new { accountIndex, skip, take }).ToList();
221+
var historyUnspentResult = conn.Query<TransactionData>(sql, new { accountIndex, skip, take }).ToList();
222+
223+
conn.Close();
224+
206225
var historyUnspent = historyUnspentResult.Select(this.Convert);
207226

208227
var items = new List<WalletHistoryData>();
@@ -282,7 +301,8 @@ ORDER BY CreationTime DESC
282301

283302
public IEnumerable<TransactionOutputData> GetForAddress(string address)
284303
{
285-
var trxs = this.sqliteConnection.Query<TransactionData>(
304+
using var conn = this.GetDbConnection();
305+
var trxs = conn.Query<TransactionData>(
286306
"SELECT * FROM TransactionData " +
287307
"WHERE Address = @address",
288308
new { address });
@@ -292,7 +312,8 @@ public IEnumerable<TransactionOutputData> GetForAddress(string address)
292312

293313
public IEnumerable<TransactionOutputData> GetUnspentForAddress(string address)
294314
{
295-
var trxs = this.sqliteConnection.Query<TransactionData>(
315+
using var conn = this.GetDbConnection();
316+
var trxs = conn.Query<TransactionData>(
296317
"SELECT * FROM 'TransactionData' " +
297318
"WHERE Address = @address " +
298319
"AND SpendingDetailsTransactionId IS NULL",
@@ -313,7 +334,8 @@ FROM TransactionData
313334
{excludeColdStakeSql}
314335
GROUP BY BlockHeight IS NOT NULL";
315336

316-
var result = this.sqliteConnection.Query(sql, new { address });
337+
using var conn = this.GetDbConnection();
338+
var result = conn.Query(sql, new { address });
317339

318340
var walletBalanceResult = new WalletBalanceResult();
319341

@@ -338,7 +360,8 @@ FROM TransactionData
338360
{excludeColdStakeSql}
339361
GROUP BY BlockHeight IS NOT NULL";
340362

341-
var result = this.sqliteConnection.Query(sql, new { accountIndex });
363+
using var conn = this.GetDbConnection();
364+
var result = conn.Query(sql, new { accountIndex });
342365

343366
var walletBalanceResult = new WalletBalanceResult();
344367

@@ -353,8 +376,10 @@ FROM TransactionData
353376

354377
public TransactionOutputData GetForOutput(OutPoint outPoint)
355378
{
356-
var trx = this.sqliteConnection.QueryFirstOrDefault<TransactionData>(
357-
"SELECT * FROM TransactionData WHERE OutPoint = @outPoint", new { outPoint });
379+
TransactionData trx = null;
380+
381+
using var conn = this.GetDbConnection();
382+
trx = conn.QueryFirstOrDefault<TransactionData>("SELECT * FROM TransactionData WHERE OutPoint = @outPoint", new { outPoint });
358383

359384
if (trx == null)
360385
{
@@ -368,8 +393,8 @@ public TransactionOutputData GetForOutput(OutPoint outPoint)
368393

369394
public bool Remove(OutPoint outPoint)
370395
{
371-
var ret = this.sqliteConnection.ExecuteScalar<int>("DELETE FROM TransactionData WHERE OutPoint = @outPoint", new { outPoint });
372-
396+
using var conn = this.GetDbConnection();
397+
var ret = conn.ExecuteScalar<int>("DELETE FROM TransactionData WHERE OutPoint = @outPoint", new { outPoint });
373398
return ret > 0;
374399
}
375400

@@ -380,17 +405,21 @@ private void UpgradeDatabase(int oldVersion)
380405

381406
private void CreateDatabase()
382407
{
383-
this.sqliteConnection.Execute(
384-
@$"CREATE TABLE WalletData(
408+
using (var conn = GetDbConnection())
409+
{
410+
conn.Open();
411+
412+
conn.Execute(
413+
@$"CREATE TABLE WalletData(
385414
Id VARCHAR(3) NOT NULL PRIMARY KEY,
386415
EncryptedSeed VARCHAR(500) NULL,
387416
WalletName VARCHAR(100) NOT NULL,
388417
WalletTip VARCHAR(75) NOT NULL,
389418
WalletVersion INTEGER NOT NULL,
390419
BlockLocator TEXT NULL)");
391420

392-
this.sqliteConnection.Execute(
393-
@$"CREATE TABLE TransactionData(
421+
conn.Execute(
422+
@$"CREATE TABLE TransactionData(
394423
OutPoint VARCHAR(66) NOT NULL PRIMARY KEY,
395424
Address VARCHAR(34) NOT NULL,
396425
Id VARCHAR(64) NOT NULL,
@@ -416,15 +445,17 @@ SpendingDetailsTransactionId VARCHAR(64) NULL,
416445
SpendingDetailsPayments TEXT NULL,
417446
SpendingDetailsHex TEXT NULL)");
418447

419-
this.sqliteConnection.Execute("CREATE INDEX 'address_index' ON 'TransactionData' ('Address')");
420-
this.sqliteConnection.Execute("CREATE INDEX 'blockheight_index' ON 'TransactionData' ('BlockHeight')");
421-
this.sqliteConnection.Execute("CREATE UNIQUE INDEX 'outpoint_index' ON 'TransactionData' ('OutPoint')");
422-
this.sqliteConnection.Execute("CREATE UNIQUE INDEX 'key_index' ON 'WalletData' ('Id')");
448+
conn.Execute("CREATE INDEX 'address_index' ON 'TransactionData' ('Address')");
449+
conn.Execute("CREATE INDEX 'blockheight_index' ON 'TransactionData' ('BlockHeight')");
450+
conn.Execute("CREATE UNIQUE INDEX 'outpoint_index' ON 'TransactionData' ('OutPoint')");
451+
conn.Execute("CREATE UNIQUE INDEX 'key_index' ON 'WalletData' ('Id')");
452+
453+
conn.Close();
454+
}
423455
}
424456

425457
public void Dispose()
426458
{
427-
this.sqliteConnection?.Dispose();
428459
this.inmemorySqliteConnection?.Dispose();
429460
}
430461

0 commit comments

Comments
 (0)