/// <summary> /// Creates a new transaction log manager. /// </summary> /// <param name="engineId">The engine this transaction log manager is used for. Only used for logging purposes.</param> /// <param name="keyValueStore">The key/value store to write transaction logs to.</param> /// <param name="policy">The serialization policy to use when serializing objects.</param> public TransactionLogManager(Uri engineId, IKeyValueStore keyValueStore, ISerializationPolicy policy) { _engineId = engineId; _keyValueStore = keyValueStore; _policy = policy; _lock = new AsyncLock(); _versionedLogs = new Queue <ITransactionLog>(); _metadataTable = new SerializingKeyValueTable <string>( _keyValueStore.GetTable(MetadataTableName), (str, s) => { using var writer = new BinaryWriter(s); writer.Write(str); }, s => { using var reader = new BinaryReader(s); return(reader.ReadString()); } ); using (var t = _keyValueStore.CreateTransaction()) { var tx = _metadataTable.Enter(t); if (!tx.Contains(ActiveCountKey)) { Invariant.Assert(!tx.Contains(LatestKey) && !tx.Contains(HeldCountKey), "Transaction log versioning keys are only partially populated."); _activeCount = _heldCount = _latest = 0; } else { Invariant.Assert(tx.Contains(LatestKey) && tx.Contains(HeldCountKey), "Transaction log versioning keys are only partially populated."); _activeCount = long.Parse(tx[ActiveCountKey], CultureInfo.InvariantCulture); _heldCount = long.Parse(tx[HeldCountKey], CultureInfo.InvariantCulture); _latest = long.Parse(tx[LatestKey], CultureInfo.InvariantCulture); } } Tracing.Transaction_Log_Initialization(null, _engineId, _latest, _activeCount, _heldCount); for (var i = _latest - _heldCount + 1; i <= _latest; i++) { _versionedLogs.Enqueue(new TransactionLog(_keyValueStore, _policy, i)); } }
private Dictionary <string, ArtifactOperation> Coalesce( IKeyValueStore keyValueStore, IList <ITransactionLog> logs, Func <ITransactionLog, IKeyValueTable <string, ArtifactOperation> > tableSelector) { var result = new Dictionary <string, ArtifactOperation>(); foreach (var log in logs) { var table = tableSelector(log); using var tx = keyValueStore.CreateTransaction(); var txTable = table.Enter(tx); foreach (var item in txTable) { if (result.TryGetValue(item.Key, out ArtifactOperation op)) { Tracing.Transaction_Log_Coalesce(null, _parent._engineId, item.Key, op.OperationKind.ToString(), item.Value.OperationKind.ToString()); // // SECOND // // Create Delete DeleteCreate // +--------------+--------------+--------------+ // F Create | Invalid | No-op | Create | // I +--------------+--------------+--------------+ // R Delete | DeleteCreate | Invalid | Invalid | // S +--------------+--------------+--------------+ // T DeleteCreate | Invalid | Delete | DeleteCreate | // +--------------+--------------+--------------+ // switch (op.OperationKind) { case ArtifactOperationKind.Create: switch (item.Value.OperationKind) { case ArtifactOperationKind.Create: UpdateInvalidReplays(item.Key, item.Value, result, _invalidReplaySequence); break; case ArtifactOperationKind.Delete: result.Remove(item.Key); break; case ArtifactOperationKind.DeleteCreate: result[item.Key] = ArtifactOperation.Create(item.Value.Expression, item.Value.State); break; } break; case ArtifactOperationKind.Delete: switch (item.Value.OperationKind) { case ArtifactOperationKind.Create: result[item.Key] = ArtifactOperation.DeleteCreate(item.Value.Expression, item.Value.State); break; case ArtifactOperationKind.Delete: UpdateInvalidReplays(item.Key, item.Value, result, _invalidReplaySequence); break; case ArtifactOperationKind.DeleteCreate: UpdateInvalidReplays(item.Key, item.Value, result, _invalidReplaySequence); break; } break; case ArtifactOperationKind.DeleteCreate: switch (item.Value.OperationKind) { case ArtifactOperationKind.Create: UpdateInvalidReplays(item.Key, item.Value, result, _invalidReplaySequence); break; case ArtifactOperationKind.Delete: result[item.Key] = item.Value; break; case ArtifactOperationKind.DeleteCreate: result[item.Key] = item.Value; break; } break; } } else { result.Add(item.Key, item.Value); } } } return(result); }