Beispiel #1
0
        public static void ExtendRAID5Volume(DiskGroupDatabase database, Raid5Volume volume, long numberOfAdditionalExtentSectors)
        {
            if (numberOfAdditionalExtentSectors % volume.SectorsPerStripe > 0)
            {
                throw new ArgumentException("Number of additional sectors must be multiple of stripes per sector");
            }

            List <DatabaseRecord> records = new List <DatabaseRecord>();

            VolumeRecord volumeRecord = database.FindVolumeByVolumeGuid(volume.VolumeGuid);

            volumeRecord          = (VolumeRecord)volumeRecord.Clone();
            volumeRecord.SizeLBA += (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(numberOfAdditionalExtentSectors * (volume.NumberOfColumns - 1), volume.BytesPerSector);
            records.Add(volumeRecord);

            foreach (DynamicColumn column in volume.Columns)
            {
                DynamicDiskExtent lastExtent   = column.Extents[column.Extents.Count - 1];
                ExtentRecord      extentRecord = database.FindExtentByExtentID(lastExtent.ExtentID);
                extentRecord          = (ExtentRecord)extentRecord.Clone();
                extentRecord.SizeLBA += (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(numberOfAdditionalExtentSectors, volume.BytesPerSector);
                records.Add(extentRecord);

                DiskRecord diskRecord = database.FindDiskByDiskID(extentRecord.DiskId); // we should update the disk, see Database.cs
                diskRecord = (DiskRecord)diskRecord.Clone();
                records.Add(diskRecord);
            }

            database.UpdateDatabase(records);
        }
Beispiel #2
0
        /// <summary>
        /// Update the database to point to the new extent location (same or different disk)
        /// </summary>
        public static void UpdateExtentLocation(DiskGroupDatabase database, DynamicVolume volume, DynamicDiskExtent relocatedExtent)
        {
            PrivateHeader privateHeader = PrivateHeader.ReadFromDisk(relocatedExtent.Disk);

            DiskRecord   targetDiskRecord = database.FindDiskByDiskGuid(privateHeader.DiskGuid);
            VolumeRecord volumeRecord     = database.FindVolumeByVolumeGuid(volume.VolumeGuid);

            List <DatabaseRecord> records               = new List <DatabaseRecord>();
            ExtentRecord          sourceExtentRecord    = database.FindExtentByExtentID(relocatedExtent.ExtentID);
            ExtentRecord          relocatedExtentRecord = (ExtentRecord)sourceExtentRecord.Clone();

            relocatedExtentRecord.DiskId        = targetDiskRecord.DiskId;
            relocatedExtentRecord.DiskOffsetLBA = (ulong)PublicRegionHelper.TranslateToPublicRegionLBA(relocatedExtent.FirstSector, privateHeader);
            records.Add(relocatedExtentRecord);

            // we should update the disk records
            foreach (DynamicDiskExtent extent in volume.Extents)
            {
                DiskRecord diskRecord = database.FindDiskByDiskID(relocatedExtentRecord.DiskId);
                // there could be multiple extents on the same disk, make sure we only add each disk once
                if (!records.Contains(diskRecord))
                {
                    diskRecord = (DiskRecord)diskRecord.Clone();
                    records.Add(diskRecord);
                }
            }

            // when moving to a new disk, we should update the new disk record as well
            if (!records.Contains(targetDiskRecord))
            {
                records.Add(targetDiskRecord.Clone());
            }

            database.UpdateDatabase(records);
        }
Beispiel #3
0
        public static ulong CreateSimpleVolume(DiskGroupDatabase database, DiskExtent extent)
        {
            List <DatabaseRecord> records = new List <DatabaseRecord>();

            VolumeRecord volumeRecord = new VolumeRecord();

            volumeRecord.Id                 = database.AllocateNewRecordID();
            volumeRecord.Name               = GetNextSimpleVolumeName(database.VolumeRecords);
            volumeRecord.VolumeTypeString   = "gen";
            volumeRecord.StateString        = "ACTIVE";
            volumeRecord.ReadPolicy         = ReadPolicyName.Select;
            volumeRecord.VolumeNumber       = GetNextVolumeNumber(database.VolumeRecords);
            volumeRecord.VolumeFlags        = VolumeFlags.Writeback | VolumeFlags.DefaultUnknown;
            volumeRecord.NumberOfComponents = 1;
            volumeRecord.SizeLBA            = (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(extent.TotalSectors, extent.BytesPerSector);
            volumeRecord.PartitionType      = PartitionType.RAW;
            volumeRecord.VolumeGuid         = Guid.NewGuid();
            records.Add(volumeRecord);

            ComponentRecord componentRecord = new ComponentRecord();

            componentRecord.Id                    = database.AllocateNewRecordID();
            componentRecord.Name                  = volumeRecord.Name + "-01";
            componentRecord.StateString           = "ACTIVE";
            componentRecord.ExtentLayout          = ExtentLayoutName.Concatenated;
            componentRecord.NumberOfExtents       = 1;
            componentRecord.VolumeId              = volumeRecord.VolumeId;
            componentRecord.HasStripedExtentsFlag = false;
            componentRecord.NumberOfColumns       = 0;
            records.Add(componentRecord);

            // we should update the disk record
            PrivateHeader privateHeader = PrivateHeader.ReadFromDisk(extent.Disk);
            DiskRecord    diskRecord    = database.FindDiskByDiskGuid(privateHeader.DiskGuid);

            diskRecord = (DiskRecord)diskRecord.Clone();
            records.Add(diskRecord);

            ExtentRecord extentRecord = new ExtentRecord();

            extentRecord.Name          = GetNextExtentName(database.ExtentRecords, diskRecord.Name);
            extentRecord.DiskOffsetLBA = (ulong)PublicRegionHelper.TranslateToPublicRegionLBA(extent.FirstSector, privateHeader);
            extentRecord.SizeLBA       = volumeRecord.SizeLBA;
            extentRecord.ComponentId   = componentRecord.ComponentId;
            extentRecord.DiskId        = diskRecord.DiskId;

            extentRecord.HasColumnIndexFlag = false;

            records.Add(extentRecord);

            database.UpdateDatabase(records);

            return(volumeRecord.VolumeId);
        }
Beispiel #4
0
        private static StripedVolume GetStripedVolume(DiskGroupDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
        {
            List <DynamicColumn> columns   = GetDynamicVolumeColumns(database, componentRecord, volumeRecord);
            int           bytesPerSector   = DynamicVolume.GetBytesPerSector(columns, DynamicColumn.DefaultBytesPerSector);
            int           sectorsPerStripe = (int)PublicRegionHelper.TranslateFromPublicRegionSizeLBA((int)componentRecord.StripeSizeLBA, bytesPerSector);
            StripedVolume volume           = new StripedVolume(columns, sectorsPerStripe, volumeRecord.VolumeGuid, database.DiskGroupGuid);

            volume.VolumeID      = volumeRecord.VolumeId;
            volume.Name          = volumeRecord.Name;
            volume.DiskGroupName = database.DiskGroupName;
            return(volume);
        }
Beispiel #5
0
        /// <summary>
        /// Support null disks
        /// </summary>
        public static long GetExtentStartSector(DynamicDisk disk, ExtentRecord extentRecord)
        {
            long publicRegionStartLBA = 0;
            int  bytesPerDiskSector   = DynamicColumn.DefaultBytesPerSector; // default for missing disks

            if (disk != null)
            {
                bytesPerDiskSector = disk.BytesPerSector;
                PrivateHeader privateHeader = disk.PrivateHeader;
                publicRegionStartLBA = (long)privateHeader.PublicRegionStartLBA;
            }
            return(PublicRegionHelper.TranslateFromPublicRegionLBA((long)extentRecord.DiskOffsetLBA, publicRegionStartLBA, bytesPerDiskSector));
        }
Beispiel #6
0
        public static void ExtendSimpleVolume(DiskGroupDatabase database, SimpleVolume volume, long numberOfAdditionalSectors)
        {
            VolumeRecord volumeRecord = database.FindVolumeByVolumeGuid(volume.VolumeGuid);

            volumeRecord          = (VolumeRecord)volumeRecord.Clone();
            volumeRecord.SizeLBA += (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(numberOfAdditionalSectors, volume.BytesPerSector);
            ExtentRecord extentRecord = database.FindExtentByExtentID(volume.DiskExtent.ExtentID);

            extentRecord          = (ExtentRecord)extentRecord.Clone();
            extentRecord.SizeLBA += (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(numberOfAdditionalSectors, volume.BytesPerSector);
            DiskRecord diskRecord = database.FindDiskByDiskID(extentRecord.DiskId); // we should update the disk, see Database.cs

            diskRecord = (DiskRecord)diskRecord.Clone();

            List <DatabaseRecord> records = new List <DatabaseRecord>();

            records.Add(volumeRecord);
            records.Add(extentRecord);
            records.Add(diskRecord);

            database.UpdateDatabase(records);
        }
Beispiel #7
0
        /// <summary>
        /// Update the database (add the new extent)
        /// </summary>
        /// <param name="volume">RAID-5 or striped volume</param>
        /// <returns>new extent ID</returns>
        public static ulong AddNewExtentToVolume(DiskGroupDatabase database, DynamicVolume volume, DiskExtent newExtent)
        {
            PrivateHeader privateHeader = PrivateHeader.ReadFromDisk(newExtent.Disk);

            List <DatabaseRecord> records = new List <DatabaseRecord>();

            VolumeRecord volumeRecord = database.FindVolumeByVolumeGuid(volume.VolumeGuid);

            if (volumeRecord == null)
            {
                throw new MissingDatabaseRecordException("Volume record is missing");
            }
            volumeRecord          = (VolumeRecord)volumeRecord.Clone();
            volumeRecord.SizeLBA += (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(newExtent.TotalSectors, privateHeader);
            records.Add(volumeRecord);

            ComponentRecord componentRecord = database.FindComponentsByVolumeID(volumeRecord.VolumeId)[0];

            if (componentRecord == null)
            {
                throw new MissingDatabaseRecordException("Component record is missing");
            }
            componentRecord = (ComponentRecord)componentRecord.Clone();
            componentRecord.NumberOfExtents++;
            componentRecord.NumberOfColumns++;
            records.Add(componentRecord);

            DiskRecord diskRecord = database.FindDiskByDiskGuid(privateHeader.DiskGuid);

            if (diskRecord == null)
            {
                throw new MissingDatabaseRecordException("Disk record is missing");
            }
            diskRecord = (DiskRecord)diskRecord.Clone();
            records.Add(diskRecord);

            ExtentRecord newExtentRecord = new ExtentRecord();

            newExtentRecord.Name               = GetNextExtentName(database.ExtentRecords, diskRecord.Name);
            newExtentRecord.ComponentId        = componentRecord.ComponentId;
            newExtentRecord.DiskId             = diskRecord.DiskId;
            newExtentRecord.DiskOffsetLBA      = (ulong)PublicRegionHelper.TranslateToPublicRegionLBA(newExtent.FirstSector, privateHeader);
            newExtentRecord.SizeLBA            = (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(newExtent.TotalSectors, privateHeader);
            newExtentRecord.HasColumnIndexFlag = true;
            newExtentRecord.ColumnIndex        = (uint)volume.Columns.Count; // zero based

            records.Add(newExtentRecord);

            // we should update the disk records and extent records
            foreach (DynamicDiskExtent extent in volume.Extents)
            {
                ExtentRecord extentRecord = database.FindExtentByExtentID(extent.ExtentID);
                if (extentRecord == null)
                {
                    throw new MissingDatabaseRecordException("Extent record is missing");
                }
                extentRecord = (ExtentRecord)extentRecord.Clone();
                records.Add(extentRecord);

                diskRecord = database.FindDiskByDiskID(extentRecord.DiskId);
                if (diskRecord == null)
                {
                    throw new MissingDatabaseRecordException("Disk record is missing");
                }
                // there could be multiple extents on the same disk, make sure we only add each disk once
                if (!records.Contains(diskRecord))
                {
                    diskRecord = (DiskRecord)diskRecord.Clone();
                    records.Add(diskRecord);
                }
            }

            database.UpdateDatabase(records);

            return(newExtentRecord.ExtentId);
        }
Beispiel #8
0
        public static ulong CreateRAID5Volume(DiskGroupDatabase database, List <DiskExtent> extents, bool isDegraded)
        {
            int numberOfColumns;

            if (isDegraded)
            {
                numberOfColumns = extents.Count + 1;
            }
            else
            {
                numberOfColumns = extents.Count;
            }

            List <DatabaseRecord> records = new List <DatabaseRecord>();

            VolumeRecord volumeRecord = new VolumeRecord();

            volumeRecord.Id                 = database.AllocateNewRecordID();
            volumeRecord.Name               = GetNextRAIDVolumeName(database.VolumeRecords);
            volumeRecord.VolumeTypeString   = "raid5";
            volumeRecord.StateString        = "ACTIVE";
            volumeRecord.ReadPolicy         = ReadPolicyName.RAID;
            volumeRecord.VolumeNumber       = GetNextVolumeNumber(database.VolumeRecords);
            volumeRecord.VolumeFlags        = VolumeFlags.Writeback | VolumeFlags.Writecopy | VolumeFlags.DefaultUnknown;
            volumeRecord.NumberOfComponents = 1;
            volumeRecord.SizeLBA            = (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(extents[0].TotalSectors * (numberOfColumns - 1), extents[0].BytesPerSector);
            volumeRecord.PartitionType      = PartitionType.RAW;
            volumeRecord.VolumeGuid         = Guid.NewGuid();
            records.Add(volumeRecord);

            ComponentRecord componentRecord = new ComponentRecord();

            componentRecord.Id                    = database.AllocateNewRecordID();
            componentRecord.Name                  = volumeRecord.Name + "-01";
            componentRecord.StateString           = "ACTIVE";
            componentRecord.ExtentLayout          = ExtentLayoutName.RAID5;
            componentRecord.NumberOfExtents       = (uint)numberOfColumns;
            componentRecord.VolumeId              = volumeRecord.VolumeId;
            componentRecord.HasStripedExtentsFlag = true;
            componentRecord.StripeSizeLBA         = 128; // 64KB - the default
            componentRecord.NumberOfColumns       = (uint)numberOfColumns;
            records.Add(componentRecord);

            for (int index = 0; index < extents.Count; index++)
            {
                DiskExtent extent = extents[index];

                // we should update the disk records
                PrivateHeader privateHeader = PrivateHeader.ReadFromDisk(extent.Disk);
                DiskRecord    diskRecord    = database.FindDiskByDiskGuid(privateHeader.DiskGuid);
                diskRecord = (DiskRecord)diskRecord.Clone();
                records.Add(diskRecord);

                ExtentRecord extentRecord = new ExtentRecord();
                extentRecord.Name          = GetNextExtentName(database.ExtentRecords, diskRecord.Name);
                extentRecord.DiskOffsetLBA = (ulong)PublicRegionHelper.TranslateToPublicRegionLBA(extent.FirstSector, privateHeader);
                extentRecord.SizeLBA       = (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(extent.TotalSectors, extent.BytesPerSector);
                extentRecord.ComponentId   = componentRecord.ComponentId;
                extentRecord.DiskId        = diskRecord.DiskId;

                extentRecord.HasColumnIndexFlag = (index > 0);
                extentRecord.ColumnIndex        = (uint)index; // zero based

                records.Add(extentRecord);
            }

            if (isDegraded)
            {
                // we have to make-up a disk
                // The DiskFlags and ExtentFlags are not necessary (they will be added later anyway when the disk group is reimported)
                DiskRecord diskRecord = new DiskRecord();
                diskRecord.Id        = database.AllocateNewRecordID();
                diskRecord.Name      = "Miss" + new Random().Next(100);
                diskRecord.DiskGuid  = Guid.NewGuid();
                diskRecord.DiskFlags = DiskFlags.Detached;
                records.Add(diskRecord);

                ExtentRecord extentRecord = new ExtentRecord();
                extentRecord.Name               = diskRecord.Name + "-01";
                extentRecord.ExtentFlags        = ExtentFlags.Recover;
                extentRecord.SizeLBA            = (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(extents[0].TotalSectors, extents[0].BytesPerSector);
                extentRecord.ComponentId        = componentRecord.ComponentId;
                extentRecord.DiskId             = diskRecord.DiskId;
                extentRecord.HasColumnIndexFlag = true;
                extentRecord.ColumnIndex        = (uint)extents.Count; // zero based

                records.Add(extentRecord);
            }

            database.UpdateDatabase(records);

            return(volumeRecord.VolumeId);
        }