Beispiel #1
0
        public static long GetPosOfFirstPage(this DBHeaderBlock dbHeaderBlock, AllocPageTypes type)
        {
            long position;

            switch (type)
            {
            case AllocPageTypes.Table:
                position = dbHeaderBlock.FirstTablePagePos;
                break;

            case AllocPageTypes.Index:
                position = dbHeaderBlock.FirstIndexPagePos;
                break;

            case AllocPageTypes.SkipListNode:
                position = dbHeaderBlock.FirstSkipListNodePagePos;
                break;

            case AllocPageTypes.Data:
                position = dbHeaderBlock.FirstDataPagePos;
                break;

            default:
                throw new NotImplementedException();
            }

            return(position);
        }
        private static void SortPage(AllocPageTypes type, PageHeaderBlock page, FileStream fs, Transaction ts, Blocks.DBHeaderBlock dbHeader)
        {
            long headPos = dbHeader.GetPosOfFirstPage(type);

            if (headPos == 0)// 一个页也没有。
            {
                dbHeader.SetPosOfFirstPage(type, page.ThisPos);
            }
            else
            {
                PageHeaderBlock head = GetPageHeaderBlock(fs, ts, headPos);
                if (page.AvailableBytes >= head.AvailableBytes)// 与第一个页进行比较。
                {
                    page.NextPagePos = head.ThisPos;
                    dbHeader.SetPosOfFirstPage(type, page.ThisPos);
                }
                else// 与后续的页进行比较。
                {
                    PageHeaderBlock current = head;
                    while (current.NextPagePos != 0)
                    {
                        PageHeaderBlock next = GetPageHeaderBlock(fs, ts, current.NextPagePos);
                        if (page.AvailableBytes >= next.AvailableBytes)
                        {
                            if (next.ThisPos != current.NextPagePos)
                            {
                                throw new Exception(string.Format("this should not happen."));
                            }
                            page.NextPagePos    = current.NextPagePos; // next.ThisPos;
                            current.NextPagePos = page.ThisPos;
                            break;
                        }
                        else
                        {
                            current = next;
                        }
                    }
                    if (current.NextPagePos == 0)
                    {
                        current.NextPagePos = page.ThisPos;
                    }

                    if (!ts.affectedPages.ContainsKey(current.ThisPos))
                    {
                        ts.affectedPages.Add(current.ThisPos, current);
                    }
                }
            }
        }
Beispiel #3
0
        public static void SetPosOfFirstPage(this DBHeaderBlock dbHeaderBlock, AllocPageTypes type, long value)
        {
            switch (type)
            {
            case AllocPageTypes.Table:
                dbHeaderBlock.FirstTablePagePos = value;
                break;

            case AllocPageTypes.Index:
                dbHeaderBlock.FirstIndexPagePos = value;
                break;

            case AllocPageTypes.SkipListNode:
                dbHeaderBlock.FirstSkipListNodePagePos = value;
                break;

            case AllocPageTypes.Data:
                dbHeaderBlock.FirstDataPagePos = value;
                break;

            default:
                throw new NotImplementedException();
            }
        }
        public static IList <AllocatedSpace> Alloc(this FileDBContext db, long length, AllocPageTypes type)
        {
            // 由于一页能用的空间很有限,所以可能需要从多个页上获取空间。
            IList <AllocatedSpace> result = new List <AllocatedSpace>();

            FileStream fs = db.fileStream;

            long allocated = 0;

            while (allocated < length)
            {
                Int16 partLength = (length - allocated >= Consts.maxAvailableSpaceInPage) ? Consts.maxAvailableSpaceInPage : (Int16)(length - allocated);
                // 找出一个可用空间充足的指定类型的页。
                PageHeaderBlock page = PickPage(db, partLength, type);
                if (!db.transaction.affectedPages.ContainsKey(page.ThisPos))// 加入缓存备用。
                {
                    db.transaction.affectedPages.Add(page.ThisPos, page);
                }
                AllocatedSpace item = new AllocatedSpace(page.ThisPos + Consts.pageSize - page.AvailableBytes - partLength, (Int16)length);
                result.Add(item);
                allocated += partLength;
            }

            return(result);
        }
        private static PageHeaderBlock PickPage(this FileDBContext db, Int16 allocatingLength, AllocPageTypes type)
        {
            PageHeaderBlock page;

            FileStream    fs       = db.fileStream;
            Transaction   ts       = db.transaction;
            DBHeaderBlock dbHeader = db.headerBlock;

            // 找到第一个给定类型的页的位置。
            long pagePos = dbHeader.GetPosOfFirstPage(type);

            if (pagePos == 0)// 尚无给定类型的页。
            {
                page = db.AllocEmptyPageOrNewPage();

                page.AvailableBytes -= allocatingLength;
                page.OccupiedBytes  += allocatingLength;
                dbHeader.SetPosOfFirstPage(type, page.ThisPos);
            }
            else
            {
                // 最前面的table页的可用空间是最大的(这需要在后续操作中进行排序)
                PageHeaderBlock firstTablePage = GetTablePage(fs, ts, pagePos);

                if (firstTablePage.AvailableBytes >= allocatingLength)// 此页的空间足够用。
                {
                    // 把此页从Page链表中移除。
                    dbHeader.SetPosOfFirstPage(type, firstTablePage.NextPagePos);
                    firstTablePage.NextPagePos = 0;

                    page = firstTablePage;
                }
                else// 此页的空间不够用,还是要申请一个新页。
                {
                    page = db.AllocEmptyPageOrNewPage();
                }

                page.AvailableBytes -= allocatingLength;
                page.OccupiedBytes  += allocatingLength;

                // 对申请的类型的页的链表进行排序。呼应上面的排序需求。
                SortPage(type, page, fs, ts, dbHeader);
            }

            return(page);
        }
Beispiel #6
0
        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;
        }