Skip to content

Commit d4dcd41

Browse files
DennisAMenacedangershonysondreb
authored
Changed LiteDB to v4 for stability. (#242)
* Changed LiteDB to v4 for stability. * Fixed the grouping for the wallet account and history * Generate test data * Regenerated test data for wallet with funds. * Updated with transactions in wallet with funds. * Update launchSettings.json * Add fix to handle downgrade of databases - Rename the database file name for addressindexer. This means users must manually delete the old file to clear up disk space. - Attempt to read the wallet database and if it fails, attempt to rename it away and try again (only one time). * Remove the zero check - The "affectedAddresses" query fails and must be updated to work properly with LiteDB V4. * Fix issue with query against LiteDB - This fixes a crash that occured due to LINQ resulting in an invalid query against V4 of LiteDB. Reverted back to old syntax. * Merge some old code into AddressIndexer * Restore the Address, HotAddress and ColdAddress support * Improve the purge performance - Improves the purge performance greatly by using query to perform a bulk delete. Co-authored-by: dangershony <dan.gershony@gmail.com> Co-authored-by: SondreB <sondre@outlook.com>
1 parent f6bcf76 commit d4dcd41

26 files changed

Lines changed: 166 additions & 119 deletions

src/Blockcore/Blockcore.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<ItemGroup>
2525
<PackageReference Include="ConcurrentHashSet" Version="1.1.0" />
2626
<PackageReference Include="DBreeze" Version="1.97.0" />
27-
<PackageReference Include="LiteDB" Version="5.0.9" />
27+
<PackageReference Include="LiteDB" Version="4.1.4" />
2828
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="4.2.0" />
2929
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
3030
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />

src/Features/Blockcore.Features.BlockStore/AddressIndexing/AddressIndexRepository.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class AddressIndexRepository : MemorySizeCache<string, AddressIndexerData
1313
{
1414
private const string DbAddressDataKey = "AddrData";
1515

16-
private readonly ILiteCollection<AddressIndexerData> addressIndexerDataCollection;
16+
private readonly LiteCollection<AddressIndexerData> addressIndexerDataCollection;
1717

1818
private readonly ILogger logger;
1919

@@ -58,7 +58,7 @@ public List<string> GetAddressesHigherThanHeight(int height)
5858
this.SaveAllItems();
5959

6060
// Need to specify index name explicitly so that it gets used for the query.
61-
IEnumerable<AddressIndexerData> affectedAddresses = this.addressIndexerDataCollection.Find(a => a.BalanceChanges.Select(ab => ab.BalanceChangedHeight).Any(ab => ab > height));
61+
IEnumerable<AddressIndexerData> affectedAddresses = this.addressIndexerDataCollection.Find(Query.GT("BalanceChangedHeightIndex", height));
6262

6363
// Per LiteDb documentation:
6464
// "Returning an IEnumerable your code still connected to datafile.

src/Features/Blockcore.Features.BlockStore/AddressIndexing/AddressIndexer.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
using Blockcore.Networks;
2020
using Blockcore.Utilities;
2121
using LiteDB;
22+
using FileMode = LiteDB.FileMode;
2223
using Microsoft.Extensions.Logging;
2324
using NBitcoin;
2425
using Script = Blockcore.Consensus.ScriptInfo.Script;
@@ -85,7 +86,7 @@ public class AddressIndexer : IAddressIndexer
8586

8687
private LiteDatabase db;
8788

88-
private ILiteCollection<AddressIndexerTipData> tipDataStore;
89+
private LiteCollection<AddressIndexerTipData> tipDataStore;
8990

9091
/// <summary>A mapping between addresses and their balance changes.</summary>
9192
/// <remarks>All access should be protected by <see cref="lockObject"/>.</remarks>
@@ -178,7 +179,8 @@ public void Initialize()
178179

179180
string dbPath = Path.Combine(this.dataFolder.RootPath, AddressIndexerDatabaseFilename);
180181

181-
this.db = new LiteDatabase(new ConnectionString() { Filename = dbPath, Upgrade = true });
182+
FileMode fileMode = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? FileMode.Exclusive : FileMode.Shared;
183+
this.db = new LiteDatabase(new ConnectionString() { Filename = dbPath, Mode = fileMode });
182184

183185
this.addressIndexRepository = new AddressIndexRepository(this.db, this.loggerFactory);
184186

@@ -365,7 +367,9 @@ private void SaveAll()
365367
AddressIndexerTipData tipData = this.tipDataStore.FindAll().FirstOrDefault();
366368

367369
if (tipData == null)
370+
{
368371
tipData = new AddressIndexerTipData();
372+
}
369373

370374
tipData.Height = this.IndexerTip.Height;
371375
tipData.TipHashBytes = this.IndexerTip.HashBlock.ToBytes();
@@ -508,7 +512,9 @@ private bool ProcessBlock(Block block, ChainedHeader header)
508512

509513
// Remove outpoints that were consumed.
510514
foreach (OutPoint consumedOutPoint in inputs.Select(x => x.PrevOut))
515+
{
511516
this.outpointsRepository.RemoveOutPointData(consumedOutPoint);
517+
}
512518
}
513519

514520
return true;

src/Features/Blockcore.Features.BlockStore/AddressIndexing/AddressIndexerOutpointsRepository.cs

Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,21 @@ public sealed class AddressIndexerOutpointsRepository : MemoryCache<string, OutP
1818

1919
/// <summary>Represents the output collection.</summary>
2020
/// <remarks>Should be protected by <see cref="LockObject"/></remarks>
21-
private readonly ILiteCollection<OutPointData> addressIndexerOutPointData;
21+
private readonly LiteCollection<OutPointData> addressIndexerOutPointData;
2222

2323
/// <summary>Represents the rewind data collection.</summary>
2424
/// <remarks>Should be protected by <see cref="LockObject"/></remarks>
25-
private readonly ILiteCollection<AddressIndexerRewindData> addressIndexerRewindData;
25+
private readonly LiteCollection<AddressIndexerRewindData> addressIndexerRewindData;
2626

2727
private readonly ILogger logger;
2828

2929
private readonly int maxCacheItems;
3030

31+
private readonly LiteDatabase db;
32+
3133
public AddressIndexerOutpointsRepository(LiteDatabase db, ILoggerFactory loggerFactory, int maxItems = 60_000)
3234
{
35+
this.db = db;
3336
this.logger = loggerFactory.CreateLogger(this.GetType().FullName);
3437
this.addressIndexerOutPointData = db.GetCollection<OutPointData>(DbOutputsDataKey);
3538
this.addressIndexerRewindData = db.GetCollection<AddressIndexerRewindData>(DbOutputsRewindDataKey);
@@ -67,7 +70,9 @@ protected override void ItemRemovedLocked(CacheItem item)
6770
base.ItemRemovedLocked(item);
6871

6972
if (item.Dirty)
73+
{
7074
this.addressIndexerOutPointData.Upsert(item.Value);
75+
}
7176
}
7277

7378
public bool TryGetOutPointData(OutPoint outPoint, out OutPointData outPointData)
@@ -93,63 +98,51 @@ public bool TryGetOutPointData(OutPoint outPoint, out OutPointData outPointData)
9398

9499
public void SaveAllItems()
95100
{
96-
lock (this.LockObject)
97-
{
98-
CacheItem[] dirtyItems = this.Keys.Where(x => x.Dirty).ToArray();
99-
this.addressIndexerOutPointData.Upsert(dirtyItems.Select(x => x.Value));
101+
CacheItem[] dirtyItems = this.Keys.Where(x => x.Dirty).ToArray();
102+
103+
this.addressIndexerOutPointData.Upsert(dirtyItems.Select(x => x.Value));
100104

101-
foreach (CacheItem dirtyItem in dirtyItems)
102-
dirtyItem.Dirty = false;
105+
foreach (CacheItem dirtyItem in dirtyItems)
106+
{
107+
dirtyItem.Dirty = false;
103108
}
104109
}
105110

106111
/// <summary>Persists rewind data into the repository.</summary>
107112
/// <param name="rewindData">The data to be persisted.</param>
108113
public void RecordRewindData(AddressIndexerRewindData rewindData)
109114
{
110-
lock (this.LockObject)
111-
{
112-
this.addressIndexerRewindData.Upsert(rewindData);
113-
}
115+
this.addressIndexerRewindData.Upsert(rewindData);
114116
}
115117

116118
/// <summary>Deletes rewind data items that were originated at height lower than <paramref name="height"/>.</summary>
117119
/// <param name="height">The threshold below which data will be deleted.</param>
118120
public void PurgeOldRewindData(int height)
119121
{
120-
lock (this.LockObject)
121-
{
122-
var itemsToPurge = this.addressIndexerRewindData.Find(x => x.BlockHeight < height).ToArray();
123-
124-
for (int i = 0; i < itemsToPurge.Count(); i++)
125-
{
126-
this.addressIndexerRewindData.Delete(itemsToPurge[i].BlockHash);
122+
// Delete all in one go based on query. This is more optimal than query, iterate and delete individual records.
123+
int purgedCount = this.addressIndexerRewindData.Delete(x => x.BlockHeight < height);
127124

128-
if (i % 100 == 0)
129-
this.logger.LogInformation("Purging {0}/{1} rewind data items.", i, itemsToPurge.Count());
130-
}
131-
}
125+
this.logger.LogInformation("Purged {0} rewind data items.", purgedCount);
132126
}
133127

134128
/// <summary>Reverts changes made by processing blocks with height higher than <param name="height">.</param></summary>
135129
/// <param name="height">The height above which to restore outpoints.</param>
136130
public void RewindDataAboveHeight(int height)
137131
{
138-
lock (this.LockObject)
139-
{
140-
IEnumerable<AddressIndexerRewindData> toRestore = this.addressIndexerRewindData.Find(x => x.BlockHeight > height);
132+
IEnumerable<AddressIndexerRewindData> toRestore = this.addressIndexerRewindData.Find(x => x.BlockHeight > height);
141133

142-
this.logger.LogDebug("Restoring data for {0} blocks.", toRestore.Count());
134+
this.logger.LogDebug("Restoring data for {0} blocks.", toRestore.Count());
143135

144-
foreach (AddressIndexerRewindData rewindData in toRestore)
136+
foreach (AddressIndexerRewindData rewindData in toRestore)
137+
{
138+
// Put the spent outputs back into the cache.
139+
foreach (OutPointData outPointData in rewindData.SpentOutputs)
145140
{
146-
// Put the spent outputs back into the cache.
147-
foreach (OutPointData outPointData in rewindData.SpentOutputs)
148-
this.AddOutPointData(outPointData);
149-
150-
// This rewind data item should now be removed from the collection.
151-
this.addressIndexerRewindData.Delete(rewindData.BlockHash);
141+
this.AddOutPointData(outPointData);
152142
}
143+
144+
// This rewind data item should now be removed from the collection.
145+
this.addressIndexerRewindData.Delete(rewindData.BlockHash);
153146
}
154147
}
155148

0 commit comments

Comments
 (0)