The Mono implementation of DriveInfo you use is broken with regards to using ZFS. I keep getting spammed in the ES log by this:
Error while reading drive info for path /data/es. Message: The drive name does not exist
Parameter name: driveName.
Because somehow DriveInfo is not able to handle the case when using ZFS datasets that are mounted.
Here is the fix:
using System;
using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
using EventStore.Common.Log;
using EventStore.Common.Utils;
using EventStore.Core.Services.Monitoring.Utils;
namespace EventStore.Core.Services.Monitoring.Stats
{
public class EsDriveInfo
{
public readonly string DiskName;
public readonly long TotalBytes;
public readonly long AvailableBytes;
public readonly long UsedBytes;
public readonly string Usage;
public static EsDriveInfo FromDirectory(string path)
{
try
{
if (IsUnix) return GetEsDriveInfoUnix(path);
var drive = new DriveInfo(Directory.GetDirectoryRoot(path));
return new EsDriveInfo(drive.Name, drive.TotalSize, drive.AvailableFreeSpace);
}
catch (Exception ex)
{
Console.Error.Write("Error while reading drive info for path {0}. Message: {1}.", path, ex.Message);
return null;
}
}
private EsDriveInfo(string diskName, long totalBytes, long availableBytes)
{
DiskName = diskName;
TotalBytes = totalBytes;
AvailableBytes = availableBytes;
UsedBytes = TotalBytes - AvailableBytes;
Usage = TotalBytes != 0
? (UsedBytes * 100 / TotalBytes).ToString(CultureInfo.InvariantCulture) + "%"
: "0%";
}
private static EsDriveInfo GetEsDriveInfoUnix(string directory)
{
// http://unix.stackexchange.com/questions/11311/how-do-i-find-on-which-physical-device-a-folder-is-located
// example
// Filesystem 1K-blocks Used Available Use% Mounted on
// /dev/sda1 153599996 118777100 34822896 78% /media/CC88FD3288FD1C20
try
{
if(!Directory.Exists(directory)) return null;
var driveInfo = ShellExecutor.GetOutput("df", $"-P {directory}");
var driveInfoLines = driveInfo.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
if(driveInfoLines.Length == 0) return null;
var ourline = driveInfoLines[1];
var trimmedLine = SpacesRegex.Replace(ourline, " ");
var info = trimmedLine.Split(' ');
var totalBytes = long.Parse(info[1].Trim()); // the '1024-blocks' column
var availableBytes = long.Parse(info[3].Trim()); // the 'Available' column
var mountPoint = info[5]; // the 'Mounted on' column
return new EsDriveInfo(mountPoint, totalBytes, availableBytes);
}
catch (Exception ex)
{
Console.Error.WriteLine("Could not get drive name for directory '{0}' on Unix - {1}", directory, ex.Message);
return null;
}
}
}
Thanks @ahjohannessen, we'll work on integrating a fix for this since ZFS is a recommended configuration. This fix looks great given the infrequency with which it is executed - we'll likely look at PInvoking libzfs functions directly if it becomes a bottleneck.
Most helpful comment
Thanks @ahjohannessen, we'll work on integrating a fix for this since ZFS is a recommended configuration. This fix looks great given the infrequency with which it is executed - we'll likely look at PInvoking
libzfsfunctions directly if it becomes a bottleneck.