Example #1
0
 private static void NotifyResourceOfCommit(ITransactionalResource resource, long transaction, MultiCompletionSource completionSource)
 {
     resource.Commit(transaction)
     .ContinueWith(
         (result, state) =>
     {
         var completion = (MultiCompletionSource)state;
         if (result.Exception != null)
         {
             completion.SetException(result.Exception);
         }
         else
         {
             completion.SetOneResult();
         }
     },
         completionSource,
         CancellationToken.None,
         TaskContinuationOptions.ExecuteSynchronously,
         TaskScheduler.Default);
 }
Example #2
0
        private async Task <bool> Checkpoint(Dictionary <ITransactionalResource, long> resources, List <Transaction> transactions)
        {
            // Rather than continue processing forever, only process the number of transactions which were waiting at invocation time.
            var total = this.checkpointRetryQueue.Count + checkpointQueue.Count;

            // The maximum number of transactions checkpointed in each batch.
            int  batchSize = Math.Min(total, MaxCheckpointBatchSize);
            long lsn       = 0;

            try
            {
                var processed = 0;
                while (processed < total && (this.checkpointRetryQueue.Count > 0 || !checkpointQueue.IsEmpty))
                {
                    resources.Clear();
                    transactions.Clear();

                    // Take a batch of transactions to checkpoint.
                    var currentBatchSize = 0;
                    while (currentBatchSize < batchSize)
                    {
                        currentBatchSize++;
                        Transaction tx;

                        // If some previous operation had failed, retry it before proceeding with new work.
                        if (this.checkpointRetryQueue.Count > 0)
                        {
                            tx = this.checkpointRetryQueue.Dequeue();
                        }
                        else if (!checkpointQueue.TryDequeue(out tx))
                        {
                            break;
                        }

                        foreach (var resource in tx.Info.WriteSet.Keys)
                        {
                            resources[resource] = tx.Info.TransactionId;
                        }

                        lsn = Math.Max(lsn, tx.LSN);
                        transactions.Add(tx);
                    }

                    processed += currentBatchSize;

                    // If the transaction involved writes, send a commit notification to each resource which performed
                    // a write and wait for acknowledgement.
                    if (resources.Count > 0)
                    {
                        // Send commit notifications to all of the resources involved.
                        var completion = new MultiCompletionSource(resources.Count);
                        foreach (var resource in resources)
                        {
                            NotifyResourceOfCommit(resource.Key, resource.Value, completion);
                        }

                        // Wait for the commit notifications to be acknowledged by the resources.
                        await completion.Task;
                    }

                    // Mark the transactions as checkpointed.
                    foreach (var tx in transactions)
                    {
                        lock (tx)
                        {
                            tx.State = TransactionState.Checkpointed;
                            tx.HighestActiveTransactionIdAtCheckpoint = activeTransactionsTracker.GetHighestActiveTransactionId();
                        }
                    }

                    // Allow the transaction log to be truncated.
                    this.checkpointedLSN = lsn;
                }
            }
            catch (Exception e)
            {
                // Retry all failed checkpoint operations.
                foreach (var tx in transactions)
                {
                    this.checkpointRetryQueue.Enqueue(tx);
                }

                this.Logger.Error(0, "Failure during checkpoint", e);
                throw;
            }

            return(total > 0);
        }