/// <summary>
        /// 申请一个空白页或新页。
        /// </summary>
        /// <param name="db"></param>
        /// <returns></returns>
        private static PageHeaderBlock AllocEmptyPageOrNewPage(this FileDBContext db)
        {
            PageHeaderBlock page;

            FileStream    fs           = db.fileStream;
            DBHeaderBlock dbHeader     = db.headerBlock;
            long          emptyPagePos = dbHeader.FirstEmptyPagePos;

            if (emptyPagePos != 0)// 存在空白页,则使用此空白页。
            {
                PageHeaderBlock emptyPage = fs.ReadBlock <PageHeaderBlock>(emptyPagePos);
                // 从链表中去掉此空白页。
                dbHeader.FirstEmptyPagePos = emptyPage.NextPagePos;
                emptyPage.NextPagePos      = 0;

                page = emptyPage;
            }
            else// 没有空白页,则拓展数据库文件,增加一个页的长度。
            {
                PageHeaderBlock newPage = new PageHeaderBlock();
                newPage.ThisPos        = fs.Length;
                newPage.OccupiedBytes  = (Int16)(Consts.pageSize - Consts.maxAvailableSpaceInPage);
                newPage.AvailableBytes = Consts.maxAvailableSpaceInPage;
                fs.SetLength(fs.Length + Consts.pageSize);

                page = newPage;
            }

            return(page);
        }
Example #2
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);
        }
Example #3
0
        //static readonly Brush dbHeaderBrush = new LinearGradientBrush(new Rectangle(0, 0, Consts.dbHeaderBlockLength, bmpHeight), Color.Silver, Color.GreenYellow, 270f);

        private static void DrawDBHeader(FileDBContext db, Bitmap[] bmps)
        {
            DBHeaderBlock dbHeader = db.GetDBHeaderBlock();
            long          index    = 0;
            Graphics      g        = Graphics.FromImage(bmps[index]);
            int           startPos = (int)(dbHeader.ThisPos - Consts.pageSize * index);
            int           length   = dbHeader.ToBytes().Length;
            Brush         brush    = new LinearGradientBrush(new Point(startPos, 0), new Point(startPos + length, 0), Color.Purple, Color.Aqua);

            g.FillRectangle(brush, startPos, 1, length, bmpHeight - 1);
            g.DrawRectangle(boundPen, startPos, 1, length, bmpHeight - 1);
            g.Dispose();
        }
        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);
        }
        /// <summary>
        /// 创建初始状态的数据库文件。
        /// </summary>
        /// <param name="fullname">数据库文件据对路径。</param>
        /// <param name="config">数据库配置信息。</param>
        private void CreateDB(string fullname, DBConfig config)
        {
            FileInfo fileInfo = new FileInfo(fullname);

            Directory.CreateDirectory(fileInfo.DirectoryName);
            using (FileStream fs = new FileStream(fullname, FileMode.CreateNew, FileAccess.Write, FileShare.None, Consts.pageSize))
            {
                PageHeaderBlock page = new PageHeaderBlock()
                {
                    OccupiedBytes = Consts.pageSize, AvailableBytes = 0,
                };
                fs.WriteBlock(page);

                DBHeaderBlock dbHeader = new DBHeaderBlock()
                {
                    MaxLevelOfSkipList = config.MaxLevelOfSkipList, ProbabilityOfSkipList = config.ProbabilityOfSkipList, MaxSunkCountInMemory = config.MaxSunkCountInMemory, LockTimeout = config.LockTimeout, ThisPos = fs.Position
                };
                fs.WriteBlock(dbHeader);

                TableBlock tableHead = new TableBlock()
                {
                    ThisPos = fs.Position,
                };
                fs.WriteBlock(tableHead);

                byte[] leftSpace = new byte[Consts.pageSize - fs.Length];
                fs.Write(leftSpace, 0, leftSpace.Length);

                BlockCache.TryRemoveFloatingBlock(page);
                BlockCache.TryRemoveFloatingBlock(dbHeader);
                BlockCache.TryRemoveFloatingBlock(tableHead);
                BlockCache.TryRemoveSunkBlock(page);
                BlockCache.TryRemoveSunkBlock(dbHeader);
                BlockCache.TryRemoveSunkBlock(tableHead);
            }
        }
Example #6
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();
            }
        }
        /// <summary>
        /// 打印数据库文件里所有表的所有主键的skip list和所有类型的页链表。
        /// </summary>
        /// <param name="db"></param>
        /// <returns></returns>
        public static string Print(this FileDBContext db)
        {
            StringBuilder builder = new StringBuilder();

            builder.AppendLine(db.Fullname);
            FileStream fs = db.GetFileStream();
            //PageHeaderBlock firstPage = fs.ReadBlock<PageHeaderBlock>(0);
            DBHeaderBlock dbHeader = db.GetDBHeaderBlock();// fs.ReadBlock<DBHeaderBlock>(fs.Position);

            PrintSkipLists(db, builder, fs);

            builder.AppendLine();
            builder.AppendLine("Page Info.:");
            for (long i = 0; i < fs.Length; i += Consts.pageSize)
            {
                PageHeaderBlock pageInfo = fs.ReadBlock <PageHeaderBlock>(i);
                string          str      = Print(pageInfo);
                builder.AppendLine(str);
            }
            builder.AppendLine();

            builder.AppendLine();
            builder.AppendLine("table pages:");
            long tablePos = dbHeader.FirstTablePagePos;

            while (tablePos != 0)
            {
                PageHeaderBlock pageInfo = fs.ReadBlock <PageHeaderBlock>(tablePos);
                builder.Append(string.Format(" {0}[{1}] ->", pageInfo.ThisPos, pageInfo.ThisPos / Consts.pageSize));
                tablePos = pageInfo.NextPagePos;
            }
            builder.AppendLine();

            builder.AppendLine();
            builder.AppendLine("index pages:");
            long indexPos = dbHeader.FirstIndexPagePos;

            while (indexPos != 0)
            {
                PageHeaderBlock pageInfo = fs.ReadBlock <PageHeaderBlock>(indexPos);
                builder.Append(string.Format(" {0}[{1}] ->", pageInfo.ThisPos, pageInfo.ThisPos / Consts.pageSize));
                indexPos = pageInfo.NextPagePos;
            }
            builder.AppendLine();

            builder.AppendLine();
            builder.AppendLine("skip list node pages:");
            long skiplistnodePos = dbHeader.FirstSkipListNodePagePos;

            while (skiplistnodePos != 0)
            {
                PageHeaderBlock pageInfo = fs.ReadBlock <PageHeaderBlock>(skiplistnodePos);
                builder.Append(string.Format(" {0}[{1}] ->", pageInfo.ThisPos, pageInfo.ThisPos / Consts.pageSize));
                skiplistnodePos = pageInfo.NextPagePos;
            }
            builder.AppendLine();

            builder.AppendLine();
            builder.AppendLine("data block pages:");
            long dataBlockPos = dbHeader.FirstDataPagePos;

            while (dataBlockPos != 0)
            {
                PageHeaderBlock pageInfo = fs.ReadBlock <PageHeaderBlock>(dataBlockPos);
                builder.Append(string.Format(" {0}[{1}] ->", pageInfo.ThisPos, pageInfo.ThisPos / Consts.pageSize));
                dataBlockPos = pageInfo.NextPagePos;
            }
            builder.AppendLine();

            builder.AppendLine();
            builder.AppendLine("empty pages:");
            long emptyPos = dbHeader.FirstEmptyPagePos;

            while (emptyPos != 0)
            {
                PageHeaderBlock pageInfo = fs.ReadBlock <PageHeaderBlock>(emptyPos);
                builder.Append(string.Format(" {0}[{1}] ->", pageInfo.ThisPos, pageInfo.ThisPos / Consts.pageSize));
                emptyPos = pageInfo.NextPagePos;
            }
            builder.AppendLine();

            return(builder.ToString());
        }
        /// <summary>
        /// 根据数据库文件初始化<see cref="FileDBContext"/>。
        /// </summary>
        /// <param name="fullname">数据库文件据对路径。</param>
        /// <param name="read">只读方式打开。</param>
        private void InitializeDB(string fullname, bool read)
        {
            // 尝试恢复数据库文件。
            string journalFilename = this.JournalFileName;

            if (File.Exists(journalFilename))
            {
                using (FileStream journal = new FileStream(journalFilename, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
                {
                    using (FileStream fs = new FileStream(fullname, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
                    {
                        while (journal.Position < journal.Length)
                        {
                            object obj   = Consts.formatter.Deserialize(journal);
                            Block  block = obj as Block;
                            fs.WriteBlock(block);
                        }
                    }
                }
                File.Delete(journalFilename);
            }

            // 准备各项工作。
            // 准备数据库文件流。
            FileStream fileStream = null;

            if (read)
            {
                fileStream      = new FileStream(fullname, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                this.fileStream = fileStream;
            }
            else
            {
                fileStream      = new FileStream(fullname, FileMode.Open, FileAccess.ReadWrite, FileShare.Read);
                this.fileStream = fileStream;
            }
            // 准备数据库头部块。
            //PageHeaderBlock pageHeaderBlock = fileStream.ReadBlock<PageHeaderBlock>(0);
            DBHeaderBlock headerBlock = fileStream.ReadBlock <DBHeaderBlock>(Consts.pageHeaderBlockLength);

#if DEBUG
            Block.IDCounter = headerBlock.BlockCount;
#endif
            BlockCache.MaxSunkCountInMemory = headerBlock.MaxSunkCountInMemory;
            this.headerBlock = headerBlock;
            // 准备数据库表块,保存到字典。
            TableBlock currentTableBlock = fileStream.ReadBlock <TableBlock>(Consts.pageHeaderBlockLength + Consts.dbHeaderBlockLength);
            this.tableBlockHead = currentTableBlock;
            while (currentTableBlock.NextPos != 0)
            {
                TableBlock tableBlock = fileStream.ReadBlock <TableBlock>(currentTableBlock.NextPos);

                currentTableBlock.NextObj = tableBlock;

                Dictionary <string, IndexBlock> indexDict = GetIndexDict(fileStream, tableBlock);
                this.tableIndexBlockDict.Add(tableBlock.TableType, indexDict);

                this.tableBlockDict.Add(tableBlock.TableType, tableBlock);

                currentTableBlock = tableBlock;
            }
        }
Example #9
0
        /// <summary>
        /// 系统启动时初始化各项常量。
        /// </summary>
        static Consts()
        {
            {
                PropertyInfo[] properties = typeof(Table).GetProperties();
                foreach (var property in properties)
                {
                    TableIndexAttribute attr = property.GetCustomAttribute <TableIndexAttribute>();
                    if (attr != null && property.PropertyType == typeof(ObjectId))
                    {
                        Consts.TableIdString = property.Name;
                        break;
                    }
                }
            }
            {
                PageHeaderBlock page = new PageHeaderBlock();
                using (MemoryStream ms = new MemoryStream())
                {
                    formatter.Serialize(ms, page);
                    if (ms.Length > Consts.pageSize / 10)
                    {
                        throw new Exception("Page header block takes too much space!");
                    }
                    Consts.pageHeaderBlockLength   = (Int16)ms.Length;
                    Consts.maxAvailableSpaceInPage = (Int16)(Consts.pageSize - ms.Length);
                    Consts.minOccupiedBytes        = (Int16)(Consts.pageSize - Consts.maxAvailableSpaceInPage);
                }
                BlockCache.TryRemoveFloatingBlock(page);
            }


            {
                PageHeaderBlock page      = new PageHeaderBlock();
                DBHeaderBlock   dbHeader  = new DBHeaderBlock();
                TableBlock      tableHead = new TableBlock();
                Int16           usedSpaceInFirstPage;
                using (MemoryStream ms = new MemoryStream())
                {
                    formatter.Serialize(ms, page);
                    dbHeader.ThisPos = ms.Length;
                    formatter.Serialize(ms, dbHeader);
                    tableHead.ThisPos          = ms.Length;
                    Consts.dbHeaderBlockLength = (Int16)(ms.Length - Consts.pageHeaderBlockLength);
                    formatter.Serialize(ms, tableHead);
                    Consts.tableBlockLength = (Int16)(ms.Length - tableHead.ThisPos);
                    usedSpaceInFirstPage    = (Int16)ms.Length;
                }

                if (usedSpaceInFirstPage > Consts.pageSize)
                {
                    throw new Exception("First page is full!");
                }
                BlockCache.TryRemoveFloatingBlock(page);
                BlockCache.TryRemoveFloatingBlock(dbHeader);
                BlockCache.TryRemoveFloatingBlock(tableHead);
            }
            {
                IndexBlock block  = new IndexBlock();
                int        length = block.ToBytes().Length;
                if (length > Consts.pageSize / 10)
                {
                    throw new Exception("index block takes too much space!");
                }
                Consts.indexBlockLength = (Int16)length;
                BlockCache.TryRemoveFloatingBlock(block);
            }
            {
                SkipListNodeBlock block = new SkipListNodeBlock();
                int length = block.ToBytes().Length;
                if (length > Consts.pageSize / 10)
                {
                    throw new Exception("index block takes too much space!");
                }
                Consts.skipListNodeBlockLength = (Int16)length;
                BlockCache.TryRemoveFloatingBlock(block);
            }
            {
                PageHeaderBlock page      = new PageHeaderBlock();
                DataBlock       dataBlock = new DataBlock();
                dataBlock.Data = new byte[0];
                Int16 minValue;
                using (MemoryStream ms = new MemoryStream())
                {
                    formatter.Serialize(ms, page);
                    long pos = ms.Length;
                    formatter.Serialize(ms, dataBlock);
                    Consts.dataBlockLength = (Int16)(ms.Length - pos);
                    if (ms.Length > Consts.pageSize / 10)
                    {
                        throw new Exception("data block's metadata takes too much space!");
                    }
                    minValue = (Int16)ms.Length;
                }
                Consts.maxDataBytes = (Int16)(Consts.pageSize - minValue);
                BlockCache.TryRemoveFloatingBlock(page);
                BlockCache.TryRemoveFloatingBlock(dataBlock);
            }
        }
Example #10
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;
        }