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);
        }
        /// <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);
        }
        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);
                    }
                }
            }
        }
        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);
        }
Example #5
0
        //static readonly Brush pageHeaderBrush = new LinearGradientBrush(new Rectangle(0, 0, Consts.pageHeaderBlockLength, bmpHeight), Color.Silver, Color.GreenYellow, 90);


        private static void DrawPageHeaders(FileStream fs, long pageCount, Bitmap[] bmps)
        {
            for (int i = 0; i < pageCount; i++)
            {
                long            pos      = i * Consts.pageSize;
                PageHeaderBlock page     = fs.ReadBlock <PageHeaderBlock>(pos);
                long            index    = pos / Consts.pageSize;
                Bitmap          bmp      = bmps[index];
                Graphics        g        = Graphics.FromImage(bmp);
                int             startPos = (int)(page.ThisPos - Consts.pageSize * index);
                int             length   = page.ToBytes().Length;
                Brush           brush    = new LinearGradientBrush(new Point(startPos, 0), new Point(startPos + length, 0), Color.YellowGreen, Color.GreenYellow);
                g.FillRectangle(brush, startPos, 1, length, bmpHeight - 1);
                g.DrawRectangle(boundPen, startPos, 1, length, bmpHeight - 1);
                g.Dispose();
            }
        }
        /// <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);
            }
        }
        /// <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());
        }
 static string Print(PageHeaderBlock pageHeaderBlock)
 {
     return(string.Format("Pos: {0}, available: {1}, Occupied: {2}",
                          pageHeaderBlock.ThisPos, pageHeaderBlock.AvailableBytes, pageHeaderBlock.OccupiedBytes));
 }
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);
            }
        }