/ThirdParty/Src/Lumisoft.Net/Data/_DataPage.cs

https://github.com/ischyrus/inbox2_desktop · C# · 362 lines · 172 code · 51 blank · 139 comment · 19 complexity · 1bac947e2ce9637147e56988e848b20f MD5 · raw file

  1. using System;
  2. using System.IO;
  3. namespace LumiSoft.Data.lsDB
  4. {
  5. /// <summary>
  6. /// Data page.
  7. /// </summary>
  8. internal class DataPage
  9. {
  10. private DbFile m_pOwnerDB = null;
  11. private long m_StartPointer = 0;
  12. private bool m_Used = false;
  13. private long m_OwnerID = 0;
  14. private long m_OwnerDataPagePointer = 0;
  15. private long m_NextDataPagePointer = 0;
  16. private int m_DataAreaSize = 1000;
  17. private int m_StoredDataLength = 0;
  18. private byte[] m_Data = null;
  19. /// <summary>
  20. /// Default constructor.
  21. /// </summary>
  22. /// <param name="dataPageDataAreaSize">Specifies how much data data page can store.</param>
  23. /// <param name="ownerDB">Owner DB file..</param>
  24. /// <param name="startOffset">Data page start offset pointer.</param>
  25. public DataPage(int dataPageDataAreaSize,DbFile ownerDB,long startOffset)
  26. {
  27. /* DataPage structure
  28. 2 bytes - CRLF
  29. 1 byte - used (f - unused,u - used)
  30. 8 byte - owner object id
  31. 8 bytes - owner data page pointer
  32. 8 bytes - continuing data page pointer
  33. 4 bytes - stored data length in data area
  34. 2 bytes - CRLF
  35. 1000 bytes - data area
  36. */
  37. m_DataAreaSize = dataPageDataAreaSize;
  38. m_pOwnerDB = ownerDB;
  39. m_StartPointer = startOffset;
  40. byte[] dataPageInfo = new byte[33];
  41. ownerDB.SetFilePosition(startOffset);
  42. ownerDB.ReadFromFile(dataPageInfo,0,dataPageInfo.Length);
  43. m_Data = new byte[dataPageDataAreaSize];
  44. ownerDB.ReadFromFile(m_Data,0,dataPageDataAreaSize);
  45. // CRLF
  46. if(dataPageInfo[0] != (byte)'\r'){
  47. throw new Exception("Not right data page startOffset, or invalid data page <CR> is expected but is '" + (int)dataPageInfo[0] + "' !");
  48. }
  49. if(dataPageInfo[1] != (byte)'\n'){
  50. throw new Exception("Not right data page startOffset, or invalid data page <LF> is expected but is '" + (int)dataPageInfo[1] + "' !");
  51. }
  52. // used
  53. if(dataPageInfo[2] == (byte)'u'){
  54. m_Used = true;
  55. }
  56. else{
  57. m_Used = false;
  58. }
  59. // owner object id
  60. m_OwnerID = ldb_Utils.ByteToLong(dataPageInfo,3);
  61. // owner data page pointer
  62. m_OwnerDataPagePointer = ldb_Utils.ByteToLong(dataPageInfo,11);
  63. // continuing data page pointer
  64. m_NextDataPagePointer = ldb_Utils.ByteToLong(dataPageInfo,19);
  65. // stored data length in data area
  66. m_StoredDataLength = ldb_Utils.ByteToInt(dataPageInfo,27);
  67. // CRLF
  68. if(dataPageInfo[31] != (byte)'\r'){
  69. throw new Exception("Not right data page startOffset, or invalid data page <CR> is expected but is '" + (int)dataPageInfo[31] + "' !");
  70. }
  71. if(dataPageInfo[32] != (byte)'\n'){
  72. throw new Exception("Not right data page startOffset, or invalid data page <LF> is expected but is '" + (int)dataPageInfo[32] + "' !");
  73. }
  74. }
  75. #region static method CreateDataPage
  76. /// <summary>
  77. /// Creates new data page structure.
  78. /// </summary>
  79. /// <param name="dataPageDataAreaSize">Specifies how much data can data page store.</param>
  80. /// <param name="used">Specifies if data page is used or free space. If this value is false, all toher parameters aren't stored.</param>
  81. /// <param name="ownerID">Owner data object ID.</param>
  82. /// <param name="ownerDataPagePointer">This data page owner data page pointer. This value can be 0, if no owner.</param>
  83. /// <param name="nextDataPagePointer">Data page pointer, what continues this data page. This value can be 0 if, data page won't spread to multiple data pages.</param>
  84. /// <param name="data">Data what data page stores. Maximum length is dataPageDataAreaSize.</param>
  85. /// <returns></returns>
  86. public static byte[] CreateDataPage(int dataPageDataAreaSize,bool used,long ownerID,long ownerDataPagePointer,long nextDataPagePointer,byte[] data)
  87. {
  88. /* DataPage structure
  89. 2 bytes - CRLF
  90. 1 byte - used (f - unused,u - used)
  91. 8 byte - owner object id
  92. 8 bytes - owner data page pointer
  93. 8 bytes - continuing data page pointer
  94. 4 bytes - stored data length in data area
  95. 2 bytes - CRLF
  96. dataPageDataAreaSize bytes - data area
  97. */
  98. if(data.Length > dataPageDataAreaSize){
  99. throw new Exception("Data page can store only " + dataPageDataAreaSize + " bytes, data conatins '" + data.Length + "' bytes !");
  100. }
  101. byte[] dataPage = new byte[dataPageDataAreaSize + 33];
  102. // CRLF
  103. dataPage[0] = (byte)'\r';
  104. dataPage[1] = (byte)'\n';
  105. if(used){
  106. // used
  107. dataPage[2] = (byte)'u';
  108. // owner object id
  109. Array.Copy(ldb_Utils.LongToByte(ownerID),0,dataPage,3,8);
  110. // owner data page pointer
  111. Array.Copy(ldb_Utils.LongToByte(ownerDataPagePointer),0,dataPage,11,8);
  112. // continuing data page pointer
  113. Array.Copy(ldb_Utils.LongToByte(nextDataPagePointer),0,dataPage,19,8);
  114. // stored data length in data area
  115. Array.Copy(ldb_Utils.IntToByte(data.Length),0,dataPage,27,4);
  116. // CRLF
  117. dataPage[31] = (byte)'\r';
  118. dataPage[32] = (byte)'\n';
  119. // data area
  120. Array.Copy(data,0,dataPage,33,data.Length);
  121. }
  122. else{
  123. // used
  124. dataPage[2] = (byte)'f';
  125. // CRLF
  126. dataPage[31] = (byte)'\r';
  127. dataPage[32] = (byte)'\n';
  128. }
  129. return dataPage;
  130. }
  131. #endregion
  132. #region method ReadData
  133. /// <summary>
  134. /// Reads specified amount data to buffer.
  135. /// </summary>
  136. /// <param name="buffer">Buffer where to store data.</param>
  137. /// <param name="startIndexInBuffer">Start index in buffer where data storing begins. Start index is included.</param>
  138. /// <param name="length">Number of bytes to read.</param>
  139. /// <param name="startOffset">Zero based offset of data area.</param>
  140. /// <returns></returns>
  141. public void ReadData(byte[] buffer,int startIndexInBuffer,int length,int startOffset)
  142. {
  143. if(startOffset < 0){
  144. throw new Exception("startOffset can't negative value !");
  145. }
  146. if((length + startOffset) > this.DataAreaSize){
  147. throw new Exception("startOffset and length are out of range data page data area !");
  148. }
  149. if((length + startOffset) > m_StoredDataLength){
  150. throw new Exception("There isn't so much data stored in data page as requested ! Stored data length = " + m_StoredDataLength + "; start offset = " + startOffset + "; length wanted = " + length);
  151. }
  152. Array.Copy(m_Data,startOffset,buffer,startIndexInBuffer,length);
  153. }
  154. /// <summary>
  155. /// Reads data page data. Offset byte is included.
  156. /// </summary>
  157. /// <param name="startOffset">Zero based offset of data area.</param>
  158. /// <param name="length">Specifies how much data to read.</param>
  159. /// <returns></returns>
  160. public byte[] ReadData(int startOffset,int length)
  161. {
  162. if(startOffset < 0){
  163. throw new Exception("startOffset can't negative value !");
  164. }
  165. if((length + startOffset) > this.DataAreaSize){
  166. throw new Exception("startOffset and length are out of range data page data area !");
  167. }
  168. if((length + startOffset) > m_StoredDataLength){
  169. throw new Exception("There isn't so much data stored in data page as requested ! Stored data length = " + m_StoredDataLength + "; start offset = " + startOffset + "; length wanted = " + length);
  170. }
  171. byte[] data = new byte[length];
  172. Array.Copy(m_Data,startOffset,data,0,length);
  173. return data;
  174. }
  175. #endregion
  176. #region method WriteData
  177. /// <summary>
  178. /// Writed data to data page.
  179. /// </summary>
  180. /// <param name="data">Data to write.</param>
  181. public void WriteData(byte[] data)
  182. {
  183. if(data.Length > this.DataAreaSize){
  184. throw new Exception("Data page can't store more than " + this.DataAreaSize + " bytes, use mutliple data pages !");
  185. }
  186. // Set stored data length
  187. m_pOwnerDB.SetFilePosition(m_StartPointer + 27);
  188. m_pOwnerDB.WriteToFile(ldb_Utils.IntToByte(data.Length),0,4);
  189. // Store data
  190. m_pOwnerDB.SetFilePosition(m_StartPointer + 33);
  191. m_pOwnerDB.WriteToFile(data,0,data.Length);
  192. m_StoredDataLength = data.Length;
  193. }
  194. #endregion
  195. #region Properties Implementation
  196. /// <summary>
  197. /// Gets data page size on disk in bytes.
  198. /// </summary>
  199. public int DataPageSize
  200. {
  201. get{ return 33 + this.DataAreaSize; }
  202. }
  203. /// <summary>
  204. /// Gets this data page address (offset in database file).
  205. /// </summary>
  206. public long Pointer
  207. {
  208. get{ return m_StartPointer; }
  209. }
  210. /// <summary>
  211. /// Gets or sets if data page used or free space.
  212. /// </summary>
  213. public bool Used
  214. {
  215. get{ return m_Used; }
  216. set{
  217. m_pOwnerDB.SetFilePosition(m_StartPointer + 2);
  218. m_pOwnerDB.WriteToFile(new byte[]{Convert.ToByte(value)},0,1);
  219. }
  220. }
  221. /// <summary>
  222. /// Gets owner object id what owns this data page.
  223. /// </summary>
  224. public long OwnerID
  225. {
  226. get{ return m_OwnerID; }
  227. }
  228. /// <summary>
  229. /// Gets or sets owner data page pointer.
  230. /// Returns 0 if this is first data page of multiple data pages or only data page.
  231. /// </summary>
  232. public long OwnerDataPagePointer
  233. {
  234. get{ return m_OwnerDataPagePointer; }
  235. set{
  236. // owner data page pointer
  237. m_pOwnerDB.SetFilePosition(m_StartPointer + 11);
  238. m_pOwnerDB.WriteToFile(ldb_Utils.LongToByte(value),0,8);
  239. m_OwnerDataPagePointer = value;
  240. }
  241. }
  242. /// <summary>
  243. /// Gets or sets pointer to data page what continues this data page.
  244. /// Returns 0 if data page has enough room for data and there isn't continuing data page.
  245. /// </summary>
  246. public long NextDataPagePointer
  247. {
  248. get{ return m_NextDataPagePointer; }
  249. set{
  250. // continuing data page pointer
  251. m_pOwnerDB.SetFilePosition(m_StartPointer + 19);
  252. m_pOwnerDB.WriteToFile(ldb_Utils.LongToByte(value),0,8);
  253. m_NextDataPagePointer = value;
  254. }
  255. }
  256. /*
  257. /// <summary>
  258. /// Gets or sets data that data page holds. Maximum size is this.DataAreaSize. Returns null if no data stored.
  259. /// </summary>
  260. public byte[] Data
  261. {
  262. get{
  263. byte[] data = new byte[m_StoredDataLength];
  264. m_pDbFileStream.Position = m_StartPointer + 33;
  265. m_pDbFileStream.Read(data,0,data.Length);
  266. return data;
  267. }
  268. set{
  269. if(value.Length > this.DataAreaSize){
  270. throw new Exception("Data page can't store more than " + this.DataAreaSize + " bytes, use mutliple data pages !");
  271. }
  272. // Set stored data length
  273. m_pDbFileStream.Position = m_StartPointer + 27;
  274. byte[] dataLength = ldb_Utils.IntToByte(value.Length);
  275. m_pDbFileStream.Write(dataLength,0,dataLength.Length);
  276. // Store data
  277. m_pDbFileStream.Position = m_StartPointer + 33;
  278. m_pDbFileStream.Write(value,0,value.Length);
  279. m_StoredDataLength = value.Length;
  280. }
  281. }
  282. */
  283. /// <summary>
  284. /// Gets how many data data page can store.
  285. /// </summary>
  286. public int DataAreaSize
  287. {
  288. get{ return m_DataAreaSize; }
  289. }
  290. /// <summary>
  291. /// Gets stored data length.
  292. /// </summary>
  293. public int StoredDataLength
  294. {
  295. get{ return m_StoredDataLength; }
  296. }
  297. /// <summary>
  298. /// Gets how much free data space is availabe in data page.
  299. /// </summary>
  300. public long SpaceAvailable
  301. {
  302. get{ return this.DataAreaSize - m_StoredDataLength; }
  303. }
  304. #endregion
  305. }
  306. }