override internal protected void TrackModification(CollectionOnDisk collection, bool untrack = false) { CollectionOnDisk p = collection; // Collection.GetTopParent(); RecordKey key = CreateKey(p); if (!untrack) { ModifiedCollections[key] = p; return; } ModifiedCollections.Remove(key); }
/// <summary> /// Commit a transaction /// </summary> /// <param name="phase"> /// FirstPhase will make changes permanent but keep transaction log so rollback /// is still possible. /// /// SecondPhase will: /// 1. call FirstPhase commit if this transaction is in UnCommitted phase /// 2. clear the transaction log to complete Commit /// NOTE: Rollback is no longer allowed after completion of SecondPhase /// </param> ///<returns>true if successful otherwise false</returns> public override bool InternalCommit(CommitPhase phase) { if (CurrentCommitPhase == CommitPhase.Committed) { throw new InvalidOperationException(string.Format("Transaction '{0}' is already committed.", Id)); } _inCommit++; try { switch (phase) { case CommitPhase.FirstPhase: if (CurrentCommitPhase == CommitPhase.UnCommitted) { RollbackConflicts(); //** save all cached data of each collection var parents = new Dictionary <CollectionOnDisk, object>(ModifiedCollections.Count); var closeColls = new List <RecordKey>(); foreach (KeyValuePair <RecordKey, CollectionOnDisk> kvp in ModifiedCollections) { CollectionOnDisk collection = kvp.Value; CollectionOnDisk ct = collection.GetTopParent(); if (ct.IsOpen) { parents[ct] = null; } else { closeColls.Add(kvp.Key); } } foreach (CollectionOnDisk collection in parents.Keys) { if (!collection.IsOpen) { continue; } collection.Flush(); collection.OnCommit(); } foreach (RecordKey k in closeColls) { ModifiedCollections.Remove(k); } //File.DeletedCollections.Flush(); CurrentCommitPhase = CommitPhase.FirstPhase; //** don't clear transaction log so rollback is still possible return(true); } break; case CommitPhase.SecondPhase: if (CurrentCommitPhase == CommitPhase.UnCommitted) { if (!Commit(CommitPhase.FirstPhase)) { break; } } if (CurrentCommitPhase == CommitPhase.FirstPhase) { //** mark second phase completed as when it starts, no turning back... CurrentCommitPhase = CommitPhase.SecondPhase; //** preserve the recycled segment so on rollback it can be restored... foreach (CollectionOnDisk collection in ModifiedCollections.Values) { if (!collection.IsOpen) { continue; } collection.HeaderData.RecycledSegmentBeforeTransaction = collection.HeaderData.RecycledSegment; if (collection.HeaderData.RecycledSegmentBeforeTransaction != null) { collection.HeaderData.RecycledSegmentBeforeTransaction = (DeletedBlockInfo) collection.HeaderData.RecycledSegmentBeforeTransaction.Clone(); } } //** delete new (AddStore), updated (LogCollection) and //** file growth segments (FileGrowthStore) "log entries" ClearStores(true); //** todo: Record on Trans Log the FileSet Remove action + info needed for //** commit resume "on crash and restart" 11/9/08 File.Delete(Server.Path + DataBackupFilename); //** todo: remove from trans Log the FileSet Remove action... 11/09/08 return(true); } break; } //** auto roll back this transaction if commit failed above if (CurrentCommitPhase != CommitPhase.Rolledback && CurrentCommitPhase != CommitPhase.SecondPhase) { Rollback(); } return(false); } finally { _inCommit--; if (Parent == null) { CollectionOnDisk.transaction = null; } else { Parent.Children.Remove(this); } } }