private Dictionary <string, IndexBlock> GetIndexDict(FileStream fileStream, TableBlock tableBlock) { Dictionary <string, IndexBlock> indexDict = new Dictionary <string, IndexBlock>(); long indexBlockHeadPos = tableBlock.IndexBlockHeadPos; IndexBlock currentIndexBlock = fileStream.ReadBlock <IndexBlock>(indexBlockHeadPos); tableBlock.IndexBlockHead = currentIndexBlock; currentIndexBlock.TryLoadNextObj(fileStream);// 此时的currentIndexBlock是索引块的头结点。 while (currentIndexBlock.NextObj != null) { SkipListNodeBlock[] headNodes = GetHeadNodesOfSkipListNodeBlock(fileStream, currentIndexBlock.NextObj); currentIndexBlock.NextObj.SkipListHeadNodes = headNodes; SkipListNodeBlock tailNode = GetTailNodeOfSkipListNodeBlock(fileStream, currentIndexBlock.NextObj); currentIndexBlock.NextObj.SkipListTailNode = tailNode; foreach (SkipListNodeBlock headNode in currentIndexBlock.NextObj.SkipListHeadNodes) { if (headNode.RightPos == tailNode.ThisPos) { headNode.RightObj = tailNode; } } currentIndexBlock.NextObj.TryLoadNextObj(fileStream); indexDict.Add(currentIndexBlock.NextObj.BindMember, currentIndexBlock.NextObj); currentIndexBlock = currentIndexBlock.NextObj; } return(indexDict); }
/// <summary> /// 为指定的索引生成头结点和尾结点。 /// </summary> /// <param name="indexBlock"></param> /// <param name="maxLevel"></param> private void InitHeadTailNodes(IndexBlock indexBlock, int maxLevel) { { // 初始化头结点列。 indexBlock.SkipListHeadNodes = new SkipListNodeBlock[maxLevel]; /*SkipListHeadNodes[maxLevel - 1]↓*/ /*SkipListHeadNodes[.]↓*/ /*SkipListHeadNodes[.]↓*/ /*SkipListHeadNodes[2]↓*/ /*SkipListHeadNodes[1]↓*/ /*SkipListHeadNodes[0] */ SkipListNodeBlock current = new SkipListNodeBlock(); indexBlock.SkipListHeadNodes[0] = current; for (int i = 1; i < maxLevel; i++) { SkipListNodeBlock block = new SkipListNodeBlock(); block.DownObj = current; indexBlock.SkipListHeadNodes[i] = block; current = block; } } { // 初始化尾结点。尾结点在序列化到数据库文件后,将永远不再变动,这给编码带来方便,也是我使用尾结点的原因。 // 这样也是完全把外存(硬盘)与内存编程相对应的思想。 indexBlock.SkipListTailNode = new SkipListNodeBlock(); } { // 头结点指向对应的尾结点。 for (int i = 0; i < maxLevel; i++) { indexBlock.SkipListHeadNodes[i].RightObj = indexBlock.SkipListTailNode; } } }
private static SkipListNodeBlock[] FindRightMostNodes(IComparable key, IndexBlock indexBlock, FileDBContext db) { FileStream fs = db.fileStream; int maxLevel = db.headerBlock.MaxLevelOfSkipList; SkipListNodeBlock[] rightNodes = new SkipListNodeBlock[maxLevel]; // Start at the top list header node SkipListNodeBlock currentNode = indexBlock.SkipListHeadNodes[indexBlock.CurrentLevel]; for (int i = indexBlock.CurrentLevel; i >= 0; i--) { IComparable rightKey = db.GetRightObjKey(db.fileStream, indexBlock, currentNode); while ((currentNode.RightObj != indexBlock.SkipListTailNode) && (rightKey.CompareTo(key) < 0)) { currentNode = currentNode.RightObj; rightKey = db.GetRightObjKey(db.fileStream, indexBlock, currentNode); } rightNodes[i] = currentNode; if (i > 0) { currentNode.TryLoadProperties(fs, SkipListNodeBlockLoadOptions.DownObj); currentNode = currentNode.DownObj; } } return(rightNodes); }
private static void DrawDataBlocks(FileDBContext db, FileStream fs, Bitmap[] bmps) { TableBlock tableBlockHead = db.GetTableBlockHeadNode(); TableBlock previousTable = tableBlockHead; while (previousTable.NextPos != 0) { TableBlock table = previousTable.NextObj; IndexBlock currentIndex = table.IndexBlockHead; while (currentIndex.NextObj != null) { SkipListNodeBlock currentNode = currentIndex.NextObj.SkipListHeadNodes[0]; while (currentNode != null) { if (currentNode.KeyPos != 0) { currentNode.TryLoadProperties(fs, SkipListNodeBlockLoadOptions.Key | SkipListNodeBlockLoadOptions.Value); { long index = currentNode.Key.ThisPos.PagePos() / Consts.pageSize; Bitmap bmp = bmps[index]; Graphics g = Graphics.FromImage(bmp); int startPos = (int)(currentNode.Key.ThisPos - Consts.pageSize * index); int length = currentNode.Key.ToBytes().Length; Brush brush = new LinearGradientBrush(new Point(startPos, 0), new Point(startPos + length, 0), Color.DarkGoldenrod, Color.LightGoldenrodYellow); g.FillRectangle(brush, startPos, 1, length, bmpHeight - 1); g.DrawRectangle(boundPen, startPos, 1, length, bmpHeight - 1); g.Dispose(); } foreach (var dataBlock in currentNode.Value) { long index = dataBlock.ThisPos.PagePos() / Consts.pageSize; Bitmap bmp = bmps[index]; Graphics g = Graphics.FromImage(bmp); int startPos = (int)(dataBlock.ThisPos - Consts.pageSize * index); int length = dataBlock.ToBytes().Length; Brush brush = new LinearGradientBrush(new Point(startPos, 0), new Point(startPos + length, 0), Color.DarkGoldenrod, Color.LightGoldenrodYellow); g.FillRectangle(brush, startPos, 1, length, bmpHeight - 1); g.DrawRectangle(boundPen, startPos, 1, length, bmpHeight - 1); g.Dispose(); } } currentNode.TryLoadProperties(fs, SkipListNodeBlockLoadOptions.RightObj); currentNode = currentNode.RightObj; } currentIndex = currentIndex.NextObj; } previousTable = table; } }
/// <summary> /// 删除数据库内的一条记录。 /// </summary> /// <param name="record"></param> public bool Delete(Table record) { if (record.Id == null) { throw new Exception(string.Format("[{0}] is a new record!", record)); } Type type = record.GetType(); if (!this.tableBlockDict.ContainsKey(type))// 添加表和索引数据。 { throw new Exception(string.Format("No Table for type [{0}] is set!", type)); } Transaction ts = this.transaction; ts.Begin(); try { // 删除record。 IndexBlock indexBlock = this.tableIndexBlockDict[type][Consts.TableIdString]; SkipListNodeBlock downNode = FindSkipListNode(fileStream, indexBlock, record.Id); if (downNode == null)// 此记录根本不存在或已经被删除过一次了。 { throw new Exception(string.Format("no data blocks for [{0}]", record)); } foreach (KeyValuePair <string, IndexBlock> item in this.tableIndexBlockDict[type]) { item.Value.Delete(record, this); } downNode.TryLoadProperties(fileStream, SkipListNodeBlockLoadOptions.Key | SkipListNodeBlockLoadOptions.Value); for (int i = 0; i < downNode.Value.Length; i++) { this.transaction.Delete(downNode.Value[i]); } // 加入事务,准备写入数据库。 this.transaction.Delete(downNode.Key); // 加入事务,准备写入数据库。 this.transaction.Commit(); return(true); } catch (Exception ex) { ts.Rollback(); throw ex; } }
private SkipListNodeBlock GetTailNodeOfSkipListNodeBlock(FileStream fileStream, IndexBlock indexBlock) { long currentSkipListNodeBlockPos = indexBlock.SkipListTailNodePos; if (currentSkipListNodeBlockPos == 0) { throw new Exception(string.Format("tail node not set for [{0}]", indexBlock)); } SkipListNodeBlock tailNode = fileStream.ReadBlock <SkipListNodeBlock>(currentSkipListNodeBlockPos); return(tailNode); }
private static void GetSkipListInfo(IndexBlock indexBlock, FileDBContext db, out List <List <SkipListNodeBlock> > skipList, out Dictionary <long, DataBlock> keyDict, out Dictionary <long, DataBlock> valueDict, out Dictionary <long, SkipListNodeBlock> skipListNodeDict) { FileStream fs = db.GetFileStream(); skipList = new List <List <SkipListNodeBlock> >(); keyDict = new Dictionary <long, DataBlock>(); valueDict = new Dictionary <long, DataBlock>(); skipListNodeDict = new Dictionary <long, SkipListNodeBlock>(); long headNodePos = indexBlock.SkipListHeadNodePos; long currentHeadNodePos = headNodePos; while (currentHeadNodePos != 0) { List <SkipListNodeBlock> line = new List <SkipListNodeBlock>(); long currentNodePos = currentHeadNodePos; while (currentNodePos != 0) { SkipListNodeBlock currentNode = fs.ReadBlock <SkipListNodeBlock>(currentNodePos); line.Add(currentNode); if (!skipListNodeDict.ContainsKey(currentNode.ThisPos)) { skipListNodeDict.Add(currentNode.ThisPos, currentNode); } if (currentNode.KeyPos != 0) { if (!keyDict.ContainsKey(currentNode.KeyPos)) { DataBlock keyBlock = fs.ReadBlock <DataBlock>(currentNode.KeyPos); keyDict.Add(currentNode.KeyPos, keyBlock); } } if (currentNode.ValuePos != 0) { if (!valueDict.ContainsKey(currentNode.ValuePos)) { DataBlock valueBlock = fs.ReadBlock <DataBlock>(currentNode.ValuePos); valueDict.Add(currentNode.ValuePos, valueBlock); } } currentNodePos = currentNode.RightPos; } skipList.Add(line); currentHeadNodePos = skipListNodeDict[currentHeadNodePos].DownPos; } }
private static void PrintSkipLists(FileDBContext db, StringBuilder builder, FileStream fs) { TableBlock tableHead = db.GetTableBlockHeadNode();// fs.ReadBlock<TableBlock>(fs.Position); TableBlock currentTableBlock = tableHead; while (currentTableBlock.NextPos != 0)// 依次Print各个表 { TableBlock tableBlock = fs.ReadBlock <TableBlock>(currentTableBlock.NextPos); builder.Append("Table:"); builder.AppendLine(tableBlock.TableType.ToString()); IndexBlock indexBlockHead = fs.ReadBlock <IndexBlock>(tableBlock.IndexBlockHeadPos); IndexBlock currentIndexBlock = indexBlockHead; IndexBlock indexBlock = fs.ReadBlock <IndexBlock>(currentIndexBlock.NextPos); SkipListNodeBlock currentHeadNode = fs.ReadBlock <SkipListNodeBlock>(indexBlock.SkipListHeadNodePos); int level = db.GetDBHeaderBlock().MaxLevelOfSkipList - 1; SkipListNodeBlock current = currentHeadNode; while (current != null)// 依次Print表的PK Index { StringBuilder levelBuilder = new StringBuilder(); levelBuilder.AppendLine(string.Format("level {0}", level--)); string str = Print(current); levelBuilder.AppendLine(str); int count = 1; while (current.RightPos != 0)//依次Print PK Index的Level { current = fs.ReadBlock <SkipListNodeBlock>(current.RightPos); str = Print(current); levelBuilder.AppendLine(str); count++; } if (count > 2) { builder.AppendLine(levelBuilder.ToString()); } if (currentHeadNode.DownPos != 0) { currentHeadNode = fs.ReadBlock <SkipListNodeBlock>(currentHeadNode.DownPos); } else { currentHeadNode = null; } current = currentHeadNode; } currentTableBlock = tableBlock; } }
/// <summary> /// 标记要删除的skip list node块。 /// </summary> /// <param name="currentIndex"></param> /// <param name="fs"></param> /// <param name="ts"></param> private void DeleteSkipListNodes(IndexBlock currentIndex, FileStream fs, Transaction ts) { foreach (SkipListNodeBlock levelHead in currentIndex.SkipListHeadNodes) { SkipListNodeBlock current = levelHead; while (current.ThisPos != currentIndex.SkipListTailNodePos) { ts.Delete(levelHead); current.TryLoadProperties(fs, SkipListNodeBlockLoadOptions.RightObj); current = levelHead.RightObj; } } ts.Delete(currentIndex.SkipListTailNode); }
/// <summary> /// 标记要删除的数据块。 /// </summary> /// <param name="currentIndex"></param> /// <param name="fs"></param> /// <param name="ts"></param> private void DeleteDataBlocks(IndexBlock currentIndex, FileStream fs, Transaction ts) { SkipListNodeBlock current = currentIndex.SkipListHeadNodes[0]; while (current.RightPos != currentIndex.SkipListTailNodePos) { current.TryLoadProperties(fs, SkipListNodeBlockLoadOptions.RightObj); current.RightObj.TryLoadProperties(fs, SkipListNodeBlockLoadOptions.Key | SkipListNodeBlockLoadOptions.Value); ts.Delete(current.RightObj.Key); foreach (var item in current.RightObj.Value) { ts.Delete(item); } current = current.RightObj; } }
/// <summary> /// 查找具有指定的key值的结点列的最下方的结点。 /// </summary> /// <param name="fileStream"></param> /// <param name="key"></param> /// <param name="indexBlock"></param> /// <returns></returns> //private SkipListNodeBlock FindSkipListNode(FileStream fileStream, IComparable key, IndexBlock indexBlock) private SkipListNodeBlock FindSkipListNode(FileStream fileStream, IndexBlock indexBlock, IComparable key) { // Start at the top list header node SkipListNodeBlock currentNode = indexBlock.SkipListHeadNodes[indexBlock.CurrentLevel]; IComparable rightKey = null; while (true) { rightKey = GetRightObjKey(fileStream, indexBlock, currentNode); while ((currentNode.RightObj != indexBlock.SkipListTailNode) && (rightKey.CompareTo(key) < 0)) { currentNode = currentNode.RightObj; rightKey = GetRightObjKey(fileStream, indexBlock, currentNode); } // Check if there is a next level, and if there is move down. if (currentNode.DownPos == 0) { break; } else { currentNode.TryLoadProperties(fileStream, SkipListNodeBlockLoadOptions.DownObj); currentNode = currentNode.DownObj; } } // Do one final comparison to see if the key to the right equals this key. // If it doesn't match, it would be bigger than this key. if (rightKey.CompareTo(key) == 0) { return(currentNode.RightObj); } else { return(null); } }
private SkipListNodeBlock[] GetHeadNodesOfSkipListNodeBlock(FileStream fileStream, IndexBlock indexBlock) { SkipListNodeBlock[] headNodes = new SkipListNodeBlock[this.headerBlock.MaxLevelOfSkipList]; long currentSkipListNodeBlockPos = indexBlock.SkipListHeadNodePos; for (int i = headNodes.Length - 1; i >= 0; i--) { if (currentSkipListNodeBlockPos == 0) { throw new Exception(string.Format("max level [{0}] != real max level [{1}]", headNodes.Length, headNodes.Length - 1 - i)); } SkipListNodeBlock skipListNodeBlock = fileStream.ReadBlock <SkipListNodeBlock>(currentSkipListNodeBlockPos); headNodes[i] = skipListNodeBlock; if (i != headNodes.Length - 1) { headNodes[i + 1].DownObj = headNodes[i]; } currentSkipListNodeBlockPos = skipListNodeBlock.DownPos; } return(headNodes); }
public static void TryLoadProperties(this SkipListNodeBlock node, FileStream fileStream, SkipListNodeBlockLoadOptions options = SkipListNodeBlockLoadOptions.RightObj | SkipListNodeBlockLoadOptions.DownObj | SkipListNodeBlockLoadOptions.Key | SkipListNodeBlockLoadOptions.Value)// where T : SkipListNodeBlock//, ISkipListNode<T> { if (node.RightPos != 0 && node.RightObj == null && (options & SkipListNodeBlockLoadOptions.RightObj) == SkipListNodeBlockLoadOptions.RightObj) { node.RightObj = fileStream.ReadBlock <SkipListNodeBlock>(node.RightPos); } if (node.DownPos != 0 && node.DownObj == null && (options & SkipListNodeBlockLoadOptions.DownObj) == SkipListNodeBlockLoadOptions.DownObj) { node.DownObj = fileStream.ReadBlock <SkipListNodeBlock>(node.DownPos); } if (node.KeyPos != 0 && node.Key == null && (options & SkipListNodeBlockLoadOptions.Key) == SkipListNodeBlockLoadOptions.Key) { node.Key = fileStream.ReadBlock <DataBlock>(node.KeyPos); } if (node.ValuePos != 0 && node.Value == null && (options & SkipListNodeBlockLoadOptions.Value) == SkipListNodeBlockLoadOptions.Value) { node.Value = fileStream.ReadBlocks <DataBlock>(node.ValuePos); } }
/// <summary> /// 查找数据库内所有指定类型的记录。 /// </summary> /// <typeparam name="T">要查找的类型。</typeparam> /// <returns></returns> public IEnumerable <T> FindAll <T>() where T : Table, new() { Type type = typeof(T); if (this.tableBlockDict.ContainsKey(type)) { TableBlock tableBlock = this.tableBlockDict[type]; IndexBlock firstIndex = tableBlock.IndexBlockHead.NextObj;// 第一个索引应该是Table.Id的索引。 FileStream fs = this.fileStream; SkipListNodeBlock current = firstIndex.SkipListHeadNodes[0]; //currentHeadNode; while (current.RightPos != firstIndex.SkipListTailNodePos) { current.TryLoadProperties(fs, SkipListNodeBlockLoadOptions.RightObj); current.RightObj.TryLoadProperties(fs, SkipListNodeBlockLoadOptions.RightObj | SkipListNodeBlockLoadOptions.Value); T item = current.RightObj.Value.GetObject <T>(this); yield return(item); current = current.RightObj; } } }
/// <summary> /// 获取数据库的所有表和表里的所有数据对象。 /// </summary> /// <param name="db"></param> /// <returns></returns> public static SharpFileDBInfo GetDBInfo(this FileDBContext db) { SharpFileDBInfo info = new SharpFileDBInfo(); FileStream fs = db.GetFileStream(); //fs.ReadBlock<PageHeaderBlock>(0); //fs.ReadBlock<DBHeaderBlock>(fs.Position); //TableBlock tableHead = fs.ReadBlock<TableBlock>(fs.Position); TableBlock currentTableBlock = db.GetTableBlockHeadNode();// tableHead; while (currentTableBlock.NextPos != 0) { TableBlock tableBlock = fs.ReadBlock <TableBlock>(currentTableBlock.NextPos); TableInfo tableInfo = new TableInfo(tableBlock); info.Add(tableInfo); IndexBlock indexBlockHead = fs.ReadBlock <IndexBlock>(tableBlock.IndexBlockHeadPos); IndexBlock currentIndexBlock = indexBlockHead; bool primaryKey = true; while (currentIndexBlock.NextPos != 0) { IndexBlock indexBlock = fs.ReadBlock <IndexBlock>(currentIndexBlock.NextPos); tableInfo.Add(indexBlock); if (primaryKey) { long currentHeadNodePos = indexBlock.SkipListHeadNodePos; SkipListNodeBlock currentHeadNode = fs.ReadBlock <SkipListNodeBlock>(currentHeadNodePos); currentHeadNode.TryLoadProperties(fs, SkipListNodeBlockLoadOptions.DownObj); while (currentHeadNode.DownObj != null) { currentHeadNode.DownObj.TryLoadProperties(fs, SkipListNodeBlockLoadOptions.DownObj); currentHeadNode = currentHeadNode.DownObj; } SkipListNodeBlock current = currentHeadNode; current.TryLoadProperties(fs, SkipListNodeBlockLoadOptions.RightObj); while (current.RightObj != null && current.RightObj.ThisPos != indexBlock.SkipListTailNodePos) { current.RightObj.TryLoadProperties(fs, SkipListNodeBlockLoadOptions.Value); Table item = current.RightObj.Value.GetObject <Table>(db); tableInfo.Add(item); current = current.RightObj; current.TryLoadProperties(fs, SkipListNodeBlockLoadOptions.RightObj); } //while (current.RightObj.RightPos != 0) //{ // current.RightObj.TryLoadProperties(fs, SkipListNodeBlockLoadOptions.Value); // Table item = current.RightObj.Value.GetObject<Table>(db); // tableInfo.Add(item); // current = current.RightObj; //} primaryKey = false; } currentIndexBlock = indexBlock; } currentTableBlock = tableBlock; } return(info); }
static string Print(SkipListNodeBlock skipListNodeBlock) { return(string.Format("Pos: {0}, K: {1}, V: {2}, Down: {3}, Right: {4}", skipListNodeBlock.ThisPos, skipListNodeBlock.KeyPos, skipListNodeBlock.ValuePos, skipListNodeBlock.DownPos, skipListNodeBlock.RightPos)); }
/// <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); } }
private static void SaveToImage(TableBlock table, IndexBlock index, List <List <SkipListNodeBlock> > skipList, Dictionary <long, DataBlock> keyDict, Dictionary <long, DataBlock> valueDict, Dictionary <long, SkipListNodeBlock> skipListNodeDict, string dir, string prefix, FileDBContext db) { const int leftMargin = 25; const int topMargin = 13; const int nodeWidth = 200; const int nodeHeight = 30; const int arrowLength = 30; const int keyValueHeight = 20; //const int keyValueInterval = 5; const int bottomLargin = 30; int width = skipList[skipList.Count - 1].Count * (nodeWidth + arrowLength) + leftMargin; int height = skipList.Count * (nodeHeight + arrowLength) + keyDict.Count * keyValueHeight * 2 + topMargin + bottomLargin; Bitmap bmp = new Bitmap(width, height); Graphics graphics = Graphics.FromImage(bmp); int maxLevel = db.GetDBHeaderBlock().MaxLevelOfSkipList; if (maxLevel != skipList.Count) { throw new Exception(); } // 画 skip list node. List <SkipListNodeBlock> lastLine = skipList[skipList.Count - 1]; for (int i = 0; i < skipList.Count; i++) { List <SkipListNodeBlock> line = skipList[i]; graphics.DrawString(string.Format("{0}:", skipList.Count - i - 1), font, brush, 2, (i) * (nodeHeight + arrowLength) + topMargin); for (int j = 0; j < line.Count; j++) { int widthStep = 0; if (j + 1 == line.Count) { widthStep = lastLine.Count - 1; } else { while (lastLine[widthStep].KeyPos != line[j].KeyPos) { widthStep++; } } SkipListNodeBlock node = line[j]; graphics.DrawString(string.Format("[@[{0}]: {1}, {2}]", node.ThisPos, node.KeyPos, node.ValuePos), font, brush, leftMargin + widthStep * (nodeWidth + arrowLength), i * (nodeHeight + arrowLength) + topMargin); } } // 画RightPos箭头。 for (int i = 0; i < skipList.Count; i++) { List <SkipListNodeBlock> line = skipList[i]; for (int j = 0; j < line.Count - 1; j++) { int leftWidthStep = 0, rightWidthStep = 0; while (lastLine[leftWidthStep].KeyPos != line[j].KeyPos) { leftWidthStep++; } if (j + 1 + 1 == line.Count) { rightWidthStep = lastLine.Count - 1; } else { while (lastLine[rightWidthStep].KeyPos != line[j + 1].KeyPos) { rightWidthStep++; } } graphics.DrawLine(rightPosPen, leftMargin + leftWidthStep * (nodeWidth + arrowLength) + nodeWidth / 2, topMargin + i * (nodeHeight + arrowLength), leftMargin + rightWidthStep * (nodeWidth + arrowLength), topMargin + i * (nodeHeight + arrowLength) ); graphics.DrawLine(rightPosPen, leftMargin + rightWidthStep * (nodeWidth + arrowLength) - 5, topMargin + i * (nodeHeight + arrowLength) - 5, leftMargin + rightWidthStep * (nodeWidth + arrowLength), topMargin + i * (nodeHeight + arrowLength)); graphics.DrawLine(rightPosPen, leftMargin + rightWidthStep * (nodeWidth + arrowLength) - 5, topMargin + i * (nodeHeight + arrowLength) + 5, leftMargin + rightWidthStep * (nodeWidth + arrowLength), topMargin + i * (nodeHeight + arrowLength)); } } // 画DownPos箭头。 for (int i = 0; i < skipList.Count; i++) { List <SkipListNodeBlock> line = skipList[i]; for (int j = 0; j < line.Count; j++) { SkipListNodeBlock node = line[j]; if (node.DownPos != 0) { SkipListNodeBlock downNode = skipListNodeDict[node.DownPos]; int topWidthStep = 0, topHeightStep = 0, downWidthStep = 0, downHeightStep = 0; while (lastLine[topWidthStep].KeyPos != node.KeyPos) { topWidthStep++; } topHeightStep = i; while (lastLine[downWidthStep].KeyPos != downNode.KeyPos) { downWidthStep++; } for (int k = 0; k < skipList.Count; k++) { if (skipList[k].Contains(downNode)) { downHeightStep = k; break; } } graphics.DrawLine(downPosPen, leftMargin + topWidthStep * (nodeWidth + arrowLength) + nodeWidth / 2, topMargin + topHeightStep * (nodeHeight + arrowLength) + nodeHeight / 2, leftMargin + downWidthStep * (nodeWidth + arrowLength) + nodeWidth / 2, topMargin + downHeightStep * (nodeHeight + arrowLength) - 2 ); graphics.DrawLine(downPosPen, leftMargin + downWidthStep * (nodeWidth + arrowLength) + nodeWidth / 2 + 5, topMargin + downHeightStep * (nodeHeight + arrowLength) - 2 - 5, leftMargin + downWidthStep * (nodeWidth + arrowLength) + nodeWidth / 2, topMargin + downHeightStep * (nodeHeight + arrowLength) - 2 ); graphics.DrawLine(downPosPen, leftMargin + downWidthStep * (nodeWidth + arrowLength) + nodeWidth / 2 - 5, topMargin + downHeightStep * (nodeHeight + arrowLength) - 2 - 5, leftMargin + downWidthStep * (nodeWidth + arrowLength) + nodeWidth / 2, topMargin + downHeightStep * (nodeHeight + arrowLength) - 2 ); } } } // 画Key和Value。 for (int i = 0; i < lastLine.Count; i++) { SkipListNodeBlock node = lastLine[i]; if ((node.KeyPos == 0 && node.ValuePos != 0) || (node.KeyPos != 0 && node.ValuePos == 0)) { throw new Exception(); } if (node.KeyPos != 0) { DataBlock keyDataBlock = keyDict[node.KeyPos]; IComparable key = keyDataBlock.GetObject <IComparable>(db.GetFileStream()); graphics.DrawString(string.Format("Key: @[{0}]: {{{1}}}", node.KeyPos, key), font, brush, leftMargin, (skipList.Count - 1) * (nodeHeight + arrowLength) + topMargin + (keyValueHeight) * i * 2); DataBlock valueDataBlock = valueDict[node.ValuePos]; Table value = valueDataBlock.GetObject <Table>(db.GetFileStream()); graphics.DrawString(string.Format("Value: @[{0}]: {{{1}}}", node.ValuePos, value), font, brush, leftMargin, (skipList.Count - 1) * (nodeHeight + arrowLength) + topMargin + (keyValueHeight) * (i * 2 + 1)); } } // 画边框。 graphics.DrawRectangle(boundPen, 0, 0, width - 1, height - 1); string fullname = Path.Combine(dir, prefix + table.TableType.FullName + "-" + index.BindMember + ".bmp"); bmp.Save(fullname); graphics.Dispose(); bmp.Dispose(); }
/// <summary> /// 更新数据库内的一条记录。 /// </summary> /// <param name="record"></param> public bool Update(Table record) { if (record.Id == null) { throw new Exception(string.Format("[{0}] is a new record! Use Insert(Table) to create a new record in SharpFileDB.", record)); } Type type = record.GetType(); if (!this.tableBlockDict.ContainsKey(type))// 添加表和索引数据。 { throw new Exception(string.Format("DBError: No Table for type [{0}] is set!", type)); } Transaction ts = this.transaction; ts.Begin(); try { // 更新record。 IndexBlock indexBlock = this.tableIndexBlockDict[type][Consts.TableIdString]; SkipListNodeBlock downNode = FindSkipListNode(fileStream, indexBlock, record.Id); downNode.TryLoadProperties(fileStream, SkipListNodeBlockLoadOptions.Value); DataBlock[] oldValue = downNode.Value; if (downNode == null)// 此记录根本不存在或已经被删除了。 { throw new Exception(string.Format("no data blocks for [{0}]", record)); } DataBlock[] dataBlocksForValue = record.ToDataBlocks(); foreach (KeyValuePair <string, IndexBlock> item in this.tableIndexBlockDict[type]) { item.Value.Update(record, dataBlocksForValue, this); } // 删除旧的record.ToDataBlocks()数据。 for (int i = 0; i < oldValue.Length; i++) { this.transaction.Delete(oldValue[i]); } // 加入事务,准备写入数据库。 //this.transaction.Delete(downNode.Key);// 加入事务,准备写入数据库。 // 写入新的record.ToDataBlocks()数据。 for (int i = 0; i < dataBlocksForValue.Length; i++) { this.transaction.Add(dataBlocksForValue[i]); } // 加入事务,准备写入数据库。 ts.Commit(); return(true); } catch (Exception ex) { ts.Rollback(); throw ex; } }
public static void Insert(this IndexBlock indexBlock, Table item, DataBlock[] dataBlocksForValue, FileDBContext db) { Type type = item.GetType(); PropertyInfo property = type.GetProperty(indexBlock.BindMember); TableIndexAttribute attr = property.GetCustomAttribute <TableIndexAttribute>(); if (attr == null) { throw new Exception(string.Format("No TableIndexAttribute binded!")); } // 准备Key。 IComparable key = property.GetValue(item) as IComparable; byte[] keyBytes = key.ToBytes(); if (keyBytes.Length > Consts.maxDataBytes) { throw new Exception(string.Format("Toooo long is the key [{0}]", key)); } DataBlock dataBlockForKey = new DataBlock() { ObjectLength = keyBytes.Length, Data = keyBytes, }; SkipListNodeBlock[] rightNodes = FindRightMostNodes(key, indexBlock, db); // Check if the item allready exists in the list. If it does, throw an exception - // we will not allow duplicate items here. FileStream fs = db.fileStream; int maxLevel = db.headerBlock.MaxLevelOfSkipList; IComparable rightKey = db.GetRightObjKey(fs, indexBlock, rightNodes[0]); if ((rightNodes[0].RightObj != indexBlock.SkipListTailNode) && (rightKey.CompareTo(key) == 0)) // key相等,说明Value相同。此处不再使用NGenerics的Comparer<TKey>.Default这种可指定外部比较工具的模式,是因为那会由于忘记编写合适的比较工具而带来隐藏地很深的bug。 { throw new Exception("Item Already In List"); } else { int newLevel = PickRandomLevel(db, indexBlock); if (newLevel > indexBlock.CurrentLevel) { for (int i = indexBlock.CurrentLevel + 1; i <= newLevel; i++) { rightNodes[i] = indexBlock.SkipListHeadNodes[i]; } indexBlock.CurrentLevel = newLevel; } List <SkipListNodeBlock> nodeList = new List <SkipListNodeBlock>(); SkipListNodeBlock newNode = new SkipListNodeBlock() { Key = dataBlockForKey, Value = dataBlocksForValue, }; nodeList.Add(newNode); // Insert the item in the first level newNode.RightObj = rightNodes[0].RightObj; rightNodes[0].RightObj = newNode; // And now insert the node in the rest of the levels, making sure // to update the the links SkipListNodeBlock previousNode = null; for (int i = 1; i <= indexBlock.CurrentLevel; i++) { previousNode = newNode; newNode = new SkipListNodeBlock() { Key = dataBlockForKey, Value = dataBlocksForValue, }; nodeList.Add(newNode); newNode.RightObj = rightNodes[i].RightObj; rightNodes[i].RightObj = newNode; newNode.DownObj = previousNode; } for (int i = nodeList.Count - 1; i >= 0; i--) { db.transaction.Add(rightNodes[i]); } // 加入事务,准备写入数据库。 for (int i = nodeList.Count - 1; i >= 0; i--) { db.transaction.Add(nodeList[i]); } // 加入事务,准备写入数据库。 db.transaction.Add(dataBlockForKey); // 加入事务,准备写入数据库。 } //itemsCount++;// 有的在内存,有的在文件,因此itemsCount不好使了。 }
internal IComparable GetRightObjKey(FileStream fileStream, IndexBlock indexBlock, SkipListNodeBlock currentNode) { IComparable rightKey = null; if (currentNode.RightPos == indexBlock.SkipListTailNodePos) { currentNode.RightObj = indexBlock.SkipListTailNode; } else { currentNode.TryLoadProperties(fileStream, SkipListNodeBlockLoadOptions.RightObj); currentNode.RightObj.TryLoadProperties(fileStream, SkipListNodeBlockLoadOptions.Key); rightKey = currentNode.RightObj.Key.GetObject <IComparable>(fileStream); } return(rightKey); }