PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Alpha/Source/Libraries/GSF.SortedTreeStore/IO/FileStructure/IndexParser.cs

#
C# | 254 lines | 139 code | 30 blank | 85 comment | 38 complexity | aab569c7a142bccfb2080417e5d62605 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, EPL-1.0
  1. //******************************************************************************************************
  2. // IndexParser.cs - Gbtc
  3. //
  4. // Copyright © 2013, Grid Protection Alliance. All Rights Reserved.
  5. //
  6. // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
  7. // the NOTICE file distributed with this work for additional information regarding copyright ownership.
  8. // The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
  9. // not use this file except in compliance with the License. You may obtain a copy of the License at:
  10. //
  11. // http://www.opensource.org/licenses/eclipse-1.0.php
  12. //
  13. // Unless agreed to in writing, the subject software distributed under the License is distributed on an
  14. // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
  15. // License for the specific language governing permissions and limitations.
  16. //
  17. // Code Modification History:
  18. // ----------------------------------------------------------------------------------------------------
  19. // 1/4/2012 - Steven E. Chisholm
  20. // Generated original version of source code.
  21. //
  22. //
  23. //******************************************************************************************************
  24. using GSF.IO.FileStructure.Media;
  25. namespace GSF.IO.FileStructure
  26. {
  27. /// <summary>
  28. /// This class provides passthrough properties for the <see cref="IndexMapper"/> class as well follows the directions
  29. /// of the Index Mapper to find the data cluster that contains the point in question.
  30. /// </summary>
  31. internal unsafe class IndexParser
  32. : IndexMapper
  33. {
  34. #region [ Members ]
  35. /// <summary>
  36. /// The file that is being read by this parser.
  37. /// </summary>
  38. private readonly SubFileMetaData m_subFile;
  39. private readonly SubFileDiskIoSessionPool m_ioSessions;
  40. private int m_blockSize;
  41. #endregion
  42. #region [ Constructors ]
  43. /// <summary>
  44. /// Creates a new instance of this class.
  45. /// </summary>
  46. /// <param name="ioSessions">IoSessions to use to read from this disk</param>
  47. public IndexParser(SubFileDiskIoSessionPool ioSessions)
  48. : base(ioSessions.Header.BlockSize)
  49. {
  50. m_blockSize = ioSessions.Header.BlockSize;
  51. m_subFile = ioSessions.File;
  52. m_ioSessions = ioSessions;
  53. m_oldFirstOffset = -1;
  54. }
  55. #endregion
  56. #region [ Properties ]
  57. /// <summary>
  58. /// The address of the first indirect block
  59. /// </summary>
  60. protected uint FirstIndirectBlockAddress;
  61. /// <summary>
  62. /// The address of the second indirect block
  63. /// </summary>
  64. protected uint SecondIndirectBlockAddress;
  65. /// <summary>
  66. /// The address of the third indirect block
  67. /// </summary>
  68. protected uint ThirdIndirectBlockAddress;
  69. /// <summary>
  70. /// The address of the third indirect block
  71. /// </summary>
  72. protected uint FourthIndirectBlockAddress;
  73. /// <summary>
  74. /// The address of the first block of the data cluster.
  75. /// </summary>
  76. protected uint DataClusterAddress;
  77. /// <summary>
  78. /// The address of the first indirect block
  79. /// </summary>
  80. private int m_oldFirstOffset;
  81. /// <summary>
  82. /// The address of the second indirect block
  83. /// </summary>
  84. private int m_oldSecondOffset;
  85. /// <summary>
  86. /// The address of the third indirect block
  87. /// </summary>
  88. private int m_oldThirdOffset;
  89. /// <summary>
  90. /// The address of the fourth indirect block
  91. /// </summary>
  92. private int m_oldFourthOffset;
  93. #endregion
  94. #region [ Methods ]
  95. /// <summary>
  96. /// This function will also call <see cref="SetPosition"/> so after it returns, the current block data will be updated.
  97. /// </summary>
  98. /// <param name="positionIndex">The virtual index address.</param>
  99. /// <returns>the physical position index for the provided virtual position</returns>
  100. public uint VirtualToPhysical(uint positionIndex)
  101. {
  102. MapPosition(positionIndex);
  103. UpdateBlockInformation();
  104. return DataClusterAddress;
  105. }
  106. /// <summary>
  107. /// Determines if the current sector contains the position passed. If not, it updates the current sector to the one that contains the passed position.
  108. /// </summary>
  109. /// <param name="positionIndex">The position to navigate to indexed to the block data block size.</param>
  110. public void SetPositionAndLookup(uint positionIndex)
  111. {
  112. MapPosition(positionIndex);
  113. UpdateBlockInformation();
  114. }
  115. public void ClearIndexCache(IndexParser mostRecentParser)
  116. {
  117. FirstIndirectBlockAddress = mostRecentParser.FirstIndirectBlockAddress;
  118. SecondIndirectBlockAddress = mostRecentParser.SecondIndirectBlockAddress;
  119. ThirdIndirectBlockAddress = mostRecentParser.ThirdIndirectBlockAddress;
  120. FourthIndirectBlockAddress = mostRecentParser.FourthIndirectBlockAddress;
  121. DataClusterAddress = mostRecentParser.DataClusterAddress;
  122. MapPosition(mostRecentParser.BaseVirtualAddressIndexValue);
  123. m_oldFirstOffset = -1;
  124. }
  125. /// <summary>
  126. /// Looks up the physical/virtual block positions for the address given.
  127. /// </summary>
  128. /// <returns></returns>
  129. private void UpdateBlockInformation()
  130. {
  131. int lowestChange;
  132. if (m_oldFirstOffset != FirstIndirectOffset)
  133. lowestChange = 1;
  134. else if (m_oldSecondOffset != SecondIndirectOffset)
  135. lowestChange = 2;
  136. else if (m_oldThirdOffset != ThirdIndirectOffset)
  137. lowestChange = 3;
  138. else if (m_oldFourthOffset != FourthIndirectOffset)
  139. lowestChange = 4;
  140. else
  141. {
  142. lowestChange = 5;
  143. //DataClusterAddress = m_subFile.DirectBlock;
  144. return;
  145. }
  146. m_oldFirstOffset = FirstIndirectOffset;
  147. m_oldSecondOffset = SecondIndirectOffset;
  148. m_oldThirdOffset = ThirdIndirectOffset;
  149. m_oldFourthOffset = FourthIndirectOffset;
  150. if (FirstIndirectOffset != 0) //Quadruple Indirect
  151. {
  152. FirstIndirectBlockAddress = m_subFile.QuadrupleIndirectBlock;
  153. if (lowestChange <= 1)
  154. SecondIndirectBlockAddress = GetBlockIndexValue(FirstIndirectBlockAddress, FirstIndirectOffset, BlockType.IndexIndirect1, FirstIndirectBaseIndex);
  155. if (lowestChange <= 2)
  156. ThirdIndirectBlockAddress = GetBlockIndexValue(SecondIndirectBlockAddress, SecondIndirectOffset, BlockType.IndexIndirect2, SecondIndirectBaseIndex);
  157. if (lowestChange <= 3)
  158. FourthIndirectBlockAddress = GetBlockIndexValue(ThirdIndirectBlockAddress, ThirdIndirectOffset, BlockType.IndexIndirect3, ThirdIndirectBaseIndex);
  159. if (lowestChange <= 4)
  160. DataClusterAddress = GetBlockIndexValue(FourthIndirectBlockAddress, FourthIndirectOffset, BlockType.IndexIndirect4, FourthIndirectBaseIndex);
  161. }
  162. else if (SecondIndirectOffset != 0) //Triple Indirect
  163. {
  164. FirstIndirectBlockAddress = 0;
  165. SecondIndirectBlockAddress = m_subFile.TripleIndirectBlock;
  166. if (lowestChange <= 2)
  167. ThirdIndirectBlockAddress = GetBlockIndexValue(SecondIndirectBlockAddress, SecondIndirectOffset, BlockType.IndexIndirect2, SecondIndirectBaseIndex);
  168. if (lowestChange <= 3)
  169. FourthIndirectBlockAddress = GetBlockIndexValue(ThirdIndirectBlockAddress, ThirdIndirectOffset, BlockType.IndexIndirect3, ThirdIndirectBaseIndex);
  170. if (lowestChange <= 4)
  171. DataClusterAddress = GetBlockIndexValue(FourthIndirectBlockAddress, FourthIndirectOffset, BlockType.IndexIndirect4, FourthIndirectBaseIndex);
  172. }
  173. else if (ThirdIndirectOffset != 0) //Double Indirect
  174. {
  175. FirstIndirectBlockAddress = 0;
  176. SecondIndirectBlockAddress = 0;
  177. ThirdIndirectBlockAddress = m_subFile.DoubleIndirectBlock;
  178. if (lowestChange <= 3)
  179. FourthIndirectBlockAddress = GetBlockIndexValue(ThirdIndirectBlockAddress, ThirdIndirectOffset, BlockType.IndexIndirect3, ThirdIndirectBaseIndex);
  180. if (lowestChange <= 4)
  181. DataClusterAddress = GetBlockIndexValue(FourthIndirectBlockAddress, FourthIndirectOffset, BlockType.IndexIndirect4, FourthIndirectBaseIndex);
  182. }
  183. else if (FourthIndirectOffset != 0) //Single Indirect
  184. {
  185. FirstIndirectBlockAddress = 0;
  186. SecondIndirectBlockAddress = 0;
  187. ThirdIndirectBlockAddress = 0;
  188. FourthIndirectBlockAddress = m_subFile.SingleIndirectBlock;
  189. if (lowestChange <= 4)
  190. DataClusterAddress = GetBlockIndexValue(FourthIndirectBlockAddress, FourthIndirectOffset, BlockType.IndexIndirect4, FourthIndirectBaseIndex);
  191. }
  192. else //Immediate
  193. {
  194. FirstIndirectBlockAddress = 0;
  195. SecondIndirectBlockAddress = 0;
  196. ThirdIndirectBlockAddress = 0;
  197. FourthIndirectBlockAddress = 0;
  198. DataClusterAddress = m_subFile.DirectBlock;
  199. }
  200. }
  201. /// <summary>
  202. /// This uses the (blockIndex,offset) values to determine what the next block index is.
  203. /// This also has consistency checks to determine if the file is inconsistent (potentially corruption)
  204. /// </summary>
  205. /// <param name="blockIndex">the index of the block to read</param>
  206. /// <param name="offset">the offset inside the block to use to determine the next index block</param>
  207. /// <param name="blockType">the value 1-4 which tell what indirect block this is</param>
  208. /// <param name="blockBaseIndex">the lowest virtual address that can be referenced from this indirect block</param>
  209. /// <returns></returns>
  210. private uint GetBlockIndexValue(uint blockIndex, int offset, BlockType blockType, uint blockBaseIndex)
  211. {
  212. DiskIoSession buffer = m_ioSessions.SourceIndex;
  213. if (blockIndex == 0)
  214. return 0;
  215. //Skip the redundant read if this block is still cached.
  216. if (!buffer.IsValid || buffer.BlockIndex != blockIndex)
  217. {
  218. buffer.Read(blockIndex, blockType, blockBaseIndex);
  219. }
  220. return *(uint*)(buffer.Pointer + (offset << 2));
  221. }
  222. #endregion
  223. }
  224. }