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);
        }
Example #4
0
        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);
            }
        }