MoveHelper.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /* Copyright (C) 2014 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 DiskAccessLibrary.LogicalDiskManager;
  11. using Utilities;
  12. namespace DiskAccessLibrary
  13. {
  14. public class MoveHelper
  15. {
  16. /// <summary>
  17. /// When a user want to move an extent one sector to the left/right (e.g. for alignment purposes),
  18. /// the regular operation method will mandate reading and writing one sector at a time,
  19. /// this can be extremely slow, and to avoid this, we use free space on the disk to "buffer" the data read.
  20. /// (this will allow us to recover from a power failure)
  21. /// </summary>
  22. public const int BufferedModeThresholdLBA = 64;
  23. public static void MoveExtentDataRight(Volume volume, DiskExtent sourceExtent, DiskExtent relocatedExtent, MoveExtentOperationBootRecord resumeRecord, ref long bytesCopied)
  24. {
  25. // we make sure no data will be overwritten too soon:
  26. long distanceLBA = (long)(resumeRecord.NewStartSector - resumeRecord.OldStartSector);
  27. bool bufferedMode = false;
  28. if (distanceLBA < BufferedModeThresholdLBA)
  29. {
  30. bufferedMode = true;
  31. }
  32. int transferSizeLBA;
  33. if (bufferedMode)
  34. {
  35. transferSizeLBA = (int)resumeRecord.BackupBufferSizeLBA;
  36. }
  37. else
  38. {
  39. transferSizeLBA = (int)Math.Min(Settings.MaximumTransferSizeLBA, distanceLBA);
  40. }
  41. // move the data
  42. for (long readCount = (long)resumeRecord.NumberOfCommittedSectors; readCount < relocatedExtent.TotalSectors; readCount += transferSizeLBA)
  43. {
  44. // we read (and write) from the end of the extent and progress to the left
  45. long sectorsLeft = relocatedExtent.TotalSectors - readCount;
  46. int sectorsToRead = (int)Math.Min(transferSizeLBA, sectorsLeft);
  47. long sectorIndex = relocatedExtent.TotalSectors - readCount - sectorsToRead;
  48. byte[] data = sourceExtent.ReadSectors(sectorIndex, sectorsToRead);
  49. if (bufferedMode)
  50. {
  51. // we write the data to the buffer for recovery purposes
  52. relocatedExtent.Disk.WriteSectors((long)resumeRecord.BackupBufferStartSector, data);
  53. resumeRecord.RestoreFromBuffer = true;
  54. // Note: if the extent we move is the first in the volume, we will write the resume record to
  55. // the source extent, which is the one that the database is still referring to
  56. volume.WriteSectors(0, resumeRecord.GetBytes());
  57. }
  58. relocatedExtent.WriteSectors(sectorIndex, data);
  59. // update the resume record
  60. resumeRecord.RestoreFromBuffer = false;
  61. resumeRecord.NumberOfCommittedSectors += (ulong)sectorsToRead;
  62. volume.WriteSectors(0, resumeRecord.GetBytes());
  63. bytesCopied = (long)resumeRecord.NumberOfCommittedSectors * sourceExtent.BytesPerSector;
  64. }
  65. }
  66. public static void MoveExtentDataLeft(Volume volume, DiskExtent sourceExtent, DiskExtent relocatedExtent, MoveExtentOperationBootRecord resumeRecord, ref long bytesCopied)
  67. {
  68. // we make sure no data will be overwritten too soon:
  69. long distanceLBA = (long)(resumeRecord.OldStartSector - resumeRecord.NewStartSector);
  70. bool bufferedMode = false;
  71. if (distanceLBA < BufferedModeThresholdLBA)
  72. {
  73. bufferedMode = true;
  74. }
  75. int transferSizeLBA;
  76. if (bufferedMode)
  77. {
  78. transferSizeLBA = (int)resumeRecord.BackupBufferSizeLBA; ;
  79. }
  80. else
  81. {
  82. transferSizeLBA = (int)Math.Min(Settings.MaximumTransferSizeLBA, distanceLBA);
  83. }
  84. // move the data
  85. for (long sectorIndex = (long)resumeRecord.NumberOfCommittedSectors; sectorIndex < relocatedExtent.TotalSectors; sectorIndex += transferSizeLBA)
  86. {
  87. long sectorsLeft = relocatedExtent.TotalSectors - sectorIndex;
  88. int sectorsToRead = (int)Math.Min(transferSizeLBA, sectorsLeft);
  89. byte[] data = sourceExtent.ReadSectors(sectorIndex, sectorsToRead);
  90. if (bufferedMode)
  91. {
  92. // we write the data to the buffer for recovery purposes
  93. relocatedExtent.Disk.WriteSectors((long)resumeRecord.BackupBufferStartSector, data);
  94. resumeRecord.RestoreFromBuffer = true;
  95. relocatedExtent.WriteSectors(0, resumeRecord.GetBytes());
  96. }
  97. relocatedExtent.WriteSectors(sectorIndex, data);
  98. // update the resume record
  99. resumeRecord.RestoreFromBuffer = false;
  100. resumeRecord.NumberOfCommittedSectors += (ulong)sectorsToRead;
  101. volume.WriteSectors(0, resumeRecord.GetBytes());
  102. bytesCopied = (long)resumeRecord.NumberOfCommittedSectors * sourceExtent.BytesPerSector;
  103. }
  104. }
  105. }
  106. }