/// <summary> /// Frees disk space /// </summary> /// <param name="MemoryRequirement">The memory required to be freed</param> /// <returns>The actual memory freed</returns> public long FreeSpace(long MemoryRequirement) { // #DEBUG# // this._Host.DebugPrint("TableStore.FreeSpace({0})", MemoryRequirement); long ReleasedSpace = 0; this._Host.DebugDepth++; while (!this.HasSpaceFor(MemoryRequirement)) { PageUID x = this._PageBurnStack.Dequeue(); Page p = this._PageStore[x]; this.ClosePage(x); ReleasedSpace += p.PageSize; // #DEBUG# // this._Host.DebugPrint("TableStore.FreeSpace-> page removed from memory({0})", x.ToString()); } this._Host.DebugDepth--; // #DEBUG# // this._Host.DebugPrint("TableStore.FreeSpace-> total memory reclaimed({0})", ReleasedSpace); return(ReleasedSpace); }
/// <summary> /// Flushes a page and releases it from memory /// </summary> /// <param name="ID"></param> public void ClosePage(PageUID ID) { // #DEBUG# // this._Host.DebugPrint("TableStore.ClosePage-> ({0})", ID.ToString()); this.FlushPage(ID); this.ReleasePage(ID); }
/// <summary> /// Requests a page, either buffering it or pulling it from the in memory page store /// </summary> /// <param name="ID"></param> /// <returns></returns> public Page RequestPage(PageUID ID) { // Check the Page ID // if (ID.PageID < 0) { throw new Exception(string.Format("Page ID {0} is invalid", ID.PageID)); } this._Host.DebugPrint("TableStore.RequestPage({0})", ID.ToString()); // #DEBUG# // Check if the page is in memory // if (this.PageIsInMemory(ID)) { this._Host.DebugPrint("TableStore.RequestPage->page found in memory({0})", ID.ToString()); // #DEBUG# return(this._PageStore[ID]); } // Check if the table is in memory or not // if (!this.TableIsInMemory(ID.Key)) { throw new ObjectNotInMemoryException(string.Format("Table '{0}' is not memory; critical code error", ID.Key)); } // Otherwise, check if we have space // int Size = this._TableStore[ID.Key].PageSize; if (!this.HasSpaceFor(Size)) { this.FreeSpace(Size); } // Tag in the recycling bin // this._PageBurnStack.EnqueueOrTag(ID); this._Host.DebugPrint("TableStore.RequestPage->page added to burn Intermediary({0})", ID.ToString()); // #DEBUG# // Page // Page p = TableStore.Buffer(ID.Key, ID.PageID, Size); this._PageInMemoryCounts[ID.Key]++; this._Host.DebugPrint("TableStore.RequestPage->page buffered({0})", ID.ToString()); // #DEBUG# this.PushPage(ID.Key, p); return(p); }
/// <summary> /// Adds a page to the store /// </summary> /// <param name="Key"></param> /// <param name="Key"></param> public void PushPage(string Key, Page Element) { // Check if the table is in memory or not // if (!this.TableIsInMemory(Key)) { throw new ObjectNotInMemoryException(string.Format("Table '{0}' is not memory; critical code error", Key)); } PageUID id = new PageUID(Key, Element.PageID); // Check if the page is in memory // if (this.PageIsInMemory(id)) { // #DEBUG# // this._Host.DebugPrint("TableStore.PushPage-> page found in memory({0})", id.ToString()); this._Host.DebugPrint("TableStore.PushPage-> page added to burn Intermediary({0})", id.ToString()); this._PageStore[id] = Element; this._PageBurnStack.EnqueueOrTag(id); return; } // Otherwise, check if we have space // int Size = Element.PageSize; if (!this.HasSpaceFor(Size)) { this._Host.DebugPrint("TableStore.PushPage-> Freeing space"); this._Host.DebugDepth++; this.FreeSpace(Size * this._FreePageFactor); this._Host.DebugDepth--; } // Tag in the recycling bin // this._PageBurnStack.EnqueueOrTag(id); // Add to the store // this._PageStore.Add(id, Element); // Increment the used memory // this._CurrentMemory += Element.PageSize; // #DEBUG# // this._Host.DebugPrint("TableStore.PushPage-> page added({0}) : used/free memory {1}/{2}", id.ToString(), this.UsedMemory, this.FreeMemory); }
/// <summary> /// Removes a page from memory // /// </summary> /// <param name="ID"></param> public void ReleasePage(PageUID ID) { // Removes a page from memory // if (this.PageIsInMemory(ID)) { this._CurrentMemory -= this._PageStore[ID].PageSize; this._PageInMemoryCounts[ID.Key]--; this._PageStore.Remove(ID); if (this._PageBurnStack.Contains(ID)) { this._PageBurnStack.Remove(ID); } this._Host.DebugPrint("TableStore.ReleasePage-> page released from memory({0}) : used/free memory {1}/{2}", ID.ToString(), this.UsedMemory, this.FreeMemory); // #DEBUG# } else { this._Host.DebugPrint("TableStore.ReleasePage-> page not found in memory({0}) : used/free memory {1}/{2}", ID.ToString(), this.UsedMemory, this.FreeMemory); // #DEBUG# } }
/// <summary> /// Flushes a page to disk /// </summary> /// <param name="ID"></param> public void FlushPage(PageUID ID) { // Check if the page is in memory // if (!this.PageIsInMemory(ID)) { throw new ObjectNotInMemoryException(string.Format("Page ID '{0}' is not memory; critical code error", ID)); } Page p = this._PageStore[ID]; // Check the version, only flush if the page has been altered // if (p.Version > 0) { TableStore.Flush(ID.Key, p); // #DEBUG# // this._Host.DebugPrint("TableStore.FlushPage-> page flushed to disk({0})", ID.ToString()); } else { // #DEBUG# // this._Host.DebugPrint("TableStore.FlushPage-> page unaltered; not flushed({0})", ID.ToString()); } }
// Page Methods // /// <summary> /// Checks if the table is in memory /// </summary> /// <param name="ID"></param> /// <returns></returns> public bool PageIsInMemory(PageUID ID) { return(this._PageStore.ContainsKey(ID)); }
/// <summary> /// Gets a table, either from memory or disk /// </summary> /// <param name="Key"></param> /// <returns></returns> public Table RequestTable(string Key) { // #DEBUG# // this._Host.DebugPrint("TableStore.RequestTable({0})", Key); this._Host.DebugDepth++; if (this.TableIsInMemory(Key)) { // #DEBUG# // this._Host.DebugPrint("TableStore.RequestTable->Table in memory({0})", Key); return(this._TableStore[Key]); } else { // Get the header // TableHeader h = Buffer(Key); Table t; // Create the actual table // if (h.RootPageID == -1) { t = new HeapTable(this._Host, h); // #DEBUG# // this._Host.DebugPrint("TableStore.RequestTable->Table not in memory; buffering table as HEAP ({0})", Key); } else { t = new TreeTable(this._Host, h); // #DEBUG# // this._Host.DebugPrint("TableStore.RequestTable->Table not in memory; buffering table as CLUSTER ({0})", Key); } // Add to the table store // this.PushTable(t); // Need to buffer a block of pages and make sure these pages are not in memory // Check to see how many pages we can buffer // int MaxPages = (int)(this.FreeMemory / h.PageSize); int Pages = Math.Min(h.PageCount, MaxPages); // Buffer a block of pages // // #DEBUG# // this._Host.DebugPrint("TableStore.RequestTable->Buffering a block of pages ({0}); from {1} - {2} of {3}", Key, 0, Pages, h.PageCount); foreach (Page p in BufferBlock(h, 0, Pages)) { PageUID k = new PageUID(Key, p.PageID); if (this._PageStore.ContainsKey(k)) { this._PageStore[k] = p; } else { this._PageStore.Add(k, p); } } this._Host.DebugDepth--; return(t); } }