123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- using System;
- using System.Collections.Generic;
- using System.Text;
- using DiskAccessLibrary;
- using Utilities;
- namespace DiskAccessLibrary.LogicalDiskManager
- {
- public class AddDiskToArrayHelper
- {
- public static void AddDiskToRaid5Volume(List<DynamicDisk> disks, Raid5Volume volume, DiskExtent newExtent, ref long bytesCopied)
- {
- DiskGroupDatabase database = DiskGroupDatabase.ReadFromDisks(disks, volume.DiskGroupGuid);
- if (database == null)
- {
- throw new DatabaseNotFoundException();
- }
-
-
- VolumeManagerDatabaseHelper.ConvertRaidToStripedVolume(database, volume.VolumeGuid);
- ulong newExtentID = VolumeManagerDatabaseHelper.AddNewExtentToVolume(database, volume, newExtent);
-
-
- byte[] filesystemBootRecord = volume.Extents[0].ReadSector(0);
- newExtent.WriteSectors(newExtent.TotalSectors - 1, filesystemBootRecord);
- AddDiskOperationBootRecord resumeRecord = new AddDiskOperationBootRecord();
- resumeRecord.VolumeGuid = volume.VolumeGuid;
- PrivateHeader privateHeader = PrivateHeader.ReadFromDisk(newExtent.Disk);
-
- resumeRecord.NumberOfCommittedSectors = 0;
-
-
- volume.WriteSectors(0, resumeRecord.GetBytes());
- ResumeAddDiskToRaid5Volume(disks, volume, new DynamicDiskExtent(newExtent, newExtentID), resumeRecord, ref bytesCopied);
- }
- public static void ResumeAddDiskToRaid5Volume(List<DynamicDisk> disks, StripedVolume stripedVolume, AddDiskOperationBootRecord resumeRecord, ref long bytesCopied)
- {
- List<DynamicColumn> columns = stripedVolume.Columns;
- DynamicDiskExtent newExtent = columns[columns.Count - 1].Extents[0];
- columns.RemoveAt(columns.Count - 1);
- Raid5Volume volume = new Raid5Volume(columns, stripedVolume.SectorsPerStripe, stripedVolume.VolumeGuid, stripedVolume.DiskGroupGuid);
- volume.VolumeID = stripedVolume.VolumeID;
- volume.Name = stripedVolume.Name;
- volume.DiskGroupName = stripedVolume.DiskGroupName;
- ResumeAddDiskToRaid5Volume(disks, volume, newExtent, resumeRecord, ref bytesCopied);
- }
- private static void ResumeAddDiskToRaid5Volume(List<DynamicDisk> disks, Raid5Volume volume, DynamicDiskExtent newExtent, AddDiskOperationBootRecord resumeRecord, ref long bytesCopied)
- {
-
-
- List<DynamicColumn> newVolumeColumns = new List<DynamicColumn>();
- newVolumeColumns.AddRange(volume.Columns);
- newVolumeColumns.Add(new DynamicColumn(newExtent));
- Raid5Volume newVolume = new Raid5Volume(newVolumeColumns, volume.SectorsPerStripe, volume.VolumeGuid, volume.DiskGroupGuid);
- int oldColumnCount = volume.Columns.Count;
- int newColumnCount = oldColumnCount + 1;
- long resumeFromStripe = (long)resumeRecord.NumberOfCommittedSectors / volume.SectorsPerStripe;
-
-
-
-
-
- int maximumStripesToTransfer = (Settings.MaximumTransferSizeLBA / volume.SectorsPerStripe) / (newColumnCount - 1) * (newColumnCount - 1);
- long totalStripesInVolume = volume.TotalStripes;
- long stripeIndexInVolume = resumeFromStripe;
- while (stripeIndexInVolume < totalStripesInVolume)
- {
-
-
-
-
- long stripeToReadIndexInColumn = stripeIndexInVolume / (oldColumnCount - 1);
- long stripeToWriteIndexInColumn = stripeIndexInVolume / (newColumnCount - 1);
- long numberOfStripesSafeToTransfer = (stripeToReadIndexInColumn - stripeToWriteIndexInColumn) * (newColumnCount - 1);
- bool verticalStripeAtRisk = (numberOfStripesSafeToTransfer == 0);
- if (numberOfStripesSafeToTransfer == 0)
- {
-
-
-
- numberOfStripesSafeToTransfer = (newColumnCount - 1);
- }
- int numberOfStripesToTransfer = (int)Math.Min(numberOfStripesSafeToTransfer, maximumStripesToTransfer);
- long stripesLeft = totalStripesInVolume - stripeIndexInVolume;
- numberOfStripesToTransfer = (int)Math.Min(numberOfStripesToTransfer, stripesLeft);
- byte[] segmentData = volume.ReadStripes(stripeIndexInVolume, numberOfStripesToTransfer);
- if (numberOfStripesToTransfer % (newColumnCount - 1) > 0)
- {
-
- int numberOfStripesToWrite = (int)Math.Ceiling((double)numberOfStripesToTransfer / (newColumnCount - 1)) * (newColumnCount - 1);
- byte[] temp = new byte[numberOfStripesToWrite * volume.BytesPerStripe];
- Array.Copy(segmentData, temp, segmentData.Length);
- segmentData = temp;
- }
- long firstStripeIndexInColumn = stripeIndexInVolume / (newColumnCount - 1);
- if (verticalStripeAtRisk)
- {
-
-
- newVolume.WriteStripes(stripeIndexInVolume, segmentData);
- }
- else
- {
- WriteSegment(volume, newExtent, firstStripeIndexInColumn, segmentData);
- }
-
- resumeRecord.NumberOfCommittedSectors += (ulong)(numberOfStripesToTransfer * volume.SectorsPerStripe);
- bytesCopied = (long)resumeRecord.NumberOfCommittedSectors * volume.BytesPerSector;
- newVolume.WriteSectors(0, resumeRecord.GetBytes());
- stripeIndexInVolume += numberOfStripesToTransfer;
- }
-
- byte[] filesystemBootRecord = newExtent.ReadSector(newExtent.TotalSectors - 1);
- newVolume.WriteSectors(0, filesystemBootRecord);
- DiskGroupDatabase database = DiskGroupDatabase.ReadFromDisks(disks, volume.DiskGroupGuid);
- VolumeManagerDatabaseHelper.ConvertStripedVolumeToRaid(database, volume.VolumeGuid);
- }
-
-
-
-
-
- public static void WriteSegment(Raid5Volume volume, DynamicDiskExtent newExtent, long firstStripeIndexInColumn, byte[] data)
- {
- List<DynamicColumn> newArray = new List<DynamicColumn>();
- newArray.AddRange(volume.Columns);
- newArray.Add(new DynamicColumn(newExtent));
- int bytesPerStripe = volume.BytesPerStripe;
- int stripesToWritePerColumn = (data.Length / bytesPerStripe) / (newArray.Count - 1);
-
- int dataLengthPerColumn = stripesToWritePerColumn * bytesPerStripe;
- byte[][] columnData = new byte[newArray.Count][];
- for(int index = 0; index < columnData.Length; index++)
- {
- columnData[index] = new byte[dataLengthPerColumn];
- }
- Parallel.For(0, stripesToWritePerColumn, delegate(int stripeOffsetInColumn)
- {
- long stripeIndexInColumn = firstStripeIndexInColumn + stripeOffsetInColumn;
- int parityColumnIndex = (newArray.Count - 1) - (int)(stripeIndexInColumn % newArray.Count);
- byte[] parityData = new byte[bytesPerStripe];
- for (int stripeVerticalIndex = 0; stripeVerticalIndex < newArray.Count - 1; stripeVerticalIndex++)
- {
- int columnIndex = (parityColumnIndex + 1 + stripeVerticalIndex) % newArray.Count;
- long stripeOffsetInData = (stripeOffsetInColumn * (newArray.Count - 1) + stripeVerticalIndex) * bytesPerStripe;
- Array.Copy(data, stripeOffsetInData, columnData[columnIndex], stripeOffsetInColumn * bytesPerStripe, bytesPerStripe);
- parityData = ByteUtils.XOR(parityData, 0, columnData[columnIndex], stripeOffsetInColumn * bytesPerStripe, bytesPerStripe);
- }
- Array.Copy(parityData, 0, columnData[parityColumnIndex], stripeOffsetInColumn * bytesPerStripe, bytesPerStripe);
- });
-
- long firstSectorIndexInColumn = firstStripeIndexInColumn * volume.SectorsPerStripe;
- for (int columnIndex = 0; columnIndex < newArray.Count; columnIndex++)
- {
- newArray[columnIndex].WriteSectors(firstSectorIndexInColumn, columnData[columnIndex]);
- }
- }
- }
- }
|