/// <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)); }
/// <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()); }
/// <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); }
/// <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)); }
/// <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; }
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 }
/// <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()); }
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)); }
/// <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; } } }
/// <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); }
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(); } }
/// <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);
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); }); }
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(); } } }
/// <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); }