/// <summary> /// Constructor with more options for derived classes /// </summary> /// <param name="filename">File name (or prefix) with path</param> /// <param name="preallocateFile"></param> /// <param name="deleteOnClose"></param> /// <param name="disableFileBuffering"></param> /// <param name="capacity">The maximum number of bytes this storage device can accommondate, or CAPACITY_UNSPECIFIED if there is no such limit </param> /// <param name="recoverDevice">Whether to recover device metadata from existing files</param> /// <param name="initialLogFileHandles">Optional set of preloaded safe file handles, which can speed up hydration of preexisting log file handles</param> /// <param name="useIoCompletionPort">Whether we use IO completion port with polling</param> protected internal LocalStorageDevice(string filename, bool preallocateFile = false, bool deleteOnClose = false, bool disableFileBuffering = true, long capacity = Devices.CAPACITY_UNSPECIFIED, bool recoverDevice = false, IEnumerable <KeyValuePair <int, SafeFileHandle> > initialLogFileHandles = null, bool useIoCompletionPort = true) : base(filename, GetSectorSize(filename), capacity) { #if NETSTANDARD || NET if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { throw new FasterException("Cannot use LocalStorageDevice from non-Windows OS platform, use ManagedLocalStorageDevice instead."); } #endif ThrottleLimit = 120; this.useIoCompletionPort = useIoCompletionPort; this._disposed = false; if (useIoCompletionPort) { ThreadPool.GetMaxThreads(out int workerThreads, out _); ioCompletionPort = Native32.CreateIoCompletionPort(new SafeFileHandle(new IntPtr(-1), false), IntPtr.Zero, UIntPtr.Zero, (uint)(workerThreads + NumCompletionThreads)); for (int i = 0; i < NumCompletionThreads; i++) { var thread = new Thread(() => new LocalStorageDeviceCompletionWorker().Start(ioCompletionPort, _callback)) { IsBackground = true }; thread.Start(); } } if (UsePrivileges && preallocateFile) { Native32.EnableProcessPrivileges(); } string path = new FileInfo(filename).Directory.FullName; if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } this.preallocateFile = preallocateFile; this.deleteOnClose = deleteOnClose; this.disableFileBuffering = disableFileBuffering; this.results = new ConcurrentQueue <SimpleAsyncResult>(); logHandles = initialLogFileHandles != null ? new SafeConcurrentDictionary <int, SafeFileHandle>(initialLogFileHandles) : new SafeConcurrentDictionary <int, SafeFileHandle>(); if (recoverDevice) { RecoverFiles(); } }
/// <summary> /// Creates a SafeFileHandle for the specified segment. This can be used by derived classes to prepopulate logHandles in the constructor. /// </summary> protected internal static SafeFileHandle CreateHandle(int segmentId, bool disableFileBuffering, bool deleteOnClose, bool preallocateFile, long segmentSize, string fileName, IntPtr ioCompletionPort) { uint fileAccess = Native32.GENERIC_READ | Native32.GENERIC_WRITE; uint fileShare = unchecked (((uint)FileShare.ReadWrite & ~(uint)FileShare.Inheritable)); uint fileCreation = unchecked ((uint)FileMode.OpenOrCreate); uint fileFlags = Native32.FILE_FLAG_OVERLAPPED; if (disableFileBuffering) { fileFlags = fileFlags | Native32.FILE_FLAG_NO_BUFFERING; } if (deleteOnClose) { fileFlags = fileFlags | Native32.FILE_FLAG_DELETE_ON_CLOSE; // FILE_SHARE_DELETE allows multiple FASTER instances to share a single log directory and each can specify deleteOnClose. // This will allow the files to persist until all handles across all instances have been closed. fileShare = fileShare | Native32.FILE_SHARE_DELETE; } var logHandle = Native32.CreateFileW( GetSegmentName(fileName, segmentId), fileAccess, fileShare, IntPtr.Zero, fileCreation, fileFlags, IntPtr.Zero); if (logHandle.IsInvalid) { var error = Marshal.GetLastWin32Error(); throw new IOException($"Error creating log file for {GetSegmentName(fileName, segmentId)}, error: {error}", Native32.MakeHRFromErrorCode(error)); } if (preallocateFile && segmentSize != -1) { SetFileSize(fileName, logHandle, segmentSize); } if (ioCompletionPort != IntPtr.Zero) { ThreadPool.GetMaxThreads(out int workerThreads, out _); Native32.CreateIoCompletionPort(logHandle, ioCompletionPort, (UIntPtr)(long)logHandle.DangerousGetHandle(), (uint)(workerThreads + NumCompletionThreads)); } else { try { ThreadPool.BindHandle(logHandle); } catch (Exception e) { throw new FasterException("Error binding log handle for " + GetSegmentName(fileName, segmentId) + ": " + e.ToString()); } } return(logHandle); }
private SafeFileHandle GetOrAddHandle(int _segmentId) { return(logHandles.GetOrAdd(_segmentId, segmentId => { uint fileAccess = Native32.GENERIC_READ | Native32.GENERIC_WRITE; uint fileShare = unchecked (((uint)FileShare.ReadWrite & ~(uint)FileShare.Inheritable)); uint fileCreation = unchecked ((uint)FileMode.OpenOrCreate); uint fileFlags = Native32.FILE_FLAG_OVERLAPPED; if (unbuffered) { fileFlags = fileFlags | Native32.FILE_FLAG_NO_BUFFERING; } if (deleteOnClose) { fileFlags = fileFlags | Native32.FILE_FLAG_DELETE_ON_CLOSE; } var logHandle = Native32.CreateFileW( GetSegmentName(segmentId), fileAccess, fileShare, IntPtr.Zero, fileCreation, fileFlags, IntPtr.Zero); if (enablePrivileges) { Native32.EnableVolumePrivileges(ref dirname, logHandle); } SetFileSize(logHandle, segmentSize); if (useIoCompletionPort) { ioCompletionPort = Native32.CreateIoCompletionPort( logHandle, IntPtr.Zero, (uint)logHandle.DangerousGetHandle().ToInt64(), 0); } try { ThreadPool.BindHandle(logHandle); } catch (Exception e) { Console.WriteLine("Log handle! : {0}", logHandle.ToString()); Console.WriteLine(e.ToString()); Environment.Exit(0); } return logHandle; })); }
public LocalStorageDevice(string filename, bool enablePrivileges = false, bool useIoCompletionPort = false, bool unbuffered = false, bool deleteOnClose = false) { this.filename = filename; this.enablePrivileges = enablePrivileges; this.useIoCompletionPort = useIoCompletionPort; if (enablePrivileges) { Native32.EnableProcessPrivileges(); } Native32.GetDiskFreeSpace(filename.Substring(0, 3), out lpSectorsPerCluster, out lpBytesPerSector, out lpNumberOfFreeClusters, out lpTotalNumberOfClusters); uint fileAccess = Native32.GENERIC_READ | Native32.GENERIC_WRITE; uint fileShare = unchecked (((uint)FileShare.ReadWrite & ~(uint)FileShare.Inheritable)); uint fileCreation = unchecked ((uint)FileMode.OpenOrCreate); uint fileFlags = Native32.FILE_FLAG_OVERLAPPED; if (unbuffered) { fileFlags = fileFlags | Native32.FILE_FLAG_NO_BUFFERING; } if (deleteOnClose) { fileFlags = fileFlags | Native32.FILE_FLAG_DELETE_ON_CLOSE; } logHandle = Native32.CreateFileW(filename, fileAccess, fileShare, IntPtr.Zero, fileCreation, fileFlags, IntPtr.Zero); if (enablePrivileges) { Native32.EnableVolumePrivileges(ref filename, logHandle); } if (useIoCompletionPort) { ioCompletionPort = Native32.CreateIoCompletionPort( logHandle, IntPtr.Zero, (uint)logHandle.DangerousGetHandle().ToInt64(), 0); } try { ThreadPool.BindHandle(logHandle); } catch (Exception e) { Console.WriteLine("Log handle! : {0}", logHandle.ToString()); Console.WriteLine(e.ToString()); Environment.Exit(0); } }