- file-io records each file's drive: sys.dm_os_volume_stats from 2008 R2 SP1 (new capability VolumeStats, mount points included), otherwise derived from the path (D:\..., \server\share\, / on Linux), so 2005 works too - migration 0007: Volume and IntervalSeconds on FileIoSamples, and DiskHourly (rolled up by maintenance, kept HourlyDays) - DiskActivity sums files per drive: read/write IOPS, MB/s and latency weighted by I/O count - instance page: "Diskhastighed pr. drev" (table and MB/s + latency charts); time window analysis and its PDF: per drive against the same hours of the four previous weeks - SQLI-IO-001/002 now report per drive (one finding when the storage is slow, the slowest files in the evidence) instead of per file Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
64 lines
2.4 KiB
C#
64 lines
2.4 KiB
C#
using SQLInsight.Core.Data;
|
|
|
|
namespace SQLInsight.Core.Tests;
|
|
|
|
public class DiskTests
|
|
{
|
|
[Theory]
|
|
[InlineData(@"D:\SQLData\Sales.mdf", @"D:\")]
|
|
[InlineData(@"l:\Logs\Sales_log.ldf", @"L:\")]
|
|
[InlineData(@"\\nas01\sql\Sales.mdf", @"\\nas01\sql\")]
|
|
[InlineData("/var/opt/mssql/data/master.mdf", "/")]
|
|
public void Drive_is_derived_from_the_file_path(string physicalName, string volume) =>
|
|
Assert.Equal(volume, DiskVolumes.FromPhysicalName(physicalName));
|
|
|
|
[Fact]
|
|
public void Reported_volume_wins_over_the_path()
|
|
{
|
|
var mountPoint = File("Sales", 1, "ROWS", @"D:\Mounts\Data1\Sales.mdf") with { Volume = @"D:\Mounts\Data1\" };
|
|
|
|
Assert.Equal(@"D:\Mounts\Data1\", DiskVolumes.Of(mountPoint));
|
|
Assert.Equal(@"D:\", DiskVolumes.Of(mountPoint with { Volume = null }));
|
|
}
|
|
|
|
[Fact]
|
|
public void Files_are_summed_per_drive_with_rates_and_weighted_latency()
|
|
{
|
|
var files = new[]
|
|
{
|
|
File("Sales", 1, "ROWS", @"D:\Sales.mdf", reads: 3000, bytesRead: 300 * 1048576L, readStall: 30_000),
|
|
File("Stock", 1, "ROWS", @"D:\Stock.mdf", reads: 1000, bytesRead: 0, readStall: 50_000),
|
|
File("Sales", 2, "LOG", @"L:\Sales_log.ldf", writes: 6000, bytesWritten: 60 * 1048576L, writeStall: 12_000),
|
|
};
|
|
|
|
var disks = DiskActivity.ByVolume(files, seconds: 300);
|
|
|
|
Assert.Equal([@"D:\", @"L:\"], disks.Select(d => d.Volume));
|
|
var data = disks[0];
|
|
Assert.Equal(2, data.DataFiles);
|
|
Assert.Equal(0, data.LogFiles);
|
|
Assert.Equal(4000 / 300.0, data.ReadIops);
|
|
Assert.Equal(1.0, data.ReadMbPerSecond);
|
|
Assert.Equal(20, data.AverageReadMs); // 80 s over 4000 reads, not the average of 10 and 50 ms
|
|
Assert.Null(data.AverageWriteMs);
|
|
var log = disks[1];
|
|
Assert.Equal(20, log.WriteIops);
|
|
Assert.Equal(0.2, log.WriteMbPerSecond!.Value, 6);
|
|
Assert.Equal(2, log.AverageWriteMs);
|
|
}
|
|
|
|
private static FileIoStat File(string db, int id, string type, string path, long reads = 0, long bytesRead = 0, long readStall = 0,
|
|
long writes = 0, long bytesWritten = 0, long writeStall = 0) => new()
|
|
{
|
|
DatabaseName = db,
|
|
FileId = id,
|
|
FileType = type,
|
|
PhysicalName = path,
|
|
Reads = reads,
|
|
BytesRead = bytesRead,
|
|
ReadStallMs = readStall,
|
|
Writes = writes,
|
|
BytesWritten = bytesWritten,
|
|
WriteStallMs = writeStall,
|
|
};
|
|
}
|