/// <summary> /// Clear contents of this Collection. /// Changes will be saved right after clearing the contents. /// </summary> public virtual void Clear() { if (HeaderData.OccupiedBlocksHead != null && HeaderData.OccupiedBlocksTail != null) { HeaderData.DiskBuffer.IsDirty = true; HeaderData.OccupiedBlocksTail.DataAddress = HeaderData.NextAllocatableAddress = HeaderData.StartAllocatableAddress = HeaderData.OccupiedBlocksHead.DataAddress; int segmentSize = File.GetSegmentSize(); if (HeaderData.OccupiedBlocksHead.DataAddress + segmentSize != HeaderData.EndAllocatableAddress) { //**** add to File.DeletedCollections the next _region for reuse... //** read next segment of deleted collection var dbi = new DeletedBlockInfo(); Sop.DataBlock db; db = DataBlockDriver.ReadBlockFromDisk(this, HeaderData.OccupiedBlocksHead.DataAddress + segmentSize - (int)File.DataBlockSize, true); if (db.InternalNextBlockAddress >= 0) { dbi.StartBlockAddress = db.InternalNextBlockAddress; dbi.EndBlockAddress = db.InternalNextBlockAddress + segmentSize; if (File.DeletedCollections != null) { bool oc = ((CollectionOnDisk)File.DeletedCollections).ChangeRegistry; ((CollectionOnDisk)File.DeletedCollections).ChangeRegistry = ChangeRegistry; File.DeletedCollections.Add(dbi); ((CollectionOnDisk)File.DeletedCollections).ChangeRegistry = oc; } HeaderData.EndAllocatableAddress = HeaderData.OccupiedBlocksHead.DataAddress + segmentSize; } } } HeaderData.Count = 0; if (HeaderData.diskBuffer != null) { HeaderData.diskBuffer.ClearData(); } if (deletedBlocks != null) { deletedBlocks.Clear(); } //if (MruManager != null) // MruManager.Clear(); //if (this.DataBlockDriver != null) // this.DataBlockDriver.MruManager.Clear(); //Blocks.Clear(); currentDataBlock = null; currentEntry = null; _currentEntryDataAddress = -1; RegisterChange(); Flush(); }
/// <summary> /// Get a deleted block from Collection 'block recycle bin' or from File 'collection recycle bin'. /// </summary> /// <param name="requestedBlockSize"> </param> /// <param name="isCollectionBlock"> </param> /// <param name="collectionDeletedBlock"> </param> /// <returns></returns> public DeletedBlockInfo GetDeletedBlock(int requestedBlockSize, bool isCollectionBlock, out bool collectionDeletedBlock) { collectionDeletedBlock = true; #region try to recycle from File collection recycle bin if (HeaderData == null || HeaderData.RecycledSegment == null) { if (File.DeletedCollections != null && GetTopParent() != File.DeletedCollections && File.DeletedCollections.Count > 0) { collectionDeletedBlock = false; return(File.DeletedCollections.GetTop()); } } if (HeaderData != null && HeaderData.RecycledSegment != null) { long blockSize = HeaderData.RecycledSegment.Count * (int)DataBlockSize; if (blockSize >= requestedBlockSize) { return(HeaderData.RecycledSegment); } if (!IsDeletedBlocksList) { if (DeletedBlocks != null) { DeletedBlocks.AddAvailableBlock(HeaderData.RecycledSegment.StartBlockAddress, blockSize); } HeaderData.RecycledSegment = null; } } #endregion #region try to recycle from Collection block recycle bin if (!IsDeletedBlocksList && DeletedBlocks != null && DeletedBlocks.Count > 0) { long availableBlockAddress; long availableBlockSize; if (DeletedBlocks.GetAvailableBlock(IsDeletedBlocksList, requestedBlockSize, out availableBlockAddress, out availableBlockSize)) { var dbi = new DeletedBlockInfo { StartBlockAddress = availableBlockAddress, Count = (int)(availableBlockSize / (int)DataBlockSize) }; return(dbi); } } #endregion return(null); }
public void SetTop(DeletedBlockInfo value) { Locker.Lock(); if (!MoveFirst()) { Locker.Unlock(); return; } Remove(); Add(value); Locker.Unlock(); }
public DeletedBlockInfo Get(long dataAddress) { Locker.Lock(); if (Search(dataAddress)) { var dbi = new DeletedBlockInfo { StartBlockAddress = (long)CurrentKey, EndBlockAddress = (long)CurrentValue }; Locker.Unlock(); return(dbi); } Locker.Unlock(); return(null); }
public DeletedBlockInfo GetTop() { Locker.Lock(); if (!MoveFirst()) { Locker.Unlock(); return(null); } var dbi = new DeletedBlockInfo { StartBlockAddress = (long)CurrentKey, EndBlockAddress = (long)CurrentValue }; Locker.Unlock(); return(dbi); }
public void Add(DeletedBlockInfo value) { Locker.Lock(); if (Search(value.StartBlockAddress)) { Locker.Unlock(); return; } if (Log.Logger.Instance.IsVerboseEnabled) { Log.Logger.Instance.Log(Log.LogLevels.Verbose, "FileRecycler.Add: {0}", value.ToString()); } var itm = new BTreeItemOnDisk(DataBlockSize, value.StartBlockAddress, value.EndBlockAddress); base.Add(itm); Locker.Unlock(); }
/// <summary> /// Rollback a transaction /// </summary> public override void InternalRollback(bool isDisposing) { if (_addStore == null && ModifiedCollections == null) { return; } if (CurrentCommitPhase == CommitPhase.Committed) { throw new InvalidOperationException( string.Format("Transaction '{0}' is already committed, can't rollback.", Id)); } if (CurrentCommitPhase == CommitPhase.Rolledback) { throw new InvalidOperationException( string.Format("Transaction '{0}' was rolled back, can't roll it back again.", Id)); } _inCommit++; try { //** Step 1. truncate all newly added blocks beyond eof before transaction began //** Step 2. copy all preserved blocks in transaction log onto respective //** collection on disk to revert changes. Ensure to mark each reverted block so during //** crash while rollback, we can resume where we left off. //** Step 3. Clear memory of this transaction objects //** Revert from backup RestoreData(); //** Clear memory of this transaction's objects var parents = new Dictionary <CollectionOnDisk, object>(ModifiedCollections.Count); foreach (KeyValuePair <RecordKey, CollectionOnDisk> de in ModifiedCollections) { de.Value.HeaderData.IsModifiedInTransaction = false; //** clear memory of objects belonging to the transaction... if (de.Key.Filename != DataBackupFilename) { parents[de.Value.GetTopParent()] = null; de.Value.HeaderData.RecycledSegment = de.Value.HeaderData.RecycledSegmentBeforeTransaction; if (de.Value.HeaderData.RecycledSegment != null) { de.Value.HeaderData.RecycledSegment = (DeletedBlockInfo)de.Value.HeaderData.RecycledSegment.Clone(); } RemoveInMemory(de.Value, de.Key.Address); } } if (!(OwnsRoot && isDisposing)) { foreach (CollectionOnDisk cod in parents.Keys) { cod.OnRollback(); if (cod is BTreeAlgorithm) { var sdod = ((BTreeAlgorithm)cod).Container; if (sdod == null) { continue; } sdod.Reload(); } else { cod.Load(); } } } //** Truncate all newly added blocks beyond eof if (_fileGrowthStore != null) { var dbis = new List <KeyValuePair <DeletedBlockInfo, OnDisk.File.IFile> >(_fileGrowthStore.Count); foreach (var de in _fileGrowthStore) { var key = de.Key; var f = (OnDisk.File.IFile)Server.FileSet[key.Filename]; if (f == null) { continue; } //** add to deleted blocks the newly extended blocks! var dbi = new DeletedBlockInfo { StartBlockAddress = de.Key.Address }; dbi.EndBlockAddress = dbi.StartBlockAddress + de.Value; dbis.Add(new KeyValuePair <DeletedBlockInfo, OnDisk.File.IFile>(dbi, f)); } _addStore.Clear(); _fileGrowthStore.Clear(); _recycledCollectionStore.Clear(); int oldCommit = _inCommit; _inCommit = 0; if (Server.HasTrashBin) { foreach (KeyValuePair <DeletedBlockInfo, OnDisk.File.IFile> itm in dbis) { //** add to deleted blocks the newly extended blocks! itm.Value.DeletedCollections.Add(itm.Key); } foreach (KeyValuePair <DeletedBlockInfo, OnDisk.File.IFile> itm in dbis) { itm.Value.DeletedCollections.Flush(); itm.Value.DeletedCollections.OnCommit(); } } _inCommit = oldCommit; } if (OwnsRoot && isDisposing) { foreach (CollectionOnDisk cod in parents.Keys) { cod.CloseStream(); } } ClearStores(true); //** if no more ongoing transaction, we can safely delete the transaction backup data file File.Delete(Server.Path + DataBackupFilename); } finally { _inCommit--; if (Parent == null) { CollectionOnDisk.transaction = null; } else if (Parent.Children != null) { Parent.Children.Remove(this); } } CurrentCommitPhase = CommitPhase.Rolledback; }
/// <summary> /// Rollback uncomitted transactions. /// NOTE: this should be invoked upon restart so uncommited transaction(s) /// when program quits in previous run can be rolled back. /// </summary> /// <param name="serverFilename"> </param> /// <param name="serverProfile"> </param> /// <param name="createOpenObjectServerIfNoRollbackLog"> </param> public static Sop.ObjectServerWithTransaction RollbackAll(string serverFilename, Preferences preferences, bool createOpenObjectServerIfNoRollbackLog) { if (string.IsNullOrEmpty(serverFilename)) { throw new ArgumentNullException("serverFilename"); } if (!Sop.Utility.Utility.HasRequiredDirectoryAccess(serverFilename)) { throw new InvalidOperationException( string.Format("Not enough rights/access on directory containing file '{0}'.", serverFilename)); } string serverRootPath = System.IO.Path.GetDirectoryName(serverFilename); if (string.IsNullOrEmpty(serverRootPath)) { serverRootPath = System.Environment.CurrentDirectory; } string[] appendLogs = null; if (preferences != null && preferences.MemoryExtenderMode) { if (Sop.Utility.Utility.FileExists(serverFilename)) { Sop.Utility.Utility.FileDelete(serverFilename); Sop.Utility.Utility.FileDelete(string.Format("{0}.{1}", serverFilename, ObjectServer.DataInfExtensionLiteral)); } } //** NOTE: ProcessUpdateLog needs to be done ahead of RollbackAll as the latter //** removes backup files which are used by the former //** rollback all pending transaction updates... ProcessUpdateLog(serverRootPath, true); //** Rollback (delete) root trans created DB objects... if (TransactionRoot.RollbackAll(serverRootPath)) { /** AppendLogxx.txt * Grow d:\Sopbin\Sop\File.dta 1050624 2096 */ appendLogs = Directory.GetFiles(serverRootPath, string.Format("{0}*.txt", AppendLogLiteral)); } #region Process append logs if (appendLogs != null && (createOpenObjectServerIfNoRollbackLog || appendLogs.Length > 0)) { if (Sop.Utility.Utility.FileExists(serverFilename)) { var r = new ObjectServerWithTransaction(serverFilename, null, preferences); r.Open(); foreach (string s in appendLogs) { ITransactionLogger trans = Transaction.BeginWithNewRoot(r); //** open the file and do restore for each backed up entry using (var sr = new StreamReader(s)) { while (sr.Peek() >= 0) { string l = sr.ReadLine(); if (l.StartsWith(GrowToken)) { int i1 = l.LastIndexOf(' '); int i2 = l.LastIndexOf(' ', i1 - 1); string s2 = l.Substring(i2, i1 - i2); long address; if (long.TryParse(s2, out address)) { string fName = l.Substring(GrowToken.Length, i2 - GrowToken.Length); var f = (OnDisk.File.IFile)r.GetFile(fName); if (f != null) { var dbi = new DeletedBlockInfo(); dbi.StartBlockAddress = address; int segmentSize; if (int.TryParse(l.Substring(i1), out segmentSize)) { dbi.EndBlockAddress = dbi.StartBlockAddress + segmentSize; if (f.DeletedCollections != null) { f.DeletedCollections.Transaction = trans; f.DeletedCollections.Add(dbi); } } } } } } } r.Flush(); trans.Commit(); //** remove the Backup log file, we're done rolling back and it's no longer needed Sop.Utility.Utility.FileDelete(s); } r.Dispose(); //return r; } else { foreach (string s in appendLogs) { Sop.Utility.Utility.FileDelete(s); } } } #endregion return(null); }
/// <summary> /// DeSerialize /// </summary> /// <param name="parent"></param> /// <param name="reader"></param> public override void Unpack(IInternalPersistent parent, BinaryReader reader) { System.IO.BinaryReader binaryReader = reader; long l = binaryReader.ReadInt64(); if (l >= 0) { DiskBuffer.DataAddress = l; } long cnt = binaryReader.ReadInt64(); long saa = binaryReader.ReadInt64(); if ((Count > 0 && cnt == 0) || StartAllocatableAddress > 0 && saa == 0) { binaryReader.ReadInt64(); binaryReader.ReadInt64(); binaryReader.ReadInt64(); binaryReader.ReadInt64(); if (reader.ReadBoolean()) { var rs = new DeletedBlockInfo(); rs.Unpack(parent, reader); } return; } Count = cnt; //BinaryReader.ReadInt32(); StartAllocatableAddress = saa; // BinaryReader.ReadInt64(); EndAllocatableAddress = binaryReader.ReadInt64(); NextAllocatableAddress = binaryReader.ReadInt64(); long obh = binaryReader.ReadInt64(); long obt = binaryReader.ReadInt64(); DataBlockSize dataBlockSize; if (parent != null) { File.File f = (File.File)InternalPersistent.GetParent(parent, typeof(File.File), true); dataBlockSize = f.DataBlockSize; } else { dataBlockSize = (DataBlockSize)DiskBuffer.Length; } if (obh >= 0) { OccupiedBlocksHead = new Sop.DataBlock(dataBlockSize); OccupiedBlocksHead.DataAddress = obh; } else if (OccupiedBlocksHead != null) { OccupiedBlocksHead = null; } if (obt >= 0) { OccupiedBlocksTail = new Sop.DataBlock(dataBlockSize); OccupiedBlocksTail.DataAddress = obt; } else if (OccupiedBlocksTail != null) { OccupiedBlocksTail = null; } if (reader.ReadBoolean()) { RecycledSegment = new DeletedBlockInfo(); RecycledSegment.Unpack(parent, reader); RecycledSegmentBeforeTransaction = (DeletedBlockInfo)RecycledSegment.Clone(); } }