private async Task SerializeAllTransactionsNoLockAsync() { List <SmartTransaction> transactionsClone; lock (TransactionsLock) { transactionsClone = Transactions.Values.ToList(); } await TransactionsFileManager.WriteAllLinesAsync(transactionsClone.ToBlockchainOrderedLines()).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 TransactionsFileManager.Mutex.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 SerializeAllTransactionsNoMutexAsync().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 SerializeAllTransactionsNoMutexAsync().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 SerializeAllTransactionsNoMutexAsync().ConfigureAwait(false); } } else { throw new NotSupportedException(); } } } } catch (Exception ex) { Logger.LogError(ex); } }