private void ProcessFilter(FilterModel filter, bool enqueue) { if (enqueue) { ImmatureFilters.Add(filter); } HashChain.AddOrReplace(filter.BlockHeight.Value, filter.BlockHash); }
/// <summary> /// It'll LogError the exceptions. /// If cancelled, it'll LogTrace the exception. /// </summary> private async Task TryCommitToFileAsync(TimeSpan throttle, CancellationToken cancel) { try { // If throttle is requested, then throttle. if (throttle != TimeSpan.Zero) { // Increment the throttle ID and remember the incremented value. int incremented = Interlocked.Increment(ref _throttleId); if (incremented < 21) { await Task.Delay(throttle, cancel); } // If the _throttleId is still the incremented value, then I am the latest CommitToFileAsync request. // In this case I want to make the _throttledId 0 and go ahead and do the writeline. // If the _throttledId is not the incremented value anymore then I am not the latest request here, // So just return, the latest request will do the file write in its own time. if (Interlocked.CompareExchange(ref _throttleId, 0, incremented) != incremented) { return; } } else { Interlocked.Exchange(ref _throttleId, 0); // So to notified the currently throttled threads that they don't have to run. } using (await MatureIndexFileManager.Mutex.LockAsync(cancel)) using (await ImmatureIndexFileManager.Mutex.LockAsync(cancel)) using (await IndexLock.LockAsync(cancel)) { // Don't feed the cancellationToken here I always want this to finish running for safety. var currentImmatureLines = ImmatureFilters.Select(x => x.ToHeightlessLine()); var matureLinesToAppend = currentImmatureLines.SkipLast(100); var immatureLines = currentImmatureLines.TakeLast(100); await MatureIndexFileManager.AppendAllLinesAsync(matureLinesToAppend); await ImmatureIndexFileManager.WriteAllLinesAsync(immatureLines); while (ImmatureFilters.Count > 100) { ImmatureFilters.RemoveFirst(); } } } catch (Exception ex) when(ex is OperationCanceledException || ex is TaskCanceledException || ex is TimeoutException) { Logger.LogTrace <IndexStore>(ex); } catch (Exception ex) { Logger.LogError <IndexStore>(ex); } }
public async Task ForeachFiltersAsync(Func <FilterModel, Task> todo, Height fromHeight, CancellationToken cancel = default) { using (await IndexLock.LockAsync(cancel).ConfigureAwait(false)) using (await MatureIndexAsyncLock.LockAsync(cancel).ConfigureAwait(false)) { var firstImmatureHeight = ImmatureFilters.FirstOrDefault()?.Header?.Height; if (!firstImmatureHeight.HasValue || firstImmatureHeight.Value > fromHeight) { if (MatureIndexFileManager.Exists()) { uint height = StartingHeight; using var sr = MatureIndexFileManager.OpenText(); if (!sr.EndOfStream) { var lineTask = sr.ReadLineAsync(); Task tTask = Task.CompletedTask; string?line = null; while (lineTask is { })
private bool TryProcessFilter(FilterModel filter, bool enqueue) { try { SmartHeaderChain.AddOrReplace(filter.Header); if (enqueue) { ImmatureFilters.Add(filter); } return(true); } catch (Exception ex) { Logger.LogError(ex); return(false); } }
public async Task ForeachFiltersAsync(Func <FilterModel, Task> todo, Height fromHeight) { using (await MatureIndexFileManager.Mutex.LockAsync()) using (await IndexLock.LockAsync()) { var firstImmatureHeight = ImmatureFilters.FirstOrDefault()?.BlockHeight; if (!firstImmatureHeight.HasValue || firstImmatureHeight.Value > fromHeight) { if (MatureIndexFileManager.Exists()) { Height height = StartingHeight; using (var sr = MatureIndexFileManager.OpenText(16384)) { while (!sr.EndOfStream) { var line = await sr.ReadLineAsync(); if (firstImmatureHeight == height) { break; // Let's use our the immature filters from here on. The content is the same, just someone else modified the file. } if (height < fromHeight.Value) { height++; continue; } var filter = FilterModel.FromHeightlessLine(line, height); await todo(filter); height++; } } } } foreach (FilterModel filter in ImmatureFilters) { await todo(filter); } } }
public async Task <FilterModel> RemoveLastFilterAsync(CancellationToken cancel) { FilterModel?filter = null; using (await IndexLock.LockAsync(cancel).ConfigureAwait(false)) { filter = ImmatureFilters.Last(); ImmatureFilters.RemoveLast(); if (SmartHeaderChain.TipHeight != filter.Header.Height) { throw new InvalidOperationException($"{nameof(SmartHeaderChain)} and {nameof(ImmatureFilters)} are not in sync."); } SmartHeaderChain.RemoveTip(); } Reorged?.Invoke(this, filter); AbandonedTasks.AddAndClearCompleted(TryCommitToFileAsync(TimeSpan.FromSeconds(3), cancel)); return(filter); }
public async Task <FilterModel> RemoveLastFilterAsync(CancellationToken cancel) { FilterModel filter = null; using (await IndexLock.LockAsync()) { filter = ImmatureFilters.Last(); ImmatureFilters.RemoveLast(); if (HashChain.TipHeight != filter.BlockHeight.Value) { throw new InvalidOperationException("HashChain and ImmatureFilters are not in sync."); } HashChain.RemoveLast(); } Reorged?.Invoke(this, filter); _ = TryCommitToFileAsync(TimeSpan.FromSeconds(3), cancel); return(filter); }
private bool TryProcessFilter(FilterModel filter, bool enqueue) { try { if (IsWrongFilter(filter)) { return(false); } SmartHeaderChain.AppendTip(filter.Header); if (enqueue) { ImmatureFilters.Add(filter); } return(true); } catch (Exception ex) { Logger.LogError(ex); return(false); } }
public async Task <IEnumerable <FilterModel> > RemoveAllImmmatureFiltersAsync(CancellationToken cancel, bool deleteAndCrashIfMature = false) { var removed = new List <FilterModel>(); using (await IndexLock.LockAsync(cancel).ConfigureAwait(false)) { if (ImmatureFilters.Any()) { Logger.LogWarning($"Filters got corrupted. Reorging {ImmatureFilters.Count} immature filters in an attempt to fix them."); } else { Logger.LogCritical($"Filters got corrupted and have no more immature filters."); if (deleteAndCrashIfMature) { Logger.LogCritical($"Deleting all filters and crashing the software..."); using (await MatureIndexAsyncLock.LockAsync(cancel).ConfigureAwait(false)) using (await ImmatureIndexAsyncLock.LockAsync(cancel).ConfigureAwait(false)) { ImmatureIndexFileManager.DeleteMe(); MatureIndexFileManager.DeleteMe(); } Environment.Exit(2); } } } while (ImmatureFilters.Any()) { removed.Add(await RemoveLastFilterAsync(cancel).ConfigureAwait(false)); } return(removed); }
public async Task ForeachFiltersAsync(Func <FilterModel, Task> todo, Height fromHeight, CancellationToken cancel = default) { using (await MatureIndexFileManager.Mutex.LockAsync(cancel).ConfigureAwait(false)) using (await IndexLock.LockAsync(cancel).ConfigureAwait(false)) { var firstImmatureHeight = ImmatureFilters.FirstOrDefault()?.Header?.Height; if (!firstImmatureHeight.HasValue || firstImmatureHeight.Value > fromHeight) { if (MatureIndexFileManager.Exists()) { uint height = StartingHeight; using var sr = MatureIndexFileManager.OpenText(); if (!sr.EndOfStream) { var lineTask = sr.ReadLineAsync(); Task tTask = Task.CompletedTask; string line = null; while (lineTask != null) { if (firstImmatureHeight == height) { break; // Let's use our the immature filters from here on. The content is the same, just someone else modified the file. } if (line is null) { line = await lineTask.ConfigureAwait(false); } lineTask = sr.EndOfStream ? null : sr.ReadLineAsync(); if (height < fromHeight.Value) { height++; line = null; continue; } var filter = FilterModel.FromLine(line); await tTask.ConfigureAwait(false); tTask = todo(filter); height++; line = null; } await tTask.ConfigureAwait(false); } while (!sr.EndOfStream) { var line = await sr.ReadLineAsync().ConfigureAwait(false); if (firstImmatureHeight == height) { break; // Let's use our the immature filters from here on. The content is the same, just someone else modified the file. } if (height < fromHeight.Value) { height++; continue; } var filter = FilterModel.FromLine(line); await todo(filter).ConfigureAwait(false); height++; } } } foreach (FilterModel filter in ImmatureFilters) { await todo(filter).ConfigureAwait(false); } } }