DynamicColumn.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /* Copyright (C) 2014-2016 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
  2. *
  3. * You can redistribute this program and/or modify it under the terms of
  4. * the GNU Lesser Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. */
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Text;
  10. using Utilities;
  11. namespace DiskAccessLibrary.LogicalDiskManager
  12. {
  13. /// <summary>
  14. /// Column is a sequence of one or more (dynamic) disk extents, it's an abstraction of disk,
  15. /// Simple Volume uses a single column that has one extent,
  16. /// Spanned volume uses a single column to span data across multiple extents,
  17. /// Striped / RAID-5 write the data in stripes across multiple columns in an orderly fashion. (each column can contain more than one extent)
  18. /// </summary>
  19. public class DynamicColumn
  20. {
  21. public const int DefaultBytesPerSector = 512; // for missing disks
  22. private int m_bytesPerSector;
  23. List<DynamicDiskExtent> m_extents = new List<DynamicDiskExtent>();
  24. public DynamicColumn(DynamicDiskExtent extent)
  25. {
  26. m_extents.Add(extent);
  27. m_bytesPerSector = GetBytesPerSector(m_extents, DefaultBytesPerSector);
  28. }
  29. public DynamicColumn(List<DynamicDiskExtent> extents)
  30. {
  31. m_extents = extents;
  32. m_bytesPerSector = GetBytesPerSector(m_extents, DefaultBytesPerSector);
  33. }
  34. private List<ArrayPosition> TranslateSectors(long startSectorIndex, int sectorCount)
  35. {
  36. List<ArrayPosition> result = new List<ArrayPosition>();
  37. int numberOfDisks = m_extents.Count;
  38. int sectorsLeft = sectorCount;
  39. long currentSectorIndex = startSectorIndex;
  40. while (sectorsLeft > 0)
  41. {
  42. long extentStartSectorInColumn = 0;
  43. long nextExtentStartSectorInColumn = 0;
  44. for (int index = 0; index < m_extents.Count; index++)
  45. {
  46. DynamicDiskExtent extent = m_extents[index];
  47. extentStartSectorInColumn = nextExtentStartSectorInColumn;
  48. nextExtentStartSectorInColumn += extent.TotalSectors;
  49. if (currentSectorIndex >= extentStartSectorInColumn && currentSectorIndex < nextExtentStartSectorInColumn)
  50. {
  51. long sectorIndexInExtent = currentSectorIndex - extentStartSectorInColumn;
  52. int sectorCountInExtent = (int)Math.Min(extent.TotalSectors - sectorIndexInExtent, sectorsLeft);
  53. ArrayPosition position = new ArrayPosition(index, sectorIndexInExtent, sectorCountInExtent);
  54. result.Add(position);
  55. currentSectorIndex += sectorCountInExtent;
  56. sectorsLeft -= sectorCountInExtent;
  57. }
  58. }
  59. }
  60. return result;
  61. }
  62. public byte[] ReadSectors(long sectorIndex, int sectorCount)
  63. {
  64. List<ArrayPosition> readPositions = TranslateSectors(sectorIndex, sectorCount);
  65. byte[] result = new byte[sectorCount * BytesPerSector];
  66. int bytesRead = 0;
  67. foreach (ArrayPosition readPosition in readPositions)
  68. {
  69. DynamicDiskExtent extent = m_extents[readPosition.DiskIndex];
  70. byte[] extentBytes = extent.ReadSectors(readPosition.SectorIndex, readPosition.SectorCount);
  71. Array.Copy(extentBytes, 0, result, bytesRead, extentBytes.Length);
  72. bytesRead += extentBytes.Length;
  73. }
  74. return result;
  75. }
  76. public void WriteSectors(long sectorIndex, byte[] data)
  77. {
  78. int sectorCount = data.Length / BytesPerSector;
  79. List<ArrayPosition> writePositions = TranslateSectors(sectorIndex, sectorCount);
  80. int bytesWritten = 0;
  81. foreach (ArrayPosition writePosition in writePositions)
  82. {
  83. DynamicDiskExtent extent = m_extents[writePosition.DiskIndex];
  84. byte[] extentBytes = new byte[writePosition.SectorCount * BytesPerSector];
  85. Array.Copy(data, bytesWritten, extentBytes, 0, extentBytes.Length);
  86. extent.WriteSectors(writePosition.SectorIndex, extentBytes);
  87. bytesWritten += extentBytes.Length;
  88. }
  89. }
  90. public List<DynamicDiskExtent> Extents
  91. {
  92. get
  93. {
  94. return m_extents;
  95. }
  96. }
  97. public long Size
  98. {
  99. get
  100. {
  101. long result = 0;
  102. foreach (DynamicDiskExtent extent in m_extents)
  103. {
  104. result += extent.Size;
  105. }
  106. return result;
  107. }
  108. }
  109. /// <summary>
  110. /// "All disks holding extents for a given volume must have the same sector size"
  111. /// </summary>
  112. public int BytesPerSector
  113. {
  114. get
  115. {
  116. return m_bytesPerSector;
  117. }
  118. }
  119. public bool IsOperational
  120. {
  121. get
  122. {
  123. foreach (DynamicDiskExtent extent in m_extents)
  124. {
  125. if (extent.Disk == null)
  126. {
  127. return false;
  128. }
  129. }
  130. return true;
  131. }
  132. }
  133. public static int GetBytesPerSector(List<DynamicDiskExtent> extents, int defaultValue)
  134. {
  135. int? bytesPerSector = GetBytesPerSector(extents);
  136. return bytesPerSector.HasValue ? bytesPerSector.Value : defaultValue;
  137. }
  138. /// <summary>
  139. /// "All disks holding extents for a given volume must have the same sector size"
  140. /// </summary>
  141. public static int? GetBytesPerSector(List<DynamicDiskExtent> extents)
  142. {
  143. foreach (DynamicDiskExtent extent in extents)
  144. {
  145. if (extent.Disk != null)
  146. {
  147. return extent.BytesPerSector;
  148. }
  149. }
  150. return null;
  151. }
  152. }
  153. }