Ejemplo n.º 1
0
        public IEntryState <TId, TData> Store(IEntryState <TId, TData> entry, TData data, long transactionId)
        {
            if (entry == null)
            {
                throw new ArgumentNullException(nameof(entry));
            }

            if (!entry.PendingTransactions.Contains(transactionId))
            {
                throw new InvalidOperationException();
            }

            if (entry.PendingOperations.Any(p => p.TransactionId == transactionId))
            {
                throw new InvalidOperationException("A single transaction must modify an entry with a single operation only.");
            }

            var lastWriteTime     = _dateTimeProvider.GetCurrentTime();
            var pendingOperation  = new PendingOperation(transactionId, originalData: ToSnapshot(entry), lastWriteTime);
            var pendingOperations = entry.PendingOperations.Add(pendingOperation);

            return(new Entry(entry.Id,
                             data,
                             entry.DataVersion + 1,
                             entry.Version + 1,
                             entry.CreatingTransaction,
                             pendingOperations,
                             entry.PendingTransactions,
                             entry.CreationTime,
                             lastWriteTime));
        }
Ejemplo n.º 2
0
        public IEntryState <TId, TData> AddPendingTransaction(IEntryState <TId, TData> entry, long transactionId)
        {
            if (entry == null)
            {
                throw new ArgumentNullException(nameof(entry));
            }

            if (entry.PendingTransactions.Contains(transactionId))
            {
                return(entry);
            }

            var lastWriteTime       = _dateTimeProvider.GetCurrentTime();
            var pendingTransactions = entry.PendingTransactions.Add(transactionId);

            return(new Entry(entry.Id,
                             entry.Data,
                             entry.DataVersion,
                             entry.Version + 1,
                             entry.CreatingTransaction,
                             entry.PendingOperations,
                             pendingTransactions,
                             entry.CreationTime,
                             lastWriteTime));
        }
Ejemplo n.º 3
0
        public IEntryState <TId, TData> Commit(IEntryState <TId, TData> entry, long transactionId)
        {
            if (entry == null)
            {
                throw new ArgumentNullException(nameof(entry));
            }

            var lastWriteTime = _dateTimeProvider.GetCurrentTime();

            var pendingOperations   = entry.PendingOperations.RemoveAll(op => op.TransactionId == transactionId);
            var pendingTransactions = entry.PendingTransactions.Remove(transactionId);

            entry = new Entry(entry.Id,
                              entry.Data,
                              entry.DataVersion,
                              entry.Version + 1,
                              entry.CreatingTransaction,
                              pendingOperations,
                              pendingTransactions,
                              entry.CreationTime,
                              lastWriteTime);

            Assert(!entry.PendingOperations.Any(p => p.TransactionId == transactionId));

            return(entry);
        }
Ejemplo n.º 4
0
        public IEntrySnapshot <TId, TData> ToSnapshot(IEntryState <TId, TData> entry)
        {
            if (entry == null)
            {
                throw new ArgumentNullException(nameof(entry));
            }

            return(new EntrySnapshot(entry.Id, entry.Data, entry.DataVersion, entry.LastWriteTime));
        }
Ejemplo n.º 5
0
        private static StoredEntry AsStoredEntry(IEntryState <TId, TData> entry)
        {
            if (entry == null)
            {
                return(null);
            }

            if (entry is StoredEntry storedEntry)
            {
                return(storedEntry);
            }

            return(new StoredEntry(entry));
        }
Ejemplo n.º 6
0
            public Entry(IEntryState <TId, TData> entry)
            {
                Assert(entry.Data != null);
                Assert(entry.PendingOperations != null);
                Assert(entry.CreationTime <= entry.LastWriteTime);

                Id                  = entry.Id;
                Data                = entry.Data;
                DataVersion         = entry.DataVersion;
                Version             = entry.Version;
                CreatingTransaction = entry.CreatingTransaction;
                PendingOperations   = entry.PendingOperations;
                CreationTime        = entry.CreationTime;
                LastWriteTime       = entry.LastWriteTime;
                PendingTransactions = entry.PendingTransactions;
            }
Ejemplo n.º 7
0
            public StoredEntry(IEntryState <TId, TData> entry)
            {
                DataVersion         = entry.DataVersion;
                LastWriteTime       = entry.LastWriteTime;
                Version             = entry.Version;
                CreationTime        = entry.CreationTime;
                CreatingTransaction = entry.CreatingTransaction;
                PendingOperations   = new List <StoredPendingOperation>(entry.PendingOperations.Select(p => AsStoredPendingOperation(p)));

                for (var i = 0; i < entry.PendingOperations.Count; i++)
                {
                    Assert(entry.PendingOperations[i].TransactionId == PendingOperations[i].TransactionId);
                }

                PendingTransactions = new List <long>(entry.PendingTransactions);

                Id   = entry.Id;
                Data = entry.Data;
            }
Ejemplo n.º 8
0
        public static IEntryState <TId, TData> CommitAll <TId, TData>(this IEntryStateTransformer <TId, TData> entryManager, IEntryState <TId, TData> entry, IEnumerable <long> transactionIds)
            where TData : class
        {
            if (entryManager == null)
            {
                throw new ArgumentNullException(nameof(entryManager));
            }

            if (transactionIds == null)
            {
                throw new ArgumentNullException(nameof(transactionIds));
            }

            return(transactionIds.Aggregate(seed: entry, (current, transactionId) => entryManager.Commit(current, transactionId)));
        }
Ejemplo n.º 9
0
 public static ValueTask <(IEntryState <TId, TData> entry, T result)> UpdateEntryAsync <TId, TData, T>(this IEntryStateStorage <TId, TData> entryStorage,
                                                                                                       IEntryState <TId, TData> entry,
                                                                                                       Func <IEntryState <TId, TData>, (IEntryState <TId, TData> entry, T result)> update,
Ejemplo n.º 10
0
        public static async ValueTask <IEntryState <TId, TData> > UpdateEntryAsync <TId, TData>(this IEntryStateStorage <TId, TData> entryStorage,
                                                                                                IEntryState <TId, TData> entry,
                                                                                                Func <IEntryState <TId, TData>, IEntryState <TId, TData> > update,
                                                                                                Func <IEntryState <TId, TData>, bool> condition,
                                                                                                CancellationToken cancellation) where TData : class
        {
            if (entryStorage == null)
            {
                throw new ArgumentNullException(nameof(entryStorage));
            }

            if (entry == null)
            {
                throw new ArgumentNullException(nameof(entry));
            }

            if (update == null)
            {
                throw new ArgumentNullException(nameof(update));
            }

            if (condition == null)
            {
                throw new ArgumentNullException(nameof(condition));
            }

            var id = entry.Id;

            while (condition(entry))
            {
                var desired = update(entry);

                if (desired == entry)
                {
                    return(entry);
                }

                if (await entryStorage.CompareExchangeAsync(desired, entry, cancellation))
                {
                    return(entry = desired);
                }

                entry = await entryStorage.GetEntryAsync(id, cancellation);

                if (entry == null)
                {
                    return(null);
                }
            }

            return(entry);
        }
Ejemplo n.º 11
0
 public static ValueTask <IEntryState <TId, TData> > UpdateEntryAsync <TId, TData>(this IEntryStateStorage <TId, TData> entryStorage,
                                                                                   IEntryState <TId, TData> entry,
                                                                                   Func <IEntryState <TId, TData>, IEntryState <TId, TData> > update,
                                                                                   CancellationToken cancellation) where TData : class
 {
     return(UpdateEntryAsync(entryStorage, entry, update, condition: e => true, cancellation));
 }
Ejemplo n.º 12
0
        public static async ValueTask <IEntryState <TId, TData> > GetEntryAsync <TId, TData>(this IEntryStateStorage <TId, TData> entryStorage,
                                                                                             IEntryState <TId, TData> comparand,
                                                                                             CancellationToken cancellation = default)
            where TData : class
        {
            if (entryStorage == null)
            {
                throw new ArgumentNullException(nameof(entryStorage));
            }
            if (comparand == null)
            {
                throw new ArgumentNullException(nameof(comparand));
            }

            var entries = await entryStorage.GetEntriesAsync(DataPropertyHelper.BuildPredicate(comparand), cancellation);

            return(entries.FirstOrDefault());
        }
Ejemplo n.º 13
0
 public Task <bool> CompareExchangeAsync(IEntryState <TId, TData> entry, IEntryState <TId, TData> comparand, CancellationToken cancellation = default)
 {
     return(_database.CompareExchangeAsync(AsStoredEntry(entry), AsStoredEntry(comparand), p => p.Version, cancellation));
 }
Ejemplo n.º 14
0
        public IEntryState <TId, TData> Abort(IEntryState <TId, TData> entry, long transactionId)
        {
            if (entry == null)
            {
                throw new ArgumentNullException(nameof(entry));
            }

            var pendingTransactions = entry.PendingTransactions.Remove(transactionId);

            var i = entry.PendingOperations.FindIndex(p => p.TransactionId == transactionId);

            // We abort the operation that happend last
            if (i >= 0 && i == entry.PendingOperations.Count() - 1)
            {
                var originalData = entry.PendingOperations[i].OriginalData;

                entry = new Entry(entry.Id,
                                  originalData.Data,
                                  originalData.DataVersion,
                                  entry.Version + 1,
                                  entry.CreatingTransaction,
                                  entry.PendingOperations.RemoveAt(entry.PendingOperations.Count - 1),
                                  pendingTransactions,
                                  entry.CreationTime,
                                  originalData.LastWriteTime ?? entry.CreationTime);
            }
            else if (i >= 0)
            {
#if DEBUG
                Assert(entry.PendingOperations.Count(p => p.TransactionId == transactionId) == 1);
#endif

                var pendingOperations = entry.PendingOperations;
                var originalData      = pendingOperations[i].OriginalData;
                pendingOperations = pendingOperations.RemoveAt(i);

                // The operations after the removed one now have an index that is one smaller
                var operationToReplace = pendingOperations[i]; // index i + 1 is now index i
                var replacement        = new PendingOperation(operationToReplace.TransactionId, originalData, operationToReplace.OperationTime);
                pendingOperations = pendingOperations.Replace(operationToReplace, replacement);

                entry = new Entry(entry.Id,
                                  entry.Data,
                                  entry.DataVersion,
                                  entry.Version + 1,
                                  entry.CreatingTransaction,
                                  pendingOperations,
                                  pendingTransactions,
                                  entry.CreationTime,
                                  entry.LastWriteTime);
            }
            else if (entry.PendingTransactions.Contains(transactionId))
            {
                entry = new Entry(entry.Id,
                                  entry.Data,
                                  entry.DataVersion,
                                  entry.Version + 1,
                                  entry.CreatingTransaction,
                                  entry.PendingOperations,
                                  pendingTransactions,
                                  entry.CreationTime,
                                  entry.LastWriteTime);
            }

            Assert(!entry.PendingOperations.Any(p => p.TransactionId == transactionId));

            return(entry);
        }