mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 08:23:05 -05:00
Add asynchronous I/O testing to memfs-dotnet.
Make SeekableReadDirectory virtual, so that it can be overridden.
This commit is contained in:
parent
af7e5432a7
commit
879fa2464f
@ -1291,7 +1291,7 @@ namespace Fsp
|
|||||||
ModificationDescriptor,
|
ModificationDescriptor,
|
||||||
ref ModifiedDescriptor);
|
ref ModifiedDescriptor);
|
||||||
}
|
}
|
||||||
public Int32 SeekableReadDirectory(
|
public virtual Int32 SeekableReadDirectory(
|
||||||
Object FileNode,
|
Object FileNode,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
String Pattern,
|
String Pattern,
|
||||||
|
@ -19,12 +19,17 @@
|
|||||||
* associated repository.
|
* associated repository.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define MEMFS_SLOWIO
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.AccessControl;
|
using System.Security.AccessControl;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
#if MEMFS_SLOWIO
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
#endif
|
||||||
|
|
||||||
using Fsp;
|
using Fsp;
|
||||||
using VolumeInfo = Fsp.Interop.VolumeInfo;
|
using VolumeInfo = Fsp.Interop.VolumeInfo;
|
||||||
@ -232,15 +237,20 @@ namespace memfs
|
|||||||
|
|
||||||
class Memfs : FileSystemBase
|
class Memfs : FileSystemBase
|
||||||
{
|
{
|
||||||
|
private FileSystemHost Host;
|
||||||
public const UInt16 MEMFS_SECTOR_SIZE = 512;
|
public const UInt16 MEMFS_SECTOR_SIZE = 512;
|
||||||
public const UInt16 MEMFS_SECTORS_PER_ALLOCATION_UNIT = 1;
|
public const UInt16 MEMFS_SECTORS_PER_ALLOCATION_UNIT = 1;
|
||||||
|
|
||||||
public Memfs(
|
public Memfs(
|
||||||
Boolean CaseInsensitive, UInt32 MaxFileNodes, UInt32 MaxFileSize, String RootSddl)
|
Boolean CaseInsensitive, UInt32 MaxFileNodes, UInt32 MaxFileSize, String RootSddl,
|
||||||
|
UInt64 SlowioMaxDelay, UInt64 SlowioPercentDelay, UInt64 SlowioRarefyDelay)
|
||||||
{
|
{
|
||||||
this.FileNodeMap = new FileNodeMap(CaseInsensitive);
|
this.FileNodeMap = new FileNodeMap(CaseInsensitive);
|
||||||
this.MaxFileNodes = MaxFileNodes;
|
this.MaxFileNodes = MaxFileNodes;
|
||||||
this.MaxFileSize = MaxFileSize;
|
this.MaxFileSize = MaxFileSize;
|
||||||
|
this.SlowioMaxDelay = SlowioMaxDelay;
|
||||||
|
this.SlowioPercentDelay = SlowioPercentDelay;
|
||||||
|
this.SlowioRarefyDelay = SlowioRarefyDelay;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create root directory.
|
* Create root directory.
|
||||||
@ -259,7 +269,7 @@ namespace memfs
|
|||||||
|
|
||||||
public override Int32 Init(Object Host0)
|
public override Int32 Init(Object Host0)
|
||||||
{
|
{
|
||||||
FileSystemHost Host = (FileSystemHost)Host0;
|
Host = (FileSystemHost)Host0;
|
||||||
Host.SectorSize = Memfs.MEMFS_SECTOR_SIZE;
|
Host.SectorSize = Memfs.MEMFS_SECTOR_SIZE;
|
||||||
Host.SectorsPerAllocationUnit = Memfs.MEMFS_SECTORS_PER_ALLOCATION_UNIT;
|
Host.SectorsPerAllocationUnit = Memfs.MEMFS_SECTORS_PER_ALLOCATION_UNIT;
|
||||||
Host.VolumeCreationTime = (UInt64)DateTime.Now.ToFileTimeUtc();
|
Host.VolumeCreationTime = (UInt64)DateTime.Now.ToFileTimeUtc();
|
||||||
@ -549,6 +559,89 @@ namespace memfs
|
|||||||
Interlocked.Decrement(ref FileNode.OpenCount);
|
Interlocked.Decrement(ref FileNode.OpenCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MEMFS_SLOWIO
|
||||||
|
private UInt64 Hash(UInt64 X)
|
||||||
|
{
|
||||||
|
X = (X ^ (X >> 30)) * 0xbf58476d1ce4e5b9ul;
|
||||||
|
X = (X ^ (X >> 27)) * 0x94d049bb133111ebul;
|
||||||
|
X = X ^ (X >> 31);
|
||||||
|
return X;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int Spin = 0;
|
||||||
|
|
||||||
|
private UInt64 PseudoRandom(UInt64 To)
|
||||||
|
{
|
||||||
|
/* John Oberschelp's PRNG */
|
||||||
|
Interlocked.Increment(ref Spin);
|
||||||
|
return Hash((UInt64)Spin) % To;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SlowioReturnPending()
|
||||||
|
{
|
||||||
|
if (0 == SlowioMaxDelay)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return PseudoRandom(100) < SlowioPercentDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SlowioSnooze()
|
||||||
|
{
|
||||||
|
double Millis = PseudoRandom(SlowioMaxDelay + 1) >> (int) PseudoRandom(SlowioRarefyDelay + 1);
|
||||||
|
Thread.Sleep(TimeSpan.FromMilliseconds(Millis));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlowioReadTask(
|
||||||
|
Object FileNode0,
|
||||||
|
IntPtr Buffer,
|
||||||
|
UInt64 Offset,
|
||||||
|
UInt64 EndOffset,
|
||||||
|
UInt64 RequestHint)
|
||||||
|
{
|
||||||
|
SlowioSnooze();
|
||||||
|
|
||||||
|
UInt32 BytesTransferred = (UInt32)(EndOffset - Offset);
|
||||||
|
FileNode FileNode = (FileNode)FileNode0;
|
||||||
|
Marshal.Copy(FileNode.FileData, (int)Offset, Buffer, (int)BytesTransferred);
|
||||||
|
|
||||||
|
Host.SendReadResponse(RequestHint, STATUS_SUCCESS, BytesTransferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlowioWriteTask(
|
||||||
|
Object FileNode0,
|
||||||
|
IntPtr Buffer,
|
||||||
|
UInt64 Offset,
|
||||||
|
UInt64 EndOffset,
|
||||||
|
UInt64 RequestHint)
|
||||||
|
{
|
||||||
|
SlowioSnooze();
|
||||||
|
|
||||||
|
UInt32 BytesTransferred = (UInt32)(EndOffset - Offset);
|
||||||
|
FileNode FileNode = (FileNode)FileNode0;
|
||||||
|
FileInfo FileInfo = FileNode.GetFileInfo();
|
||||||
|
Marshal.Copy(Buffer, FileNode.FileData, (int)Offset, (int)BytesTransferred);
|
||||||
|
|
||||||
|
Host.SendWriteResponse(RequestHint, STATUS_SUCCESS, BytesTransferred, ref FileInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlowioReadDirectoryTask(
|
||||||
|
Object FileNode0,
|
||||||
|
Object FileDesc,
|
||||||
|
String Pattern,
|
||||||
|
String Marker,
|
||||||
|
IntPtr Buffer,
|
||||||
|
UInt32 Length,
|
||||||
|
UInt64 RequestHint)
|
||||||
|
{
|
||||||
|
SlowioSnooze();
|
||||||
|
|
||||||
|
UInt32 BytesTransferred;
|
||||||
|
var Status = base.SeekableReadDirectory(FileNode0, FileDesc, Pattern, Marker, Buffer, Length, out BytesTransferred);
|
||||||
|
Host.SendReadDirectoryResponse(RequestHint, Status, BytesTransferred);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public override Int32 Read(
|
public override Int32 Read(
|
||||||
Object FileNode0,
|
Object FileNode0,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
@ -570,6 +663,17 @@ namespace memfs
|
|||||||
if (EndOffset > FileNode.FileInfo.FileSize)
|
if (EndOffset > FileNode.FileInfo.FileSize)
|
||||||
EndOffset = FileNode.FileInfo.FileSize;
|
EndOffset = FileNode.FileInfo.FileSize;
|
||||||
|
|
||||||
|
#if MEMFS_SLOWIO
|
||||||
|
if (SlowioReturnPending())
|
||||||
|
{
|
||||||
|
var Hint = Host.GetOperationRequestHint();
|
||||||
|
Task.Run(() => SlowioReadTask(FileNode0, Buffer, Offset, EndOffset, Hint)).ConfigureAwait(false);
|
||||||
|
|
||||||
|
BytesTransferred = 0;
|
||||||
|
return STATUS_PENDING;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
BytesTransferred = (UInt32)(EndOffset - Offset);
|
BytesTransferred = (UInt32)(EndOffset - Offset);
|
||||||
Marshal.Copy(FileNode.FileData, (int)Offset, Buffer, (int)BytesTransferred);
|
Marshal.Copy(FileNode.FileData, (int)Offset, Buffer, (int)BytesTransferred);
|
||||||
|
|
||||||
@ -619,6 +723,18 @@ namespace memfs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MEMFS_SLOWIO
|
||||||
|
if (SlowioReturnPending())
|
||||||
|
{
|
||||||
|
var hint = Host.GetOperationRequestHint();
|
||||||
|
Task.Run(() => SlowioWriteTask(FileNode0, Buffer, Offset, EndOffset, hint)).ConfigureAwait(false);
|
||||||
|
|
||||||
|
BytesTransferred = 0;
|
||||||
|
FileInfo = default(FileInfo);
|
||||||
|
return STATUS_PENDING;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
BytesTransferred = (UInt32)(EndOffset - Offset);
|
BytesTransferred = (UInt32)(EndOffset - Offset);
|
||||||
Marshal.Copy(Buffer, FileNode.FileData, (int)Offset, (int)BytesTransferred);
|
Marshal.Copy(Buffer, FileNode.FileData, (int)Offset, (int)BytesTransferred);
|
||||||
|
|
||||||
@ -902,6 +1018,29 @@ namespace memfs
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MEMFS_SLOWIO
|
||||||
|
public override int SeekableReadDirectory(
|
||||||
|
Object FileNode0,
|
||||||
|
Object FileDesc,
|
||||||
|
String Pattern,
|
||||||
|
String Marker,
|
||||||
|
IntPtr Buffer,
|
||||||
|
UInt32 Length,
|
||||||
|
out UInt32 BytesTransferred)
|
||||||
|
{
|
||||||
|
if (SlowioReturnPending())
|
||||||
|
{
|
||||||
|
var Hint = Host.GetOperationRequestHint();
|
||||||
|
Task.Run(() => SlowioReadDirectoryTask(FileNode0, FileDesc, Pattern, Marker, Buffer, Length, Hint));
|
||||||
|
BytesTransferred = 0;
|
||||||
|
|
||||||
|
return STATUS_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.SeekableReadDirectory(FileNode0, FileDesc, Pattern, Marker, Buffer, Length, out BytesTransferred);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public override int GetDirInfoByName(
|
public override int GetDirInfoByName(
|
||||||
Object ParentNode0,
|
Object ParentNode0,
|
||||||
Object FileDesc,
|
Object FileDesc,
|
||||||
@ -1140,6 +1279,9 @@ namespace memfs
|
|||||||
private FileNodeMap FileNodeMap;
|
private FileNodeMap FileNodeMap;
|
||||||
private UInt32 MaxFileNodes;
|
private UInt32 MaxFileNodes;
|
||||||
private UInt32 MaxFileSize;
|
private UInt32 MaxFileSize;
|
||||||
|
private UInt64 SlowioMaxDelay;
|
||||||
|
private UInt64 SlowioPercentDelay;
|
||||||
|
private UInt64 SlowioRarefyDelay;
|
||||||
private String VolumeLabel;
|
private String VolumeLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1170,6 +1312,9 @@ namespace memfs
|
|||||||
UInt32 FileInfoTimeout = unchecked((UInt32)(-1));
|
UInt32 FileInfoTimeout = unchecked((UInt32)(-1));
|
||||||
UInt32 MaxFileNodes = 1024;
|
UInt32 MaxFileNodes = 1024;
|
||||||
UInt32 MaxFileSize = 16 * 1024 * 1024;
|
UInt32 MaxFileSize = 16 * 1024 * 1024;
|
||||||
|
UInt32 SlowioMaxDelay = 0;
|
||||||
|
UInt32 SlowioPercentDelay = 0;
|
||||||
|
UInt32 SlowioRarefyDelay = 0;
|
||||||
String FileSystemName = null;
|
String FileSystemName = null;
|
||||||
String VolumePrefix = null;
|
String VolumePrefix = null;
|
||||||
String MountPoint = null;
|
String MountPoint = null;
|
||||||
@ -1202,9 +1347,18 @@ namespace memfs
|
|||||||
case 'm':
|
case 'm':
|
||||||
argtos(Args, ref I, ref MountPoint);
|
argtos(Args, ref I, ref MountPoint);
|
||||||
break;
|
break;
|
||||||
|
case 'M':
|
||||||
|
argtol(Args, ref I, ref SlowioMaxDelay);
|
||||||
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
argtol(Args, ref I, ref MaxFileNodes);
|
argtol(Args, ref I, ref MaxFileNodes);
|
||||||
break;
|
break;
|
||||||
|
case 'P':
|
||||||
|
argtol(Args, ref I, ref SlowioPercentDelay);
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
argtol(Args, ref I, ref SlowioRarefyDelay);
|
||||||
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
argtos(Args, ref I, ref RootSddl);
|
argtos(Args, ref I, ref RootSddl);
|
||||||
break;
|
break;
|
||||||
@ -1233,7 +1387,8 @@ namespace memfs
|
|||||||
throw new CommandLineUsageException("cannot open debug log file");
|
throw new CommandLineUsageException("cannot open debug log file");
|
||||||
|
|
||||||
Host = new FileSystemHost(Memfs = new Memfs(
|
Host = new FileSystemHost(Memfs = new Memfs(
|
||||||
CaseInsensitive, MaxFileNodes, MaxFileSize, RootSddl));
|
CaseInsensitive, MaxFileNodes, MaxFileSize, RootSddl,
|
||||||
|
SlowioMaxDelay, SlowioPercentDelay, SlowioRarefyDelay));
|
||||||
Host.FileInfoTimeout = FileInfoTimeout;
|
Host.FileInfoTimeout = FileInfoTimeout;
|
||||||
Host.Prefix = VolumePrefix;
|
Host.Prefix = VolumePrefix;
|
||||||
Host.FileSystemName = null != FileSystemName ? FileSystemName : "-MEMFS";
|
Host.FileSystemName = null != FileSystemName ? FileSystemName : "-MEMFS";
|
||||||
@ -1262,6 +1417,9 @@ namespace memfs
|
|||||||
" -t FileInfoTimeout [millis]\n" +
|
" -t FileInfoTimeout [millis]\n" +
|
||||||
" -n MaxFileNodes\n" +
|
" -n MaxFileNodes\n" +
|
||||||
" -s MaxFileSize [bytes]\n" +
|
" -s MaxFileSize [bytes]\n" +
|
||||||
|
" -M MaxDelay [maximum slow IO delay in millis]\n" +
|
||||||
|
" -P PercentDelay [percent of slow IO to make pending]\n" +
|
||||||
|
" -R RarefyDelay [adjust the rarity of pending slow IO]\n" +
|
||||||
" -F FileSystemName\n" +
|
" -F FileSystemName\n" +
|
||||||
" -S RootSddl [file rights: FA, etc; NO generic rights: GA, etc.]\n" +
|
" -S RootSddl [file rights: FA, etc; NO generic rights: GA, etc.]\n" +
|
||||||
" -u \\Server\\Share [UNC prefix (single backslash)]\n" +
|
" -u \\Server\\Share [UNC prefix (single backslash)]\n" +
|
||||||
|
Loading…
x
Reference in New Issue
Block a user