PageRenderTime 57ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/RaptorDB/Indexes/IndexFile.cs

#
C# | 400 lines | 323 code | 51 blank | 26 comment | 46 complexity | d451acd9e929b30ee39d8e65649928a8 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.IO;
  5. using System.Collections;
  6. //using RaptorDB.Common;
  7. namespace RaptorDB
  8. {
  9. internal class IndexFile<T>
  10. {
  11. FileStream _file = null;
  12. private byte[] _FileHeader = new byte[] {
  13. (byte)'M', (byte)'G', (byte)'I',
  14. 0, // 3 = [keysize] max 255
  15. 0,0, // 4 = [node size] max 65536
  16. 0,0,0,0, // 6 = [root page num]
  17. 0, // 10 = Index file type : 0=mgindex
  18. 0,0,0,0 // 11 = last record number indexed
  19. };
  20. private byte[] _BlockHeader = new byte[] {
  21. (byte)'P',(byte)'A',(byte)'G',(byte)'E',
  22. 0, // 4 = [Flag] = 0=page 1=page list
  23. 0,0, // 5 = [item count]
  24. 0,0,0,0, // 7 = reserved
  25. 0,0,0,0 // 11 = [right page number] / [next page number]
  26. };
  27. internal byte _maxKeySize;
  28. internal ushort _PageNodeCount = 5000;
  29. private int _LastPageNumber = 1; // 0 = page list
  30. private int _PageLength;
  31. private int _rowSize;
  32. ILog log = LogManager.GetLogger(typeof(IndexFile<T>));
  33. private BitmapIndex _bitmap;
  34. IGetBytes<T> _T = null;
  35. private object _fileLock = new object();
  36. public IndexFile(string filename, byte maxKeySize, ushort pageNodeCount)
  37. {
  38. _T = RDBDataType<T>.ByteHandler();
  39. _maxKeySize = maxKeySize;
  40. _PageNodeCount = pageNodeCount;
  41. _rowSize = (_maxKeySize + 1 + 4 + 4);
  42. string path = Path.GetDirectoryName(filename);
  43. Directory.CreateDirectory(path);
  44. if (File.Exists(filename))
  45. {
  46. // if file exists open and read header
  47. _file = File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
  48. ReadFileHeader();
  49. // compute last page number from file length
  50. _PageLength = (_BlockHeader.Length + _rowSize * (_PageNodeCount));
  51. _LastPageNumber = (int)((_file.Length - _FileHeader.Length) / _PageLength);
  52. }
  53. else
  54. {
  55. // else create new file
  56. _file = File.Open(filename, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
  57. _PageLength = (_BlockHeader.Length + _rowSize * (_PageNodeCount));
  58. CreateFileHeader(0);
  59. _LastPageNumber = (int)((_file.Length - _FileHeader.Length) / _PageLength);
  60. }
  61. if (_LastPageNumber == 0)
  62. _LastPageNumber = 1;
  63. // bitmap duplicates
  64. _bitmap = new BitmapIndex(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename));
  65. }
  66. #region [ C o m m o n ]
  67. public void SetBitmapDuplicate(int bitmaprec, int rec)
  68. {
  69. _bitmap.SetDuplicate(bitmaprec, rec);
  70. }
  71. public int GetBitmapDuplaicateFreeRecordNumber()
  72. {
  73. return _bitmap.GetFreeRecordNumber();
  74. }
  75. public IEnumerable<int> GetDuplicatesRecordNumbers(int recno)
  76. {
  77. return GetDuplicateBitmap(recno).GetBitIndexes();
  78. }
  79. public WAHBitArray GetDuplicateBitmap(int recno)
  80. {
  81. return _bitmap.GetBitmap(recno);
  82. }
  83. private byte[] CreateBlockHeader(byte type, ushort itemcount, int rightpagenumber)
  84. {
  85. byte[] block = new byte[_BlockHeader.Length];
  86. Array.Copy(_BlockHeader, block, block.Length);
  87. block[4] = type;
  88. byte[] b = Helper.GetBytes(itemcount, false);
  89. Buffer.BlockCopy(b, 0, block, 5, 2);
  90. b = Helper.GetBytes(rightpagenumber, false);
  91. Buffer.BlockCopy(b, 0, block, 11, 4);
  92. return block;
  93. }
  94. private void CreateFileHeader(int rowsindexed)
  95. {
  96. lock (_fileLock)
  97. {
  98. // max key size
  99. byte[] b = Helper.GetBytes(_maxKeySize, false);
  100. Buffer.BlockCopy(b, 0, _FileHeader, 3, 1);
  101. // page node count
  102. b = Helper.GetBytes(_PageNodeCount, false);
  103. Buffer.BlockCopy(b, 0, _FileHeader, 4, 2);
  104. b = Helper.GetBytes(rowsindexed, false);
  105. Buffer.BlockCopy(b, 0, _FileHeader, 11, 4);
  106. _file.Seek(0L, SeekOrigin.Begin);
  107. _file.Write(_FileHeader, 0, _FileHeader.Length);
  108. if (rowsindexed == 0)
  109. {
  110. byte[] pagezero = new byte[_PageLength];
  111. byte[] block = CreateBlockHeader(1, 0, -1);
  112. Buffer.BlockCopy(block, 0, pagezero, 0, block.Length);
  113. _file.Write(pagezero, 0, _PageLength);
  114. }
  115. _file.Flush();
  116. }
  117. }
  118. private bool ReadFileHeader()
  119. {
  120. _file.Seek(0L, SeekOrigin.Begin);
  121. byte[] b = new byte[_FileHeader.Length];
  122. _file.Read(b, 0, _FileHeader.Length);
  123. if (b[0] == _FileHeader[0] && b[1] == _FileHeader[1] && b[2] == _FileHeader[2])
  124. {
  125. byte maxks = b[3];
  126. ushort nodes = (ushort)Helper.ToInt16(b, 4);
  127. int root = Helper.ToInt32(b, 6);
  128. _maxKeySize = maxks;
  129. _PageNodeCount = nodes;
  130. _FileHeader = b;
  131. }
  132. return false;
  133. }
  134. public int GetNewPageNumber()
  135. {
  136. return _LastPageNumber++;
  137. }
  138. private void SeekPage(int pnum)
  139. {
  140. long offset = _FileHeader.Length;
  141. offset += (long)pnum * _PageLength;
  142. if (offset > _file.Length)
  143. CreateBlankPages(pnum);
  144. _file.Seek(offset, SeekOrigin.Begin);
  145. }
  146. private void CreateBlankPages(int pnum)
  147. {
  148. // create space
  149. byte[] b = new byte[_PageLength];
  150. _file.Seek(0L, SeekOrigin.Current);
  151. for (int i = pnum; i < _LastPageNumber; i++)
  152. _file.Write(b, 0, b.Length);
  153. _file.Flush();
  154. }
  155. public void FreeMemory()
  156. {
  157. _bitmap.FreeMemory();
  158. }
  159. public void Shutdown()
  160. {
  161. log.Debug("Shutdown IndexFile");
  162. if (_file != null)
  163. {
  164. _file.Flush();
  165. _file.Close();
  166. }
  167. _file = null;
  168. _bitmap.Commit(Global.FreeBitmapMemoryOnSave);
  169. _bitmap.Shutdown();
  170. }
  171. #endregion
  172. #region [ P a g e s ]
  173. public void GetPageList(List<int> PageListDiskPages, SafeSortedList<T, PageInfo> PageList, out int lastIndexedRow)
  174. {
  175. lastIndexedRow = Helper.ToInt32(_FileHeader, 11);
  176. // load page list
  177. PageListDiskPages.Add(0); // first page list
  178. int nextpage = LoadPageListData(0, PageList);
  179. while (nextpage != -1)
  180. {
  181. nextpage = LoadPageListData(nextpage, PageList);
  182. if (nextpage != -1)
  183. PageListDiskPages.Add(nextpage);
  184. }
  185. }
  186. private int LoadPageListData(int page, SafeSortedList<T, PageInfo> PageList)
  187. {
  188. lock (_fileLock)
  189. {
  190. // load page list data
  191. int nextpage = -1;
  192. SeekPage(page);
  193. byte[] b = new byte[_PageLength];
  194. _file.Read(b, 0, _PageLength);
  195. if (b[0] == _BlockHeader[0] && b[1] == _BlockHeader[1] && b[2] == _BlockHeader[2] && b[3] == _BlockHeader[3])
  196. {
  197. short count = Helper.ToInt16(b, 5);
  198. if (count > _PageNodeCount)
  199. throw new Exception("Count > node size");
  200. nextpage = Helper.ToInt32(b, 11);
  201. int index = _BlockHeader.Length;
  202. for (int i = 0; i < count; i++)
  203. {
  204. int idx = index + _rowSize * i;
  205. byte ks = b[idx];
  206. T key = _T.GetObject(b, idx + 1, ks);
  207. int pagenum = Helper.ToInt32(b, idx + 1 + _maxKeySize);
  208. // add counts
  209. int unique = Helper.ToInt32(b, idx + 1 + _maxKeySize + 4);
  210. // FEATURE : add dup count
  211. PageList.Add(key, new PageInfo(pagenum, unique, 0));
  212. }
  213. }
  214. else
  215. throw new Exception("Page List header is invalid");
  216. return nextpage;
  217. }
  218. }
  219. internal void SavePage(Page<T> node)
  220. {
  221. lock (_fileLock)
  222. {
  223. int pnum = node.DiskPageNumber;
  224. if (pnum > _LastPageNumber)
  225. throw new Exception("should not be here: page out of bounds");
  226. SeekPage(pnum);
  227. byte[] page = new byte[_PageLength];
  228. byte[] blockheader = CreateBlockHeader(0, (ushort)node.tree.Count, node.RightPageNumber);
  229. Buffer.BlockCopy(blockheader, 0, page, 0, blockheader.Length);
  230. int index = blockheader.Length;
  231. int i = 0;
  232. byte[] b = null;
  233. T[] keys = node.tree.Keys();
  234. Array.Sort(keys); // sort keys on save for read performance
  235. // node children
  236. foreach (var kp in keys)
  237. {
  238. var val = node.tree[kp];
  239. int idx = index + _rowSize * i++;
  240. // key bytes
  241. byte[] kk = _T.GetBytes(kp);
  242. byte size = (byte)kk.Length;
  243. if (size > _maxKeySize)
  244. size = _maxKeySize;
  245. // key size = 1 byte
  246. page[idx] = size;
  247. Buffer.BlockCopy(kk, 0, page, idx + 1, page[idx]);
  248. // offset = 4 bytes
  249. b = Helper.GetBytes(val.RecordNumber, false);
  250. Buffer.BlockCopy(b, 0, page, idx + 1 + _maxKeySize, b.Length);
  251. // duplicatepage = 4 bytes
  252. b = Helper.GetBytes(val.DuplicateBitmapNumber, false);
  253. Buffer.BlockCopy(b, 0, page, idx + 1 + _maxKeySize + 4, b.Length);
  254. }
  255. _file.Write(page, 0, page.Length);
  256. }
  257. }
  258. public Page<T> LoadPageFromPageNumber(int number)
  259. {
  260. lock (_fileLock)
  261. {
  262. SeekPage(number);
  263. byte[] b = new byte[_PageLength];
  264. _file.Read(b, 0, _PageLength);
  265. if (b[0] == _BlockHeader[0] && b[1] == _BlockHeader[1] && b[2] == _BlockHeader[2] && b[3] == _BlockHeader[3])
  266. {
  267. // create node here
  268. Page<T> page = new Page<T>();
  269. short count = Helper.ToInt16(b, 5);
  270. if (count > _PageNodeCount)
  271. throw new Exception("Count > node size");
  272. page.DiskPageNumber = number;
  273. page.RightPageNumber = Helper.ToInt32(b, 11);
  274. int index = _BlockHeader.Length;
  275. for (int i = 0; i < count; i++)
  276. {
  277. int idx = index + _rowSize * i;
  278. byte ks = b[idx];
  279. T key = _T.GetObject(b, idx + 1, ks);
  280. int offset = Helper.ToInt32(b, idx + 1 + _maxKeySize);
  281. int duppage = Helper.ToInt32(b, idx + 1 + _maxKeySize + 4);
  282. page.tree.Add(key, new KeyInfo(offset, duppage));
  283. }
  284. return page;
  285. }
  286. else
  287. throw new Exception("Page read error header invalid, number = " + number);
  288. }
  289. }
  290. #endregion
  291. internal void SavePageList(SafeSortedList<T, PageInfo> _pages, List<int> diskpages)
  292. {
  293. lock (_fileLock)
  294. {
  295. // save page list
  296. int c = (_pages.Count / Global.PageItemCount) + 1;
  297. // allocate pages needed
  298. while (c > diskpages.Count)
  299. diskpages.Add(GetNewPageNumber());
  300. byte[] page = new byte[_PageLength];
  301. for (int i = 0; i < (diskpages.Count - 1); i++)
  302. {
  303. byte[] block = CreateBlockHeader(1, Global.PageItemCount, diskpages[i + 1]);
  304. Buffer.BlockCopy(block, 0, page, 0, block.Length);
  305. for (int j = 0; j < Global.PageItemCount; j++)
  306. CreatePageListData(_pages, i * Global.PageItemCount, block.Length, j, page);
  307. SeekPage(diskpages[i]);
  308. _file.Write(page, 0, page.Length);
  309. }
  310. c = _pages.Count % Global.PageItemCount;
  311. byte[] lastblock = CreateBlockHeader(1, (ushort)c, -1);
  312. Buffer.BlockCopy(lastblock, 0, page, 0, lastblock.Length);
  313. int lastoffset = (_pages.Count / Global.PageItemCount) * Global.PageItemCount;
  314. for (int j = 0; j < c; j++)
  315. CreatePageListData(_pages, lastoffset, lastblock.Length, j, page);
  316. SeekPage(diskpages[diskpages.Count - 1]);
  317. _file.Write(page, 0, page.Length);
  318. }
  319. }
  320. private void CreatePageListData(SafeSortedList<T, PageInfo> _pages, int offset, int index, int counter, byte[] page)
  321. {
  322. int idx = index + _rowSize * counter;
  323. // key bytes
  324. byte[] kk = _T.GetBytes(_pages.GetKey(counter + offset));
  325. byte size = (byte)kk.Length;
  326. if (size > _maxKeySize)
  327. size = _maxKeySize;
  328. // key size = 1 byte
  329. page[idx] = size;
  330. Buffer.BlockCopy(kk, 0, page, idx + 1, page[idx]);
  331. // offset = 4 bytes
  332. byte[] b = Helper.GetBytes(_pages.GetValue(offset + counter).PageNumber, false);
  333. Buffer.BlockCopy(b, 0, page, idx + 1 + _maxKeySize, b.Length);
  334. // add counts
  335. b = Helper.GetBytes(_pages.GetValue(offset + counter).UniqueCount, false);
  336. Buffer.BlockCopy(b, 0, page, idx + 1 + _maxKeySize + 4, b.Length);
  337. // FEATURE : add dup counts
  338. }
  339. internal void SaveLastRecordNumber(int recnum)
  340. {
  341. // save the last record number indexed to the header
  342. CreateFileHeader(recnum);
  343. }
  344. internal void BitmapFlush()
  345. {
  346. _bitmap.Commit(Global.FreeBitmapMemoryOnSave);
  347. }
  348. }
  349. }