public static AllocPageTypes BelongedPageType(this AllocBlock block) { AllocPageTypes pageType; Type type = block.GetType(); if (type == typeof(DataBlock)) { pageType = AllocPageTypes.Data; } else if (type == typeof(SkipListNodeBlock)) { pageType = AllocPageTypes.SkipListNode; } else if (type == typeof(IndexBlock)) { pageType = AllocPageTypes.Index; } else if (type == typeof(TableBlock)) { pageType = AllocPageTypes.Table; } else { throw new Exception("Wrong Block Type!"); } return(pageType); }
/// <summary> /// 添加一个准备从数据库文件中删除的块。 /// </summary> /// <param name="block"></param> public void Delete(AllocBlock block) { if (block.ThisPos == 0)// 尝试删除一个连在文件里的位置都没有的块。这个块似乎在文件里根本不存在。 { throw new Exception("Deleting [{0}] but it's position still not set!"); } if (!this.oldDeletingBlockPositions.Contains(block.ThisPos)) { this.oldDeletingBlockPositions.Add(block.ThisPos); this.deletingBlockList.Add(block); } else { throw new Exception(string.Format("{0} already instantiated!", block)); } }
/// <summary> /// 添加一个准备写入数据库的块。 /// </summary> /// <param name="block"></param> public void Add(AllocBlock block) { if (block.ThisPos == 0)// 这是一个新建的块。 { if (!this.addlingBlockList.Contains(block)) { this.addlingBlockList.Add(block); } } else// 这是已有的块。 { if (this.oldAddingBlockPositions.Contains(block.ThisPos)) { // 此时说明你重复反序列化了同一个块,这将导致数据混乱。 throw new Exception(string.Format("Block [{0}] already in transaction.", block)); } this.addlingBlockList.Add(block); this.oldAddingBlockPositions.Add(block.ThisPos); } }
private void DoCommit() { DBHeaderBlock dbHeaderBlock = this.fileDBContext.headerBlock; FileStream fs = this.fileDBContext.fileStream; // 给所有的块安排数据库文件中的位置。 List <Block> arrangedBlocks = new List <Block>(); while (arrangedBlocks.Count < this.addlingBlockList.Count) { for (int i = this.addlingBlockList.Count - 1; i >= 0; i--)// 后加入列表的先处理。 { AllocBlock block = this.addlingBlockList[i]; if (arrangedBlocks.Contains(block)) { continue; } bool done = block.ArrangePos(); if (done) { if (block.ThisPos == 0) { byte[] bytes = block.ToBytes(); if (bytes.Length > Consts.maxAvailableSpaceInPage) { throw new Exception("Block size is toooo large!"); } AllocPageTypes pageType = block.BelongedPageType(); IList <AllocatedSpace> spaces = this.fileDBContext.Alloc(bytes.LongLength, pageType); block.ThisPos = spaces[0].position; } arrangedBlocks.Add(block); } } } // 根据要删除的块,更新文件头。 foreach (var block in this.deletingBlockList) { long pagePos = block.ThisPos.PagePos(); PageHeaderBlock page; if (!this.affectedPages.TryGetValue(pagePos, out page)) { page = fs.ReadBlock <PageHeaderBlock>(pagePos); this.affectedPages.Add(pagePos, page); } byte[] bytes = block.ToBytes(); Int16 length = (Int16)bytes.Length; if (length > Consts.maxAvailableSpaceInPage) { throw new Exception(string.Format("Block [{0}]'s serialized bytes is more than {1}", block, Consts.maxAvailableSpaceInPage)); } page.OccupiedBytes -= length; if (page.OccupiedBytes < Consts.minOccupiedBytes) { throw new Exception(string.Format("DB Error: {0}'s Occupied bytes is less than {1}", page, Consts.minOccupiedBytes)); } if (page.OccupiedBytes == Consts.minOccupiedBytes)// 此页已成为新的空白页。 { // page 加入空白页链表。 //DBHeaderBlock dbHeader = this.fileDBContext.headerBlock; page.NextPagePos = dbHeaderBlock.FirstEmptyPagePos; dbHeaderBlock.FirstEmptyPagePos = page.ThisPos; } } // 准备恢复文件。 string journalFilename = this.fileDBContext.JournalFileName; FileStream journalFile = new FileStream(journalFilename, FileMode.Create, FileAccess.ReadWrite, FileShare.None, Consts.pageSize); foreach (Block block in this.addlingBlockList) { Consts.formatter.Serialize(journalFile, block); } foreach (PageHeaderBlock block in this.affectedPages.Values) { if (block.IsDirty) { Consts.formatter.Serialize(journalFile, block); } } if (dbHeaderBlock.IsDirty) { Consts.formatter.Serialize(journalFile, dbHeaderBlock); } journalFile.Flush(); // 写入所有的更改。 foreach (Block block in this.addlingBlockList) { fs.WriteBlock(block); } foreach (PageHeaderBlock block in this.affectedPages.Values) { if (block.IsDirty) { fs.WriteBlock(block); block.IsDirty = false; } } if (dbHeaderBlock.IsDirty) { fs.WriteBlock(dbHeaderBlock); dbHeaderBlock.IsDirty = false; } fs.Flush(); // 删除恢复文件。 journalFile.Close(); journalFile.Dispose(); File.Delete(journalFilename); // 恢复Transaction最初的状态。 this.addlingBlockList.Clear(); this.oldAddingBlockPositions.Clear(); this.deletingBlockList.Clear(); this.oldDeletingBlockPositions.Clear(); this.affectedPages.Clear(); //if (actUnlockDB == null) { actUnlockDB = new Action(UnlockDB); } UnlockDB(); this.level = 0; }