public async Task InitializeAsync(string workFolderPath, Network network, string operationName, CancellationToken cancel) { using (BenchmarkLogger.Measure(operationName: operationName)) { WorkFolderPath = Guard.NotNullOrEmptyOrWhitespace(nameof(workFolderPath), workFolderPath, trim: true); Network = Guard.NotNull(nameof(network), network); var transactionsFilePath = Path.Combine(WorkFolderPath, "Transactions.dat"); // In Transactions.dat every line starts with the tx id, so the first character is the best for digest creation. TransactionsFileManager = new IoManager(transactionsFilePath); cancel.ThrowIfCancellationRequested(); using (await TransactionsFileAsyncLock.LockAsync(cancel).ConfigureAwait(false)) { IoHelpers.EnsureDirectoryExists(WorkFolderPath); cancel.ThrowIfCancellationRequested(); if (!TransactionsFileManager.Exists()) { await SerializeAllTransactionsNoLockAsync().ConfigureAwait(false); cancel.ThrowIfCancellationRequested(); } await InitializeTransactionsNoLockAsync(cancel).ConfigureAwait(false); } } }
private async Task TryCommitToFileAsync(ITxStoreOperation operation) { try { if (operation is null || operation.IsEmpty) { return; } // Make sure that only one call can continue. lock (OperationsLock) { var isRunning = Operations.Any(); Operations.Add(operation); if (isRunning) { return; } } // Wait until the operation list calms down. IEnumerable <ITxStoreOperation> operationsToExecute; while (true) { var count = Operations.Count; await Task.Delay(100).ConfigureAwait(false); lock (OperationsLock) { if (count == Operations.Count) { // Merge operations. operationsToExecute = OperationMerger.Merge(Operations).ToList(); Operations.Clear(); break; } } } using (await TransactionsFileAsyncLock.LockAsync().ConfigureAwait(false)) { foreach (ITxStoreOperation op in operationsToExecute) { if (op is Append appendOperation) { var toAppends = appendOperation.Transactions; try { await TransactionsFileManager.AppendAllLinesAsync(toAppends.ToBlockchainOrderedLines()).ConfigureAwait(false); } catch { await SerializeAllTransactionsNoLockAsync().ConfigureAwait(false); } } else if (op is Remove removeOperation) { var toRemoves = removeOperation.Transactions; string[] allLines = await TransactionsFileManager.ReadAllLinesAsync().ConfigureAwait(false); var toSerialize = new List <string>(); foreach (var line in allLines) { var startsWith = false; foreach (var toRemoveString in toRemoves.Select(x => x.ToString())) { startsWith = startsWith || line.StartsWith(toRemoveString, StringComparison.Ordinal); } if (!startsWith) { toSerialize.Add(line); } } try { await TransactionsFileManager.WriteAllLinesAsync(toSerialize).ConfigureAwait(false); } catch { await SerializeAllTransactionsNoLockAsync().ConfigureAwait(false); } } else if (op is Update updateOperation) { var toUpdates = updateOperation.Transactions; string[] allLines = await TransactionsFileManager.ReadAllLinesAsync().ConfigureAwait(false); IEnumerable <SmartTransaction> allTransactions = allLines.Select(x => SmartTransaction.FromLine(x, Network)); var toSerialize = new List <SmartTransaction>(); foreach (SmartTransaction tx in allTransactions) { var txsToUpdateWith = toUpdates.Where(x => x == tx); foreach (var txToUpdateWith in txsToUpdateWith) { tx.TryUpdate(txToUpdateWith); } toSerialize.Add(tx); } try { await TransactionsFileManager.WriteAllLinesAsync(toSerialize.ToBlockchainOrderedLines()).ConfigureAwait(false); } catch { await SerializeAllTransactionsNoLockAsync().ConfigureAwait(false); } } else { throw new NotSupportedException(); } } } } catch (Exception ex) { Logger.LogError(ex); } }