public BatchOperation(ILogger logger, KeyEntity key, CloudTable table)
 {
     this.batchOperation = new TableBatchOperation();
     this.logger         = logger;
     this.key            = key;
     this.table          = table;
 }
        public async Task <TransactionalStorageLoadResponse <TState> > Load()
        {
            try
            {
                var keyTask    = ReadKey();
                var statesTask = ReadStates();
                key = await keyTask.ConfigureAwait(false);

                states = await statesTask.ConfigureAwait(false);

                if (string.IsNullOrEmpty(key.ETag))
                {
                    if (logger.IsEnabled(LogLevel.Debug))
                    {
                        logger.LogDebug($"{partition} Loaded v0, fresh");
                    }

                    // first time load
                    return(new TransactionalStorageLoadResponse <TState>());
                }
                else
                {
                    if (!FindState(this.key.CommittedSequenceId, out var pos))
                    {
                        var error = $"Storage state corrupted: no record for committed state";
                        logger.LogCritical(error);
                        throw new InvalidOperationException(error);
                    }
                    var committedState = states[pos].Value.GetState <TState>(this.jsonSettings);

                    var PrepareRecordsToRecover = new List <PendingTransactionState <TState> >();
                    for (int i = 0; i < states.Count; i++)
                    {
                        var kvp = states[i];

                        // pending states for already committed transactions can be ignored
                        if (kvp.Key <= key.CommittedSequenceId)
                        {
                            continue;
                        }

                        // upon recovery, local non-committed transactions are considered aborted
                        if (kvp.Value.TransactionManager == null)
                        {
                            break;
                        }

                        PrepareRecordsToRecover.Add(new PendingTransactionState <TState>()
                        {
                            SequenceId         = kvp.Key,
                            State              = kvp.Value.GetState <TState>(this.jsonSettings),
                            TimeStamp          = kvp.Value.TransactionTimestamp,
                            TransactionId      = kvp.Value.TransactionId,
                            TransactionManager = kvp.Value.TransactionManager
                        });
                    }

                    // clear the state strings... no longer needed, ok to GC now
                    for (int i = 0; i < states.Count; i++)
                    {
                        states[i].Value.StateJson = null;
                    }

                    if (logger.IsEnabled(LogLevel.Debug))
                    {
                        logger.LogDebug($"{partition} Loaded v{this.key.CommittedSequenceId} rows={string.Join(",", states.Select(s => s.Key.ToString("x16")))}");
                    }

                    return(new TransactionalStorageLoadResponse <TState>(this.key.ETag, committedState, this.key.CommittedSequenceId, this.key.Metadata, PrepareRecordsToRecover));
                }
            }
            catch (Exception ex)
            {
                this.logger.LogError("Transactional state load failed {Exception}.", ex);
                throw;
            }
        }