예제 #1
0
        /// <inheritdoc/>
        public async Task <IList <T?> > GetAllAsync(ITransaction?transaction, IEnumerable <T> keys)
        {
            IgniteArgumentCheck.NotNull(keys, nameof(keys));

            using var iterator = keys.GetEnumerator();

            if (!iterator.MoveNext())
            {
                return(Array.Empty <T>());
            }

            var schema = await _table.GetLatestSchemaAsync().ConfigureAwait(false);

            var tx = transaction.ToInternal();

            using var writer = new PooledArrayBufferWriter();
            _ser.WriteMultiple(writer, tx, schema, iterator, keyOnly: true);

            using var resBuf = await DoOutInOpAsync(ClientOp.TupleGetAll, tx, writer).ConfigureAwait(false);

            var resSchema = await _table.ReadSchemaAsync(resBuf).ConfigureAwait(false);

            // TODO: Read value parts only (IGNITE-16022).
            return(_ser.ReadMultipleNullable(resBuf, resSchema));
        }
예제 #2
0
        /// <inheritdoc/>
        public async Task <bool> DeleteExactAsync(ITransaction?transaction, T record)
        {
            IgniteArgumentCheck.NotNull(record, nameof(record));

            using var resBuf = await DoRecordOutOpAsync(ClientOp.TupleDeleteExact, transaction, record).ConfigureAwait(false);

            return(resBuf.GetReader().ReadBoolean());
        }
예제 #3
0
        /// <inheritdoc/>
        public async Task <bool> DeleteAsync(ITransaction?transaction, T key)
        {
            IgniteArgumentCheck.NotNull(key, nameof(key));

            using var resBuf = await DoRecordOutOpAsync(ClientOp.TupleDelete, transaction, key, keyOnly : true).ConfigureAwait(false);

            return(resBuf.GetReader().ReadBoolean());
        }
        private ITransaction GetLoadModeTransaction()
        {
            if (_loadModeTransaction == null)
            {
                _loadModeTransaction = _objectManager.CreateTransaction();
            }

            return(_loadModeTransaction);
        }
        private ITransaction GetCommandTransaction()
        {
            if (_cmdTransaction == null)
            {
                _cmdTransaction = _objectManager.CreateTransaction();
            }

            return(_cmdTransaction);
        }
예제 #6
0
        /// <inheritdoc/>
        public async Task <T?> GetAsync(ITransaction?transaction, T key)
        {
            IgniteArgumentCheck.NotNull(key, nameof(key));

            using var resBuf = await DoRecordOutOpAsync(ClientOp.TupleGet, transaction, key, keyOnly : true).ConfigureAwait(false);

            var resSchema = await _table.ReadSchemaAsync(resBuf).ConfigureAwait(false);

            return(_ser.ReadValue(resBuf, resSchema, key));
        }
예제 #7
0
        /// <inheritdoc/>
        public async Task <T?> GetAndReplaceAsync(ITransaction?transaction, T record)
        {
            IgniteArgumentCheck.NotNull(record, nameof(record));

            using var resBuf = await DoRecordOutOpAsync(ClientOp.TupleGetAndReplace, transaction, record).ConfigureAwait(false);

            var resSchema = await _table.ReadSchemaAsync(resBuf).ConfigureAwait(false);

            return(_ser.ReadValue(resBuf, resSchema, record));
        }
        public void FinishLoadMode()
        {
            _loadMode = false;

            if (_loadModeTransaction != null)
            {
                _loadModeTransaction.Commit();
            }

            _loadModeTransaction = null;
        }
        /// <summary>
        /// Rollbacks transaction.
        /// </summary>
        public virtual void Rollback()
        {
            if (_transaction == null || !_transaction.IsActive)
            {
                throw new InvalidOperationException("Oops! We don't have an active transaction");
            }

            _transaction.Rollback();
            _transaction.Dispose();
            _transaction = null;
        }
        /// <summary>
        /// Commits transaction.
        /// </summary>
        /// <exception cref="InvalidOperationException">Oops! We don't have an active transaction</exception>
        public void Commit()
        {
            if (_transaction == null || !_transaction.IsActive)
            {
                throw new InvalidOperationException("Oops! We don't have an active transaction");
            }

            _transaction.Commit();
            _transaction.Dispose();
            _transaction = null;
        }
        /// <summary>
        /// Rollbacks transaction asynchronously.
        /// </summary>
        /// <returns></returns>
        public async Task RollbackAsync()
        {
            if (_transaction == null || !_transaction.IsActive)
            {
                throw new InvalidOperationException("Oops! We don't have an active transaction");
            }

            await _transaction.RollbackAsync();

            _transaction.Dispose();
            _transaction = null;
        }
예제 #12
0
        private bool?TryAcquire(IUmbracoDatabase db, string tempId, string updatedTempId)
        {
            // Creates a separate transaction to the DB instance so we aren't allocating tons of new DB instances for each transaction
            // since this is executed in a tight loop

            ITransaction?transaction = null;

            try
            {
                transaction = db.GetTransaction(IsolationLevel.Serializable);

                // the row
                var mainDomRows = db.Fetch <KeyValueDto>("SELECT * FROM umbracoKeyValue WHERE [key] = @key",
                                                         new { key = MainDomKey });

                if (mainDomRows.Count == 0 || mainDomRows[0].Value == updatedTempId)
                {
                    // the other main dom has updated our record
                    // Or the other maindom shutdown super fast and just deleted the record
                    // which indicates that we
                    // can acquire it and it has shutdown.

                    // so now we update the row with our appdomain id
                    InsertLockRecord(_lockId, db);
                    _logger.LogDebug("Acquired with ID {LockId}", _lockId);
                    return(true);
                }
                else if (mainDomRows.Count == 1 && (!mainDomRows[0].Value?.StartsWith(tempId) ?? false))
                {
                    // in this case, the prefixed ID is different which  means
                    // another new AppDomain has come online and is wanting to take over. In that case, we will not
                    // acquire.

                    _logger.LogDebug("Cannot acquire, another booting application detected.");
                    return(false);
                }
            }
            catch (Exception ex)
            {
                // unexpected
                _logger.LogError(ex, "Unexpected error, waiting for existing MainDom is canceled.");
                _errorDuringAcquiring = true;
                return(false);
            }
            finally
            {
                transaction?.Complete();
                transaction?.Dispose();
            }

            return(null); // continue
        }
예제 #13
0
        /// <summary>
        /// Gets transaction as internal <see cref="Transaction"/> class.
        /// </summary>
        /// <param name="tx">Transaction.</param>
        /// <returns>Internal transaction.</returns>
        /// <exception cref="TransactionException">When provided transaction is not supported.</exception>
        public static Transaction?ToInternal(this ITransaction?tx)
        {
            if (tx == null)
            {
                return(null);
            }

            if (tx is Transaction t)
            {
                return(t);
            }

            throw new TransactionException("Unsupported transaction implementation: " + tx.GetType());
        }
예제 #14
0
        private async Task <PooledBuffer> DoRecordOutOpAsync(
            ClientOp op,
            ITransaction?transaction,
            T record,
            bool keyOnly = false)
        {
            var schema = await _table.GetLatestSchemaAsync().ConfigureAwait(false);

            var tx = transaction.ToInternal();

            using var writer = new PooledArrayBufferWriter();
            _ser.Write(writer, tx, schema, record, keyOnly);

            return(await DoOutInOpAsync(op, tx, writer).ConfigureAwait(false));
        }
예제 #15
0
        /// <inheritdoc/>
        public async Task <bool> ReplaceAsync(ITransaction?transaction, T record, T newRecord)
        {
            IgniteArgumentCheck.NotNull(record, nameof(record));

            var schema = await _table.GetLatestSchemaAsync().ConfigureAwait(false);

            var tx = transaction.ToInternal();

            using var writer = new PooledArrayBufferWriter();
            _ser.WriteTwo(writer, tx, schema, record, newRecord);

            using var resBuf = await DoOutInOpAsync(ClientOp.TupleReplaceExact, tx, writer).ConfigureAwait(false);

            return(resBuf.GetReader().ReadBoolean());
        }
        public void FinishWithTransaction()
        {
            __lastEventRecievedTimestamp = DateTime.UtcNow;
            _numberOfObjectsLoaded++;

            // We're our of load mode, and dealing with last event
            if (!_loadMode && _loadModeTransaction == null)
            {
                // Commit the command transaction
                if (_cmdTransaction != null)
                {
                    _cmdTransaction.Commit();
                    _cmdTransaction = null;
                }
            }
        }
예제 #17
0
        /// <inheritdoc/>
        public async Task UpsertAllAsync(ITransaction?transaction, IEnumerable <T> records)
        {
            IgniteArgumentCheck.NotNull(records, nameof(records));

            using var iterator = records.GetEnumerator();

            if (!iterator.MoveNext())
            {
                return;
            }

            var schema = await _table.GetLatestSchemaAsync().ConfigureAwait(false);

            var tx = transaction.ToInternal();

            using var writer = new PooledArrayBufferWriter();
            _ser.WriteMultiple(writer, tx, schema, iterator);

            using var resBuf = await DoOutInOpAsync(ClientOp.TupleUpsertAll, tx, writer).ConfigureAwait(false);
        }
예제 #18
0
        private bool AcquireWhenMaxWaitTimeElapsed(IUmbracoDatabase db)
        {
            // Creates a separate transaction to the DB instance so we aren't allocating tons of new DB instances for each transaction
            // since this is executed in a tight loop

            // if the timeout has elapsed, it either means that the other main dom is taking too long to shutdown,
            // or it could mean that the previous appdomain was terminated and didn't clear out the main dom SQL row
            // and it's just been left as an orphan row.
            // There's really know way of knowing unless we are constantly updating the row for the current maindom
            // which isn't ideal.
            // So... we're going to 'just' take over, if the writelock works then we'll assume we're ok

            _logger.LogDebug("Timeout elapsed, assuming orphan row, acquiring MainDom.");

            ITransaction?transaction = null;

            try
            {
                transaction = db.GetTransaction(IsolationLevel.Serializable);

                // so now we update the row with our appdomain id
                InsertLockRecord(_lockId, db);
                _logger.LogDebug("Acquired with ID {LockId}", _lockId);
                return(true);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Unexpected error, could not forcibly acquire MainDom.");
                _errorDuringAcquiring = true;
                return(false);
            }
            finally
            {
                transaction?.Complete();
                transaction?.Dispose();
            }
        }
예제 #19
0
        /// <inheritdoc/>
        public async Task <IList <T> > DeleteAllExactAsync(ITransaction?transaction, IEnumerable <T> records)
        {
            IgniteArgumentCheck.NotNull(records, nameof(records));

            using var iterator = records.GetEnumerator();

            if (!iterator.MoveNext())
            {
                return(Array.Empty <T>());
            }

            var schema = await _table.GetLatestSchemaAsync().ConfigureAwait(false);

            var tx = transaction.ToInternal();

            using var writer = new PooledArrayBufferWriter();
            _ser.WriteMultiple(writer, tx, schema, iterator);

            using var resBuf = await DoOutInOpAsync(ClientOp.TupleDeleteAllExact, tx, writer).ConfigureAwait(false);

            var resSchema = await _table.ReadSchemaAsync(resBuf).ConfigureAwait(false);

            return(_ser.ReadMultiple(resBuf, resSchema));
        }
 /// <summary>
 /// Begins the transaction.
 /// </summary>
 public void BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted) => _transaction = Session.BeginTransaction(isolationLevel);
예제 #21
0
        public async Task AccountScenario()
        {
            var userAccount = new Account(new UserId());

            var testServer = TestHost.Server;

            testServer.CleanupDbContext();

            await testServer.UsingScopeAsync(
                async scope =>
            {
                var accountRepository = scope.GetRequiredService <IAccountRepository>();
                accountRepository.Create(userAccount);
                await accountRepository.CommitAsync();
            });

            await testServer.UsingScopeAsync(
                async scope =>
            {
                var accountRepository = scope.GetRequiredService <IAccountRepository>();
                var account           = await accountRepository.FindAccountOrNullAsync(userAccount.Id);
                account.Should().NotBeNull();
                account.Should().Be(account);
                account?.Transactions.Should().HaveCount(account.Transactions.Count);
                account?.Transactions.Should().NotContain(transaction => transaction.Status == TransactionStatus.Pending);
            });

            ITransaction?moneyDepositTransaction = null;

            await testServer.UsingScopeAsync(
                async scope =>
            {
                var accountRepository = scope.GetRequiredService <IAccountRepository>();
                var account           = await accountRepository.FindAccountOrNullAsync(userAccount.Id);
                account.Should().NotBeNull();
                account.Should().Be(userAccount);
                var moneyAccount        = new MoneyAccountDecorator(account !);
                moneyDepositTransaction = moneyAccount.Deposit(Money.Fifty);
                await accountRepository.CommitAsync();
            });

            await testServer.UsingScopeAsync(
                async scope =>
            {
                var accountRepository = scope.GetRequiredService <IAccountRepository>();
                var account           = await accountRepository.FindAccountOrNullAsync(userAccount.Id);
                account.Should().NotBeNull();
                account.Should().Be(userAccount);
                account?.Transactions.Should().HaveCount(userAccount.Transactions.Count + 1);
                account?.Transactions.Should().Contain(moneyDepositTransaction !);
                account?.Transactions.Should().ContainSingle(transaction => transaction.Status == TransactionStatus.Pending);
            });

            await testServer.UsingScopeAsync(
                async scope =>
            {
                var accountRepository = scope.GetRequiredService <IAccountRepository>();
                var account           = await accountRepository.FindAccountOrNullAsync(userAccount.Id);
                account.Should().NotBeNull();
                account.Should().Be(userAccount);
                var transaction = account?.Transactions.Single(accountTransaction => accountTransaction.Id == moneyDepositTransaction !.Id);
                transaction.Should().NotBeNull();
                transaction?.MarkAsSucceeded();
                await accountRepository.CommitAsync();
            });

            await testServer.UsingScopeAsync(
                async scope =>
            {
                var accountRepository = scope.GetRequiredService <IAccountRepository>();
                var account           = await accountRepository.FindAccountOrNullAsync(userAccount.Id);
                account.Should().NotBeNull();
                account.Should().Be(userAccount);
                var transaction = account?.Transactions.Single(accountTransaction => accountTransaction.Id == moneyDepositTransaction !.Id);
                transaction.Should().NotBeNull();
                var action = new Action(() => transaction?.MarkAsFailed());
                action.Should().Throw <InvalidOperationException>();
            });

            await testServer.UsingScopeAsync(
                async scope =>
            {
                var accountRepository = scope.GetRequiredService <IAccountRepository>();
                var account           = await accountRepository.FindAccountOrNullAsync(userAccount.Id);
                account.Should().NotBeNull();
                account.Should().Be(userAccount);
                account?.Transactions.Should().Contain(moneyDepositTransaction !);
                account?.Transactions.Should().ContainSingle(transaction => transaction.Status == TransactionStatus.Succeeded);
            });
        }
예제 #22
0
        public static async Task RunInTransactionAsync(this IAppDbContext dbContext, Action <ITransaction> action, ITransaction?transaction = null)
        {
            //We should commit and dispose the transaction only if we create it ourselves, that is it's an inbound transaction
            //if the transaction is provided by the caller, it's the responsibility of the caller to commit and dispose it
            bool shouldCreateInboundTransaction = transaction == null;

            transaction ??= await dbContext.StartTransactionAsync();

            bool outboundTransactionExists = transaction == null;
            bool isInboundTransaction      = shouldCreateInboundTransaction && !outboundTransactionExists;

            try
            {
                action(transaction !);
                if (isInboundTransaction)
                {
                    await transaction !.CommitAsync();
                }
            }
            finally
            {
                if (isInboundTransaction)
                {
                    transaction !.Dispose();
                }
            }
        }
예제 #23
0
        /// <inheritdoc/>
        public async Task UpsertAsync(ITransaction?transaction, T record)
        {
            IgniteArgumentCheck.NotNull(record, nameof(record));

            using var resBuf = await DoRecordOutOpAsync(ClientOp.TupleUpsert, transaction, record).ConfigureAwait(false);
        }