public void AddState(string dataProviderKey, JToken data, Guid transactionId)
        {
            var dataStr = JsonConvert.SerializeObject(data, Formatting.Indented, new JsonSerializerSettings
            {
                TypeNameHandling = TypeNameHandling.All
            });
            TransactionStateEntity n = new TransactionStateEntity()
            {
                Data = dataStr, Id = transactionId
            };
            var transactionalCasDataProvider = this.dataProviderPool.GetProvider(dataProviderKey);

            using (new StopwatchLog(Metrics.CassAdd))
            {
                transactionalCasDataProvider.Mapper.InsertAsync(n, CqlQueryOptions.New());
            }
        }
Example #2
0
        public async Task <string> Store(string expectedETag, TransactionalStateMetaData metadata,
                                         List <PendingTransactionState <TState> > statesToPrepare, long?commitUpTo,
                                         long?abortAfter)
        {
            if (_metadata.ETag != expectedETag)
            {
                throw new ArgumentException(nameof(expectedETag), "Etag does not match");
            }

            var stateUpdater = new StateUpdater(_dbExecuter, _stateId, _options.StateTableName, _jsonSettings);

            // first, clean up aborted records
            if (abortAfter.HasValue && _states.Count != 0)
            {
                await stateUpdater.DeleteStates(afterSequenceId : abortAfter);

                while (_states.Count > 0 && _states[_states.Count - 1].SequenceId > abortAfter)
                {
                    _states.RemoveAt(_states.Count - 1);
                }
            }

            // second, persist non-obsolete prepare records
            var obsoleteBefore = commitUpTo.HasValue ? commitUpTo.Value : _metadata.CommittedSequenceId;

            if (statesToPrepare != null && statesToPrepare.Count > 0)
            {
                foreach (var s in statesToPrepare)
                {
                    if (s.SequenceId >= obsoleteBefore)
                    {
                        var newState = new TransactionStateEntity
                        {
                            SequenceId         = s.SequenceId,
                            TransactionId      = s.TransactionId,
                            Timestamp          = s.TimeStamp,
                            TransactionManager = s.TransactionManager,
                            Value = s.State
                        };

                        if (FindState(s.SequenceId, out var pos))
                        {
                            // overwrite with new pending state
                            _states[pos] = newState;
                            await stateUpdater.UpdateState(newState).ConfigureAwait(false);
                        }
                        else
                        {
                            await stateUpdater.InsertState(newState).ConfigureAwait(false);

                            _states.Insert(pos, newState);
                        }

                        _logger.LogTrace($"{_stateId}.{newState.SequenceId} Update {newState.TransactionId}");
                    }
                }
            }

            await stateUpdater.EnsureInsertBufferFlushed();

            // third, persist metadata and commit position
            _metadata = await PersistMetadata(metadata, commitUpTo ?? _metadata.CommittedSequenceId);

            // fourth, remove obsolete records
            if (_states.Count > 0 && _states[0].SequenceId < obsoleteBefore)
            {
                FindState(obsoleteBefore, out var pos);
                await stateUpdater.DeleteStates(beforeSequenceId : obsoleteBefore);

                _states.RemoveRange(0, pos);
            }

            return(_metadata.ETag);
        }