public void CanMergeSingleOperations() { var tx = Common.RandomSmartTransaction(); var append = new Append(tx); var unmergedAppendOperations = new[] { append }; var mergedOperations = OperationMerger.Merge(unmergedAppendOperations); var expectedOperation = Assert.Single(mergedOperations); var expectedAppendOperationInstance = Assert.IsType <Append>(expectedOperation); var expectedTx = Assert.Single(expectedAppendOperationInstance.Transactions); Assert.Equal(expectedTx, tx); var remove = new Remove(tx.GetHash()); var unmergedRemoveOperations = new[] { remove }; mergedOperations = OperationMerger.Merge(unmergedRemoveOperations); expectedOperation = Assert.Single(mergedOperations); var expectedRemoveOperationInstance = Assert.IsType <Remove>(expectedOperation); var expectedTxHash = Assert.Single(expectedRemoveOperationInstance.Transactions); Assert.Equal(expectedTxHash, tx.GetHash()); var update = new Update(tx); var unmergedUpdateOperations = new[] { update }; mergedOperations = OperationMerger.Merge(unmergedUpdateOperations); expectedOperation = Assert.Single(mergedOperations); var expectedUpdateOperationInstance = Assert.IsType <Update>(expectedOperation); expectedTx = Assert.Single(expectedUpdateOperationInstance.Transactions); Assert.Equal(expectedTx, tx); }
public void CanMergeComplexOperations() { var tx1 = Common.RandomSmartTransaction(); var tx2 = Common.RandomSmartTransaction(); var tx3 = Common.RandomSmartTransaction(); var tx4 = Common.RandomSmartTransaction(); var tx5 = Common.RandomSmartTransaction(); var tx6 = Common.RandomSmartTransaction(); var tx7 = Common.RandomSmartTransaction(); var tx8 = Common.RandomSmartTransaction(); var a1 = new Append(tx1, tx2); var a2 = new Append(tx3, tx4, tx5); var r1 = new Remove(tx6.GetHash()); var a3 = new Append(tx6); var r2 = new Remove(tx1.GetHash(), tx2.GetHash()); var r3 = new Remove(tx6.GetHash()); var a4 = new Append(tx1); var u1 = new Update(tx7); var u2 = new Update(tx8); var unmergedOperations = new ITxStoreOperation[] { a1, a2, a3, a4, r1, r2, r3, u1, u2 }; var mergedOperations = OperationMerger.Merge(unmergedOperations); Assert.Equal(3, mergedOperations.Count()); unmergedOperations = new ITxStoreOperation[] { u1, u2, r1, r2, r3, a1, a2, a3, a4 }; mergedOperations = OperationMerger.Merge(unmergedOperations); Assert.Equal(3, mergedOperations.Count()); unmergedOperations = new ITxStoreOperation[] { a1, r1, u1, a2, r2, a3, r3, u2, a4 }; mergedOperations = OperationMerger.Merge(unmergedOperations); Assert.Equal(9, mergedOperations.Count()); unmergedOperations = new ITxStoreOperation[] { a1, a2, r1, a3, r2, r3, a4, u1, u2 }; mergedOperations = OperationMerger.Merge(unmergedOperations); Assert.Equal(6, mergedOperations.Count()); var mergedOperationsArray = mergedOperations.ToArray(); Assert.Equal(5, Assert.IsType <Append>(mergedOperationsArray[0]).Transactions.Count()); Assert.Single(Assert.IsType <Remove>(mergedOperationsArray[1]).Transactions); Assert.Single(Assert.IsType <Append>(mergedOperationsArray[2]).Transactions); Assert.Equal(3, Assert.IsType <Remove>(mergedOperationsArray[3]).Transactions.Count()); Assert.Single(Assert.IsType <Append>(mergedOperationsArray[4]).Transactions); Assert.Equal(2, Assert.IsType <Update>(mergedOperationsArray[5]).Transactions.Count()); }
public void CanMergeComplexOperations() { var tx1 = Global.GenerateRandomSmartTransaction(); var tx2 = Global.GenerateRandomSmartTransaction(); var tx3 = Global.GenerateRandomSmartTransaction(); var tx4 = Global.GenerateRandomSmartTransaction(); var tx5 = Global.GenerateRandomSmartTransaction(); var tx6 = Global.GenerateRandomSmartTransaction(); var a1 = new Append(tx1, tx2); var a2 = new Append(tx3, tx4, tx5); var r1 = new Remove(tx6.GetHash()); var a3 = new Append(tx6); var r2 = new Remove(tx1.GetHash(), tx2.GetHash()); var r3 = new Remove(tx6.GetHash()); var a4 = new Append(tx1); var unmergedOperations = new ITxStoreOperation[] { a1, a2, a3, a4, r1, r2, r3 }; var mergedOperations = OperationMerger.Merge(unmergedOperations); Assert.Equal(2, mergedOperations.Count()); unmergedOperations = new ITxStoreOperation[] { r1, r2, r3, a1, a2, a3, a4 }; mergedOperations = OperationMerger.Merge(unmergedOperations); Assert.Equal(2, mergedOperations.Count()); unmergedOperations = new ITxStoreOperation[] { a1, r1, a2, r2, a3, r3, a4 }; mergedOperations = OperationMerger.Merge(unmergedOperations); Assert.Equal(7, mergedOperations.Count()); unmergedOperations = new ITxStoreOperation[] { a1, a2, r1, a3, r2, r3, a4 }; mergedOperations = OperationMerger.Merge(unmergedOperations); Assert.Equal(5, mergedOperations.Count()); var mergedOperationsArray = mergedOperations.ToArray(); Assert.Equal(5, Assert.IsType <Append>(mergedOperationsArray[0]).Transactions.Count()); Assert.Single(Assert.IsType <Remove>(mergedOperationsArray[1]).Transactions); Assert.Single(Assert.IsType <Append>(mergedOperationsArray[2]).Transactions); Assert.Equal(3, Assert.IsType <Remove>(mergedOperationsArray[3]).Transactions.Count()); Assert.Single(Assert.IsType <Append>(mergedOperationsArray[4]).Transactions); }
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); } }