protected override async Task LogReceiveImplAsync(IReadOnlyList <LogServerReceivedData> dataList) { SingletonSlim <string, MemoryBuffer <byte> > writeBufferList = new SingletonSlim <string, MemoryBuffer <byte> >((filename) => new MemoryBuffer <byte>(), this.Options.DestFileSystem.PathParser.PathStringComparer); foreach (var data in dataList) { Options.SetDestinationsProc(data, this.Options); foreach (string fileName in data.DestFileNames) { var buffer = writeBufferList[fileName]; buffer.Write(data.BinaryData); buffer.Write(Str.NewLine_Bytes_Windows); } } bool firstFlag = false; // 2020/8/17 パスで並び替えるようにしてみた (そのほうがファイルシステム上高速だという仮定) foreach (string fileName in writeBufferList.Keys.OrderBy(x => x, this.Options.DestFileSystem.PathParser.PathStringComparer)) { try { MemoryBuffer <byte>?buffer = writeBufferList[fileName]; if (buffer != null) { if (firstFlag == false) { // ファイルシステム API が同期モードになっておりディスク I/O に長時間かかる場合を想定し、 // 呼び出し元の非同期ソケットタイムアウト検出がおかしくなる問題がありえるため // 1 回は必ず Yield する firstFlag = true; await Task.Yield(); } await Options.DestFileSystem.ConcurrentSafeAppendDataToFileAsync(fileName, buffer.Memory, this.Options.FileFlags | FileFlags.AutoCreateDirectory); } } catch (Exception ex) { Con.WriteError($"LogReceiveImplAsync: Filename '{fileName}' write error: {ex.ToString()}"); } } }
protected override async Task LogReceiveImplAsync(IReadOnlyList <LogServerReceivedData> dataList) { SingletonSlim <string, MemoryBuffer <byte> > writeBufferList = new SingletonSlim <string, MemoryBuffer <byte> >((filename) => new MemoryBuffer <byte>(), this.Options.DestFileSystem.PathParser.PathStringComparer); foreach (LogServerReceivedData data in dataList) { Options.SetDestinationsProc(data, this.Options); foreach (string fileName in data.DestFileNames) { var buffer = writeBufferList[fileName]; buffer.Write(data.BinaryData); buffer.Write(Str.NewLine_Bytes_Windows); } } foreach (string fileName in writeBufferList.Keys) { try { var buffer = writeBufferList[fileName]; var handle = await Options.DestFileSystem.GetRandomAccessHandleAsync(fileName, true, this.Options.FileFlags | FileFlags.AutoCreateDirectory); var concurrentHandle = handle.GetConcurrentRandomAccess(); await concurrentHandle.AppendAsync(buffer.Memory); await concurrentHandle.FlushAsync(); } catch (Exception ex) { Con.WriteDebug($"LogReceiveImplAsync: Filename '{fileName}' write error: {ex.ToString()}"); } } }
protected override async Task DataVaultReceiveImplAsync(IReadOnlyList <DataVaultServerReceivedData> dataList) { SingletonSlim <string, MemoryBuffer <byte> > writeBufferList = new SingletonSlim <string, MemoryBuffer <byte> >((filename) => new MemoryBuffer <byte>(), this.Options.DestFileSystem.PathParser.PathStringComparer); foreach (var data in dataList) { Options.SetDestinationsProc(data, this.Options); foreach (string fileName in data.DestFileNames) { var buffer = writeBufferList[fileName]; buffer.Write(data.BinaryData); buffer.Write(Str.NewLine_Bytes_Windows); } } bool firstFlag = false; // 2020/8/17 パスで並び替えるようにしてみた (そのほうがファイルシステム上高速だという仮定) foreach (string fileName in writeBufferList.Keys.OrderBy(x => x, this.Options.DestFileSystem.PathParser.PathStringComparer)) { try { MemoryBuffer <byte>?buffer = writeBufferList[fileName]; if (buffer != null) { if (firstFlag == false) { // ファイルシステム API が同期モードになっておりディスク I/O に長時間かかる場合を想定し、 // 呼び出し元の非同期ソケットタイムアウト検出がおかしくなる問題がありえるため // 1 回は必ず Yield する firstFlag = true; await Task.Yield(); } if (Options.ServerFlags.Bit(DataVaultServerFlags.UseConcurrentSafeAppendDataToFileAsync) == false) { // 従来のモード。動作重い? btrfs がバグる var handle = await Options.DestFileSystem.GetRandomAccessHandleAsync(fileName, true, this.Options.FileFlags | FileFlags.AutoCreateDirectory); var concurrentHandle = handle.GetConcurrentRandomAccess(); await concurrentHandle.AppendWithLargeFsAutoPaddingAsync(buffer.Memory); await concurrentHandle.FlushAsync(); } else { // 新しいモード。軽いことを期待 2020/8/16 await Options.DestFileSystem.ConcurrentSafeAppendDataToFileAsync(fileName, buffer.Memory, this.Options.FileFlags | FileFlags.AutoCreateDirectory); } } } catch (Exception ex) { Con.WriteError($"DataVaultReceiveImplAsync: Filename '{fileName}' write error: {ex.ToString()}"); } } }