private void DisposeOldVersions() { List <object> disposeList = new List <object>(); lock (versions) { // size - 1 because we don't want to delete the very last version, int sz = versions.Count - 1; bool foundLockedEntry = false; for (int i = 0; i < sz && foundLockedEntry == false; ++i) { VersionInfo vinfo = versions[i]; // If this version isn't locked, if (vinfo.NotLocked) { // Add to the dispose list disposeList.Add(vinfo); // And delete from the versions list, versions.RemoveAt(i); --sz; --i; } else { // If it is locked, we exit the loop foundLockedEntry = true; } } } // If there are entries to dispose? if (disposeList.Count > 0) { // We synchronize here to ensure the versions list can't be modified by // a commit operation while we are disposing this. lock (this) { // Run within a write lock on the store try { nodeStore.LockForWrite(); // First we write out a modified version header minus the versions we // are to delete, // Get the current version list IMutableArea headerArea = nodeStore.GetMutableArea(headerId); headerArea.Position = 8; long versionListId = headerArea.ReadInt8(); // Read information from the old version info, IArea versionListArea = nodeStore.GetArea(versionListId); versionListArea.ReadInt4(); // The magic int versionCount = versionListArea.ReadInt4(); int newVersionCount = versionCount - disposeList.Count; // Create a new list, IAreaWriter newVersionList = nodeStore.CreateArea(8 + (8 * newVersionCount)); newVersionList.WriteInt4(0x01433); newVersionList.WriteInt4(newVersionCount); // Skip the versions we are deleting, for (int i = 0; i < disposeList.Count; ++i) { versionListArea.ReadInt8(); } // Now copy the list from the new point for (int i = 0; i < newVersionCount; ++i) { newVersionList.WriteInt8(versionListArea.ReadInt8()); } newVersionList.Finish(); // Write the new area to the header, headerArea.Position = 8; headerArea.WriteInt8(newVersionList.Id); // Delete the old version list Area, nodeStore.DeleteArea(versionListId); // Dispose the version info, int sz = disposeList.Count; for (int i = 0; i < sz; ++i) { VersionInfo vinfo = (VersionInfo)disposeList[i]; long vRef = vinfo.VersionInfoRef; IArea versionArea = nodeStore.GetArea(vRef); int magic = versionArea.ReadInt4(); int rev = versionArea.ReadInt4(); // Check the magic, if (magic != 0x04EA23) { throw new ApplicationException("Magic value for version area is incorrect."); } long verId = versionArea.ReadInt8(); long nrnHigh = versionArea.ReadInt8(); long nrnLow = versionArea.ReadInt8(); int nodeCount = versionArea.ReadInt4(); // For each node, for (int n = 0; n < nodeCount; ++n) { // Read the next area long drnHigh = versionArea.ReadInt8(); long drnLow = versionArea.ReadInt8(); NodeId delNodeId = new NodeId(drnHigh, drnLow); // Cleanly disposes the node DoDisposeNode(delNodeId); } // Delete the node header, nodeStore.DeleteArea(vRef); } } finally { nodeStore.UnlockForWrite(); } } } }
private long WriteVersionsList(long versionId, TreeSystemTransaction tran) { lock (this) { // Write the version info and the deleted refs to a new area, NodeId rootNodeId = tran.RootNodeId; if (rootNodeId.IsInMemory) { throw new ApplicationException("Assertion failed, root_node is on heap."); } // Get the list of all nodes deleted in the transaction List <NodeId> deletedRefs = tran.NodeDeletes; // Sort it deletedRefs.Sort(); // Check for any duplicate entries (we shouldn't double delete stuff). for (int i = 1; i < deletedRefs.Count; ++i) { if (deletedRefs[i - 1].Equals(deletedRefs[i])) { // Oops, duplicated delete throw new ApplicationException("PRAGMATIC_CHECK failed: duplicate records in delete list."); } } long theVersionId = WriteSingleVersionInfo(versionId, rootNodeId, deletedRefs); // Now update the version list by copying the list and adding the new ref // to the end. // Get the current version list IMutableArea headerArea = nodeStore.GetMutableArea(headerId); headerArea.Position = 8; long versionListId = headerArea.ReadInt8(); // Read information from the old version info, IArea versionListArea = nodeStore.GetArea(versionListId); versionListArea.ReadInt4(); // The magic int versionCount = versionListArea.ReadInt4(); // Create a new list, IAreaWriter newVersionList = nodeStore.CreateArea(8 + (8 * (versionCount + 1))); newVersionList.WriteInt4(0x01433); newVersionList.WriteInt4(versionCount + 1); for (int i = 0; i < versionCount; ++i) { newVersionList.WriteInt8(versionListArea.ReadInt8()); } newVersionList.WriteInt8(theVersionId); newVersionList.Finish(); // Write the new area to the header, headerArea.Position = 8; headerArea.WriteInt8(newVersionList.Id); // Delete the old version list Area, nodeStore.DeleteArea(versionListId); // Done, return(theVersionId); } }