OutputFileWriter
using Microsoft.VisualBasic.CompilerServices;
using Relativity.DataExchange.Io;
using Relativity.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
namespace kCura.WinEDDS
{
public class OutputFileWriter : IDisposable
{
private const int _MAXIMUM_NUMBER_OF_ITEMS_IN_QUEUE = 12;
private readonly Queue<string> _createdFilesPaths;
private readonly object _syncRoot;
private readonly ILog _logger;
private readonly IFileSystem _fileSystem;
private bool _filesCreated;
private bool _filesOpened;
private long _nativeFileWriterRollbackPos;
private long _dataGridFileWriterRollbackPos;
private bool _disposed;
[CompilerGenerated]
private string _OutputNativeFilePath;
[CompilerGenerated]
private string _OutputDataGridFilePath;
[CompilerGenerated]
private string _OutputCodeFilePath;
[CompilerGenerated]
private string _OutputObjectFilePath;
[CompilerGenerated]
private IStreamWriter _OutputNativeFileWriter;
[CompilerGenerated]
private IStreamWriter _OutputDataGridFileWriter;
[CompilerGenerated]
private IStreamWriter _OutputCodeFileWriter;
[CompilerGenerated]
private IStreamWriter _OutputObjectFileWriter;
public string OutputNativeFilePath { get; }
public string OutputDataGridFilePath { get; }
public string OutputCodeFilePath { get; }
public string OutputObjectFilePath { get; }
public IStreamWriter OutputNativeFileWriter { get; }
public IStreamWriter OutputDataGridFileWriter { get; }
public IStreamWriter OutputCodeFileWriter { get; }
public IStreamWriter OutputObjectFileWriter { get; }
public long CombinedStreamLength {
get {
object syncRoot = _syncRoot;
ObjectFlowControl.CheckForSyncLockOnValueType(syncRoot);
bool lockTaken = false;
try {
Monitor.Enter(syncRoot, ref lockTaken);
if (OutputNativeFileWriter != null && OutputDataGridFileWriter != null) {
if (OutputNativeFileWriter.BaseStream != null && OutputDataGridFileWriter.BaseStream != null)
return checked(OutputNativeFileWriter.BaseStream.Length + OutputDataGridFileWriter.BaseStream.Length);
return 0;
}
return 0;
} finally {
if (lockTaken)
Monitor.Exit(syncRoot);
}
}
}
public OutputFileWriter(ILog logger, IFileSystem fileSystem)
{
_createdFilesPaths = new Queue<string>();
_syncRoot = RuntimeHelpers.GetObjectValue(new object());
if (logger == null)
throw new ArgumentNullException("logger");
if (fileSystem == null)
throw new ArgumentNullException("fileSystem");
_disposed = false;
_filesCreated = false;
_filesOpened = false;
_fileSystem = fileSystem;
_logger = logger.ForContext<OutputFileWriter>();
}
public void DeleteFiles()
{
object syncRoot = _syncRoot;
ObjectFlowControl.CheckForSyncLockOnValueType(syncRoot);
bool lockTaken = false;
try {
Monitor.Enter(syncRoot, ref lockTaken);
CheckDispose();
if (_filesOpened) {
_logger.LogWarning("An attempt was made to delete temp files while they were still open. Trying to close.", new object[0]);
CloseWithoutLocking();
}
DeleteFilesWithoutLocking();
} finally {
if (lockTaken)
Monitor.Exit(syncRoot);
}
}
public void Dispose()
{
object syncRoot = _syncRoot;
ObjectFlowControl.CheckForSyncLockOnValueType(syncRoot);
bool lockTaken = false;
try {
Monitor.Enter(syncRoot, ref lockTaken);
Dispose(true);
GC.SuppressFinalize(this);
} finally {
if (lockTaken)
Monitor.Exit(syncRoot);
}
}
void IDisposable.Dispose()
{
this.Dispose();
}
public void Open(bool append = false)
{
object syncRoot = _syncRoot;
ObjectFlowControl.CheckForSyncLockOnValueType(syncRoot);
bool lockTaken = false;
try {
Monitor.Enter(syncRoot, ref lockTaken);
CheckDispose();
OpenWithoutLocking(append);
} finally {
if (lockTaken)
Monitor.Exit(syncRoot);
}
}
public void Close()
{
object syncRoot = _syncRoot;
ObjectFlowControl.CheckForSyncLockOnValueType(syncRoot);
bool lockTaken = false;
try {
Monitor.Enter(syncRoot, ref lockTaken);
CheckDispose();
CloseWithoutLocking();
} finally {
if (lockTaken)
Monitor.Exit(syncRoot);
}
}
public void MarkRollbackPosition()
{
object syncRoot = _syncRoot;
ObjectFlowControl.CheckForSyncLockOnValueType(syncRoot);
bool lockTaken = false;
try {
Monitor.Enter(syncRoot, ref lockTaken);
CheckDispose();
if (OutputNativeFileWriter != null && OutputNativeFileWriter.BaseStream != null) {
OutputNativeFileWriter.Flush();
_nativeFileWriterRollbackPos = OutputNativeFileWriter.BaseStream.Length;
}
if (OutputDataGridFileWriter != null && OutputDataGridFileWriter.BaseStream != null) {
OutputDataGridFileWriter.Flush();
_dataGridFileWriterRollbackPos = OutputDataGridFileWriter.BaseStream.Length;
}
} finally {
if (lockTaken)
Monitor.Exit(syncRoot);
}
}
public void RollbackDocumentLineWrites()
{
object syncRoot = _syncRoot;
ObjectFlowControl.CheckForSyncLockOnValueType(syncRoot);
bool lockTaken = false;
try {
Monitor.Enter(syncRoot, ref lockTaken);
CheckDispose();
CloseWithoutLocking();
SetStreamLengths();
OpenWithoutLocking(true);
} finally {
if (lockTaken)
Monitor.Exit(syncRoot);
}
}
public int TryCloseAndDeleteAllTempFiles()
{
object syncRoot = _syncRoot;
ObjectFlowControl.CheckForSyncLockOnValueType(syncRoot);
bool lockTaken = false;
try {
Monitor.Enter(syncRoot, ref lockTaken);
CheckDispose();
return TryCloseAndDeleteAllTempFilesWithoutLocking();
} finally {
if (lockTaken)
Monitor.Exit(syncRoot);
}
}
private void OpenWithoutLocking(bool append)
{
if (!_filesOpened) {
if (!_filesCreated)
CreateTempFiles();
_OutputNativeFileWriter = _fileSystem.CreateStreamWriter(OutputNativeFilePath, append, Encoding.Unicode);
_OutputDataGridFileWriter = _fileSystem.CreateStreamWriter(OutputDataGridFilePath, append, Encoding.Unicode);
_OutputCodeFileWriter = _fileSystem.CreateStreamWriter(OutputCodeFilePath, append, Encoding.Unicode);
_OutputObjectFileWriter = _fileSystem.CreateStreamWriter(OutputObjectFilePath, append, Encoding.Unicode);
_filesOpened = true;
}
}
private void CloseWithoutLocking()
{
if (_filesOpened) {
TryCloseWriter(OutputNativeFileWriter);
_OutputNativeFileWriter = null;
TryCloseWriter(OutputDataGridFileWriter);
_OutputDataGridFileWriter = null;
TryCloseWriter(OutputCodeFileWriter);
_OutputCodeFileWriter = null;
TryCloseWriter(OutputObjectFileWriter);
_OutputObjectFileWriter = null;
_filesOpened = false;
}
}
private void DeleteFilesWithoutLocking()
{
_OutputNativeFilePath = null;
_OutputDataGridFilePath = null;
_OutputCodeFilePath = null;
_OutputObjectFilePath = null;
_filesCreated = false;
int count = _createdFilesPaths.Count;
for (int i = 1; i <= count; i = checked(i + 1)) {
string text = _createdFilesPaths.Dequeue();
try {
_fileSystem.File.Delete(text);
} catch (IOException ex) when () {
IOException ex2;
_logger.LogWarning((Exception)ex2, "Unable to delete file because it was locked. Adding to queue for retry.", new object[0]);
_createdFilesPaths.Enqueue(text);
ProjectData.ClearProjectError();
}
}
EnsureCreatedFilesQueueSizeLimit();
}
private void EnsureCreatedFilesQueueSizeLimit()
{
checked {
int num = Math.Max(0, _createdFilesPaths.Count - 12);
for (int i = 1; i <= num; i++) {
_createdFilesPaths.Dequeue();
}
}
}
private int TryCloseAndDeleteAllTempFilesWithoutLocking()
{
CloseWithoutLocking();
DeleteFilesWithoutLocking();
return _createdFilesPaths.Count;
}
private void SetStreamLengths()
{
using (FileStream fileStream = new FileStream(OutputNativeFilePath, FileMode.Open, FileAccess.ReadWrite)) {
fileStream.SetLength(_nativeFileWriterRollbackPos);
fileStream.Close();
}
using (FileStream fileStream2 = new FileStream(OutputDataGridFilePath, FileMode.Open, FileAccess.ReadWrite)) {
fileStream2.SetLength(_dataGridFileWriterRollbackPos);
fileStream2.Close();
}
}
private void CreateTempFiles()
{
_OutputNativeFilePath = CreateTempFile("rel-native");
_OutputDataGridFilePath = CreateTempFile("rel-datagrid");
_OutputCodeFilePath = CreateTempFile("rel-code");
_OutputObjectFilePath = CreateTempFile("rel-object");
_filesCreated = true;
}
private string CreateTempFile(string nameSuffix)
{
string tempFileName = _fileSystem.Path.GetTempFileName(nameSuffix);
_createdFilesPaths.Enqueue(tempFileName);
return tempFileName;
}
private void TryCloseWriter(IStreamWriter writer)
{
if (writer != null)
try {
writer.Close();
} catch (Exception ex) {
ProjectData.SetProjectError(ex);
Exception ex2 = ex;
_logger.LogWarning(ex2, "Exception was thrown while trying to close stream writer.", new object[0]);
ProjectData.ClearProjectError();
}
}
private void CheckDispose()
{
if (_disposed)
throw new ObjectDisposedException("This load file operation cannot be performed because the load file writer has been disposed.");
}
private void Dispose(bool disposing)
{
if (!_disposed && disposing)
try {
TryCloseAndDeleteAllTempFilesWithoutLocking();
} finally {
_disposed = true;
}
}
private static bool IsExceptionDueToLockedFile(IOException exception)
{
int num = exception.HResult & 65535;
if (num != 32)
return num == 33;
return true;
}
}
}