private static void ReadLineFromFile(LineParam lineParam) { Utility.PerformIOWithRetries( ctx => { LineParam param = ctx; param.Line = param.Reader.ReadLine(); }, lineParam); }
internal void OnEtlFileReadStop(string fileName, bool isActiveEtl, string currentBookmark, string nextBookmark, bool fileReadAborted) { if (null == this.streamWriter) { // An error occurred during the creation of the buffered event // file. So just return immediately without doing anything. return; } if (false == fileReadAborted) { // Flush pending events this.FlushPendingEvents(isActiveEtl, currentBookmark, nextBookmark); } // We're done processing an ETL file. Before this ETL file is moved // to the archives, make sure all the events we've written so far are // flushed to the buffered event file. try { Utility.PerformIOWithRetries( () => { try { this.streamWriter.Flush(); } catch (System.Text.EncoderFallbackException ex) { // This can happen if the manifest file does not match the binary. // Write an error message and move on. this.TraceSource.WriteError( this.LogSourceId, "Exception occurred while flushing filtered ETW events to buffered event file. Exception information: {0}", ex); } }); } catch (Exception e) { // Log an error and move on this.TraceSource.WriteExceptionAsError( this.LogSourceId, e, "Failed to flush data to buffered event file."); } }
internal static void Compress(string source, string archiveEntryName, out string tempArchivePath) { string archiveFullPath = Utility.GetTempFileName(); Utility.PerformIOWithRetries( () => { using (FileStream fs = new FileStream(archiveFullPath, FileMode.Create)) { // ZipArchive archive; object archive = null; try { try { // archive = new ZipArchive(fs, ZipArchiveMode.Create); archive = ZipArchiveConstructor.Invoke(new[] { fs, ZipArchiveModeCreate }); // archive.CreateEntryFromFile(source, archiveEntryName, CompressionLevel.Optimal); ZipFileExtCreateEntryFromFile.Invoke( null, new[] { archive, source, archiveEntryName, CompressionLevelOptimal }); } catch (TargetInvocationException e) { throw e.InnerException; } } finally { if (null != archive) { // archive.Dispose(); ZipArchiveDispose.Invoke(archive, null); } } } }); tempArchivePath = archiveFullPath; }
private bool LoadFromFile() { // Open the map file StreamReader reader = null; bool mapFileNotPresent = false; try { Utility.PerformIOWithRetries( () => { try { FileStream fileStream = FabricFile.Open(this.fileFullPath, FileMode.Open, FileAccess.Read); #if !DotNetCoreClrLinux Helpers.SetIoPriorityHint(fileStream.SafeFileHandle, Kernel32Types.PRIORITY_HINT.IoPriorityHintVeryLow); #endif reader = new StreamReader(fileStream); } catch (FileNotFoundException) { mapFileNotPresent = true; } catch (DirectoryNotFoundException) { mapFileNotPresent = true; } }); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Unable to open index map file {0}", this.fileFullPath); return(false); } if (mapFileNotPresent) { return(true); } try { // Get the version line string versionLine = string.Empty; try { Utility.PerformIOWithRetries( () => { versionLine = reader.ReadLine(); }); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Unable to read version line from index map file {0}", this.fileFullPath); return(false); } if (null == versionLine) { this.traceSource.WriteError( this.logSourceId, "Index map file {0} does not contain a version line.", this.fileFullPath); return(false); } // Ensure that the version line is compatible string versionString = versionLine.Remove(0, VersionPrefix.Length); int version; if (false == int.TryParse( versionString, out version)) { this.traceSource.WriteError( this.logSourceId, "Version {0} in index map file {1} cannot be parsed as an integer.", versionString, this.fileFullPath); return(false); } if (version != this.fileFormatVersion) { this.traceSource.WriteError( this.logSourceId, "Index map file {0} has incompatible file version '{1}'.", this.fileFullPath, version); return(false); } // Read the map records from the file string mapRecord = null; for (;;) { mapRecord = string.Empty; try { Utility.PerformIOWithRetries( () => { mapRecord = reader.ReadLine(); }); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Unable to retrieve record from index map file {0}", this.fileFullPath); return(false); } if (null == mapRecord) { // Reached end of file this.traceSource.WriteInfo( this.logSourceId, "Reached end of index map file {0}", this.fileFullPath); break; } this.ProcessMapRecord(mapRecord, this.fileFullPath); } } finally { reader.Dispose(); } return(true); }
private bool SaveToFile() { // Create a new temp file string tempFilePath = Utility.GetTempFileName(); try { // Open the temp file StreamWriter writer = null; try { Utility.PerformIOWithRetries( () => { FileStream fileStream = FabricFile.Open(tempFilePath, FileMode.Create, FileAccess.Write); #if !DotNetCoreClrLinux Helpers.SetIoPriorityHint(fileStream.SafeFileHandle, Kernel32Types.PRIORITY_HINT.IoPriorityHintVeryLow); #endif writer = new StreamWriter(fileStream); }); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Failed to open temp file {0} for persisting index map.", tempFilePath); return(false); } try { // Write the version information to the map file string versionString = string.Concat(VersionPrefix, this.fileFormatVersion.ToString(CultureInfo.InvariantCulture)); try { Utility.PerformIOWithRetries( () => { writer.WriteLine(versionString); }); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Failed to write version information to temp file {0} for persisting index map.", tempFilePath); return(false); } // Write the map records to the map file foreach (TItem item in this.dictionary.Keys) { string mapRecord = string.Concat( item.ToString(), ", ", this.dictionary[item].ToString(CultureInfo.InvariantCulture)); try { Utility.PerformIOWithRetries( () => { writer.WriteLine(mapRecord); }); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Failed to write record {0} to temp file {1} for persisting index map.", mapRecord, tempFilePath); return(false); } } } finally { writer.Dispose(); } // Copy the temp file as the new map file try { Utility.PerformIOWithRetries( () => { FabricFile.Copy(tempFilePath, this.fileFullPath, true); }); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Failed to copy file {0} to {1} for persisting index map", tempFilePath, this.fileFullPath); return(false); } this.traceSource.WriteInfo( this.logSourceId, "Index map file {0} created.", this.fileFullPath); } finally { try { Utility.PerformIOWithRetries( () => { FabricFile.Delete(tempFilePath); }); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Failed to delete temp file {0} which was created for persisting index map.", tempFilePath); } } return(true); }
private static bool LoadFromFile() { // Open the backup file StreamReader reader = null; bool backupFileNotPresent = false; try { Utility.PerformIOWithRetries( () => { try { FileStream fileStream = FabricFile.Open(backupFileFullPath, FileMode.Open, FileAccess.Read); #if !DotNetCoreClrLinux Helpers.SetIoPriorityHint(fileStream.SafeFileHandle, Kernel32Types.PRIORITY_HINT.IoPriorityHintVeryLow); #endif reader = new StreamReader(fileStream); } catch (FileNotFoundException) { backupFileNotPresent = true; } catch (DirectoryNotFoundException) { backupFileNotPresent = true; } }); } catch (Exception e) { Utility.TraceSource.WriteExceptionAsError( LogSourceId, e, "Unable to open application activation table backup file {0}", backupFileFullPath); return(false); } if (backupFileNotPresent) { return(true); } try { // Get the version line string versionLine = string.Empty; try { Utility.PerformIOWithRetries( () => { versionLine = reader.ReadLine(); }); } catch (Exception e) { Utility.TraceSource.WriteExceptionAsError( LogSourceId, e, "Unable to read version line from application activation table backup file {0}", backupFileFullPath); return(false); } if (null == versionLine) { Utility.TraceSource.WriteError( LogSourceId, "Application activation table backup file {0} does not contain a version line.", backupFileFullPath); return(false); } // Ensure that the version line is compatible if (false == versionLine.Equals(VersionString, StringComparison.Ordinal)) { Utility.TraceSource.WriteError( LogSourceId, "Application activation table backup file {0} has incompatible file version '{1}'.", backupFileFullPath, versionLine); return(false); } // Read the application activation records from the file string activationRecord = null; for (;;) { activationRecord = string.Empty; try { Utility.PerformIOWithRetries( () => { activationRecord = reader.ReadLine(); }); } catch (Exception e) { Utility.TraceSource.WriteExceptionAsError( LogSourceId, e, "Unable to retrieve record from application activation table backup file {0}", backupFileFullPath); return(false); } if (null == activationRecord) { // Reached end of file Utility.TraceSource.WriteInfo( LogSourceId, "Reached end of application activation table backup file {0}", backupFileFullPath); break; } ProcessActivationRecord(activationRecord, backupFileFullPath); } } finally { reader.Dispose(); } return(true); }
private static bool SaveToFile() { // Create a new temp file string tempFilePath = Utility.GetTempFileName(); try { // Open the temp file StreamWriter writer = null; try { Utility.PerformIOWithRetries( () => { FileStream fileStream = FabricFile.Open(tempFilePath, FileMode.Create, FileAccess.Write); #if !DotNetCoreClrLinux Helpers.SetIoPriorityHint(fileStream.SafeFileHandle, Kernel32Types.PRIORITY_HINT.IoPriorityHintVeryLow); #endif writer = new StreamWriter(fileStream); }); } catch (Exception e) { Utility.TraceSource.WriteExceptionAsError( LogSourceId, e, "Failed to open temp file {0} for backing up application activation table.", tempFilePath); return(false); } try { // Write the version information to the backup file try { Utility.PerformIOWithRetries( () => { writer.WriteLine(VersionString); }); } catch (Exception e) { Utility.TraceSource.WriteExceptionAsError( LogSourceId, e, "Failed to write version information to temp file {0} for backing up application activation table.", tempFilePath); return(false); } // Write the activation records to the backup file foreach (string appType in applicationEtwTracesStartTime.Keys) { foreach (string appInstanceId in applicationEtwTracesStartTime[appType].Keys) { DateTime activationTime = applicationEtwTracesStartTime[appType][appInstanceId]; string activationRecord = string.Join( ",", appInstanceId, appType, activationTime.ToBinary().ToString(), activationTime.ToString()); try { Utility.PerformIOWithRetries( () => { writer.WriteLine(activationRecord); }); } catch (Exception e) { Utility.TraceSource.WriteExceptionAsError( LogSourceId, e, "Failed to write record {0} to temp file {1} for backing up application activation table.", activationRecord, tempFilePath); return(false); } } } } finally { writer.Dispose(); } // Copy the temp file as the new backup file try { Utility.PerformIOWithRetries( () => { FabricFile.Copy(tempFilePath, backupFileFullPath, true); }); } catch (Exception e) { Utility.TraceSource.WriteExceptionAsError( LogSourceId, e, "Failed to copy file {0} to {1} for backing up application activation table.", tempFilePath, backupFileFullPath); return(false); } Utility.TraceSource.WriteInfo( LogSourceId, "Application activation table backup file {0} created.", backupFileFullPath); } finally { try { Utility.PerformIOWithRetries( () => { FabricFile.Delete(tempFilePath); }); } catch (Exception e) { Utility.TraceSource.WriteExceptionAsError( LogSourceId, e, "Failed to delete temp file {0} which was created for backing up application activation table.", tempFilePath); } } return(true); }
private void ProcessEventsFromFile(string fileName) { this.TraceSource.WriteInfo( this.LogSourceId, "Processing ETW events from file {0}.", fileName); // Open the file ReadEventsFromFileParam readEventsParam = new ReadEventsFromFileParam(); readEventsParam.StreamReader = null; readEventsParam.FileName = fileName; try { Utility.PerformIOWithRetries( this.OpenEtwEventCacheFile, readEventsParam); } catch (Exception e) { this.TraceSource.WriteExceptionAsError( this.LogSourceId, e, "Failed to open file {0} for read.", fileName); return; } if (readEventsParam.FileNotFound) { Debug.Assert(null == readEventsParam.StreamReader, "StreamReader should remain unset if file is not found."); return; } // Read and process events from the file try { // Check the DCA version to make sure we can parse this file int version; if (false == this.CanParseFile(readEventsParam.StreamReader, fileName, out version)) { return; } // Upload the ETW events that we just retrieved this.TraceSource.WriteInfo( this.LogSourceId, "Starting delivery of ETW events from file {0} ....", fileName); LineParam lineParam = new LineParam(); lineParam.Reader = readEventsParam.StreamReader; for (;;) { // Read an event from the file try { ReadLineFromFile(lineParam); } catch (Exception e) { this.TraceSource.WriteExceptionAsError( this.LogSourceId, e, "Failed to read event from file {0}.", fileName); break; } if (null == lineParam.Line) { // End of file reached break; } DecodedEtwEvent etwEventInfo = new DecodedEtwEvent(); string nodeUniqueEventId = null; if (false == this.ParseEventInfo(fileName, version, lineParam.Line, ref etwEventInfo, ref nodeUniqueEventId)) { // Couldn't parse this event, so skip it and continue with the // remaining events. continue; } // Deliver the event to the consumer this.eventSink.OnEtwEventAvailable(etwEventInfo, nodeUniqueEventId); this.perfHelper.EventDeliveredToConsumer(); // If the consumer has asked for the event delivery period to // be aborted, then do so immediately. if (this.eventDeliveryPeriodAborted) { this.TraceSource.WriteInfo( this.LogSourceId, "The event delivery pass is being aborted. Therefore, no more events will be read from file {0}.", fileName); break; } // If we are in the process of stopping, then don't process // any more events if (this.Stopping) { this.TraceSource.WriteInfo( this.LogSourceId, "The consumer is being stopped. Therefore, no more events will be read from file {0}.", fileName); break; } } this.TraceSource.WriteInfo( this.LogSourceId, "Finished delivery of ETW events from file {0}.", fileName); } finally { readEventsParam.StreamReader.Dispose(); } }
private void WriteTraceEvent(DecodedEventWrapper eventWrapper, string nodesUniqueEventId) { if (null == this.streamWriter) { // An error occurred during the creation of the buffered event // file. So just return immediately without doing anything. return; } // NOTE: The order in which the information is written must match // the order of the EventLineParts enumeration defined in this class. string eventInfo = string.Format( CultureInfo.InvariantCulture, "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15}", eventWrapper.InternalEvent.EventRecord.EventHeader.ProviderId, eventWrapper.InternalEvent.EventRecord.EventHeader.EventDescriptor.Id, eventWrapper.InternalEvent.EventRecord.EventHeader.EventDescriptor.Version, eventWrapper.InternalEvent.EventRecord.EventHeader.EventDescriptor.Channel, eventWrapper.InternalEvent.EventRecord.EventHeader.EventDescriptor.Opcode, eventWrapper.InternalEvent.EventRecord.EventHeader.EventDescriptor.Task, eventWrapper.InternalEvent.EventRecord.EventHeader.EventDescriptor.Keyword, nodesUniqueEventId, eventWrapper.Timestamp.ToBinary(), eventWrapper.Timestamp, // We write the human-readable form for easier debugging eventWrapper.Level, eventWrapper.ThreadId, eventWrapper.ProcessId, eventWrapper.TaskName, eventWrapper.EventType, eventWrapper.EventText); eventInfo = eventInfo.Replace("\r\n", "\t").Replace("\n", "\t").Replace("\r", "\t"); try { Utility.PerformIOWithRetries( ctx => { string eventString = ctx; try { this.streamWriter.WriteLine(eventString); } catch (System.Text.EncoderFallbackException ex) { // This can happen if the manifest file does not match the binary. // Write an error message and move on. this.TraceSource.WriteError( this.LogSourceId, "Exception occurred while writing filtered ETW event to buffered event file. Exception information: {0}", ex); } }, eventInfo); } catch (Exception e) { // Log an error and move on this.TraceSource.WriteExceptionAsError( this.LogSourceId, e, "Failed to write ETW event to buffered event file."); } }
public void OnEtwEventProcessingPeriodStart() { this.streamWriter = null; this.perfHelper.EtlReadPassBegin(); // Build the full path to our buffered event file string tempCacheFileName = string.Format( CultureInfo.InvariantCulture, "{0}{1}.{2}", TempCacheFileNamePrefix, DateTime.Now.Ticks, TempCacheFileExtension); string tempCacheFileFullPath = Path.Combine(this.etwEventCache, tempCacheFileName); // Open the file StreamWriter writer = null; try { Utility.PerformIOWithRetries( ctx => { string fileName = ctx; FileStream fileStream = FabricFile.Open(fileName, FileMode.Create, FileAccess.Write); #if !DotNetCoreClr Helpers.SetIoPriorityHint(fileStream.SafeFileHandle, Kernel32Types.PRIORITY_HINT.IoPriorityHintVeryLow); #endif writer = new StreamWriter(fileStream); }, tempCacheFileFullPath); } catch (Exception e) { // Log an error and move on. No events from this pass will be // written to the destination. this.TraceSource.WriteExceptionAsError( this.LogSourceId, e, "Failed to create a new file in the buffered event directory. None of the events from this pass will be written to the event buffer."); return; } // Write the version number. This will help us read data from the file. try { Utility.PerformIOWithRetries( () => { writer.WriteLine(EtlConsumerConstants.EtwEventCacheFormatVersionString); }); } catch (Exception e) { // Log an error and move on. No events from this pass will be // written to the destination. this.TraceSource.WriteExceptionAsError( this.LogSourceId, e, "Failed to write buffered event file format version number to file {0} in the buffered event file. None of the events from this pass will be written to the event buffer.", tempCacheFileFullPath); return; } this.streamWriter = writer; this.TraceSource.WriteInfo( this.LogSourceId, "Filtered ETW events for consumer will be buffered in file {0}.", tempCacheFileFullPath); }
public void OnEtwEventProcessingPeriodStop() { if (null == this.streamWriter) { // An error occurred during the creation of the buffered event // file. So just return immediately without doing anything. return; } // Close the buffered event file that we are currently working on. try { this.streamWriter.Dispose(); } catch (System.Text.EncoderFallbackException ex) { // This can happen if the manifest file does not match the binary. // Write an error message and move on. this.TraceSource.WriteError( this.LogSourceId, "Exception occurred while closing buffered event file. Exception information: {0}", ex); } // Make our buffered event files available for delivery to the consumer. // This includes: // - the buffered event file that we wrote in this pass // - any old buffered event files that we wrote in previous passes // (and got interrupted before we could rename them for delivery to // the consumer). string[] cacheFiles = FabricDirectory.GetFiles( this.etwEventCache, TempCacheFileNameSearchPattern); foreach (string cacheFile in cacheFiles) { try { Utility.PerformIOWithRetries( ctx => { string fileName = ctx; FabricFile.Move( fileName, Path.ChangeExtension(fileName, CacheFileNameExtension)); }, cacheFile); this.TraceSource.WriteInfo( this.LogSourceId, "File containing filtered ETW events was renamed for delivery to consumer. Old name: {0}, new name: {1}.", cacheFile, Path.ChangeExtension(cacheFile, CacheFileNameExtension)); } catch (Exception e) { this.TraceSource.WriteExceptionAsError( this.LogSourceId, e, "Buffered event file {0} could not be renamed for delivery to consumer.", cacheFile); } } this.perfHelper.EtlReadPassEnd(); }
private void DeliverEventsToConsumer(object state) { this.perfHelper.EventDeliveryPassBegin(); this.eventDeliveryPeriodAborted = false; // Perform any tasks necessary at the beginning of the event delivery pass this.eventSink.OnEtwEventDeliveryStart(); // Get the files from the buffered event directory // We ignore files that are so old that they need to be deleted DateTime cutoffTime = DateTime.UtcNow.Add(-this.eventDeletionAge); DirectoryInfo dirInfo = new DirectoryInfo(this.etwEventCache); FileInfo[] eventFilesInfo = dirInfo.GetFiles(CacheFileNameSearchPattern) .Where(file => file.LastWriteTimeUtc.CompareTo(cutoffTime) > 0) .ToArray(); // Sort the files such that the file with the most recent last-write // time comes first. We'll process files in that order so that in // case of huge backlogs the most recent (and hence likely to be // most interesting) traces are processed first. Array.Sort(eventFilesInfo, CompareFileLastWriteTimes); // Process each of the files int filesProcessed = 0; DateTime processingEndTime = DateTime.Now.Add(this.eventDeliveryPassLength); List <string> filesToDelete = new List <string>(); foreach (FileInfo eventFileInfo in eventFilesInfo) { // Process events from the current file string eventFile = eventFileInfo.FullName; this.ProcessEventsFromFile(eventFile); filesProcessed++; // If the event delivery pass is being aborted, then don't process // any more files. Also, don't delete the current file because // its processing may have been interrupted. This file will be // processed again in the next pass. if (this.eventDeliveryPeriodAborted) { this.TraceSource.WriteInfo( this.LogSourceId, "The event delivery pass is being aborted. Therefore, no more files in the buffered event directory will be processed."); break; } // If we are in the process of stopping, then don't process any // more files. Also, don't delete the current file because its // processing may have been interrupted. This file will be // processed again when we are restarted. if (this.Stopping) { this.TraceSource.WriteInfo( this.LogSourceId, "The consumer is being stopped. Therefore, no more files in the buffered event directory will be processed."); break; } // Add the file to the list of files that we delete at the end // of the event delivery pass filesToDelete.Add(eventFile); if (0 > DateTime.Compare(processingEndTime, DateTime.Now)) { this.TraceSource.WriteInfo( this.LogSourceId, "Due to time limit on backlog processing, no more files in the buffered event directory will be processed in this pass."); break; } } // Perform any tasks necessary at the end of the ETL processing pass this.eventSink.OnEtwEventDeliveryStop(); // Delete the files that we successfully processed in this pass foreach (string fileToDelete in filesToDelete) { try { Utility.PerformIOWithRetries( ctx => { string fileName = ctx; FabricFile.Delete(fileName); }, fileToDelete); } catch (Exception e) { this.TraceSource.WriteExceptionAsError( this.LogSourceId, e, "Failed to delete file {0}.", fileToDelete); } } // Write performance-related information. this.perfHelper.RecordEventDeliveryBacklog(eventFilesInfo.Length - filesProcessed); this.perfHelper.EventDeliveryPassEnd(); // Schedule the next pass this.eventDeliveryTimer.Start(); }
/// <summary> /// Updates the bookmark file with the last event read index. /// </summary> /// <param name="bookmarkFolder"></param> /// <param name="lastReadEventIndexPosition"></param> /// <param name="eventIndex"></param> /// <param name="bytesWritten"></param> /// <returns></returns> internal bool UpdateBookmarkFile( string bookmarkFolder, long lastReadEventIndexPosition, EventIndex eventIndex, out long bytesWritten) { bytesWritten = 0; FileStream fs = null; StreamWriter writer = null; string bookmarkFile = Path.Combine(bookmarkFolder, BookmarkFileName); if (false == FabricFile.Exists(bookmarkFile)) { return(false); } try { // Open the bookmark file try { Utility.PerformIOWithRetries( () => { fs = new FileStream(bookmarkFile, FileMode.Open); writer = new StreamWriter(fs); }, this.methodExecutionInitialRetryIntervalMs, this.methodExecutionMaxRetryCount, this.methodExecutionMaxRetryIntervalMs); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Unable to open bookmark file {0} while processing events.", bookmarkFile); return(false); } // Move the stream position to the point where the event index needs to be written fs.Position = lastReadEventIndexPosition; long localBytesWritten = 0; // Write the timestamp and index of the last event read and close the file string lastEventReadString = string.Format("{0},{1},{2}", eventIndex.Timestamp.ToBinary(), eventIndex.Timestamp.ToString(), eventIndex.TimestampDifferentiator); try { Utility.PerformIOWithRetries( () => { writer.WriteLine(lastEventReadString); localBytesWritten = lastEventReadString.Length + 2; writer.Dispose(); fs.Dispose(); }, this.methodExecutionInitialRetryIntervalMs, this.methodExecutionMaxRetryCount, this.methodExecutionMaxRetryIntervalMs); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Unable to write last event read {0} in bookmark file {1} while processing events.", lastEventReadString, bookmarkFile); return(false); } // record bytes written bytesWritten = localBytesWritten; } finally { if (null != writer) { writer.Dispose(); } if (null != fs) { fs.Dispose(); } } return(true); }
/// <summary> /// Retrieves the last event index processed. /// </summary> /// <param name="bookmarkFolder"></param> /// <param name="bytesRead"></param> /// <returns></returns> internal EventIndex ReadBookmarkFile( string bookmarkFolder, out long bytesRead) { bytesRead = 0; EventIndex lastEventIndex = new EventIndex(); lastEventIndex.Set(DateTime.MinValue, -1); string bookmarkFile = Path.Combine(bookmarkFolder, BookmarkFileName); if (false == FabricFile.Exists(bookmarkFile)) { // Bookmark file doesn't exist return(lastEventIndex); } StreamReader reader = null; try { // Open the file try { Utility.PerformIOWithRetries( () => { FileStream fileStream = FabricFile.Open(bookmarkFile, FileMode.Open, FileAccess.Read); Helpers.SetIoPriorityHint(fileStream.SafeFileHandle, Kernel32Types.PRIORITY_HINT.IoPriorityHintVeryLow); reader = new StreamReader(fileStream); }, this.methodExecutionInitialRetryIntervalMs, this.methodExecutionMaxRetryCount, this.methodExecutionMaxRetryIntervalMs); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Unable to open bookmark file {0}.", bookmarkFile); return(lastEventIndex); } long localBytesRead = 0; // Get the version string versionString = string.Empty; try { Utility.PerformIOWithRetries( () => { versionString = reader.ReadLine(); localBytesRead += versionString.Length + 2; }, this.methodExecutionInitialRetryIntervalMs, this.methodExecutionMaxRetryCount, this.methodExecutionMaxRetryIntervalMs); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Unable to read version information from bookmark file {0}.", bookmarkFile); return(lastEventIndex); } // Check the version if (false == versionString.Equals(BookmarkFileFormatVersionString, StringComparison.Ordinal)) { this.traceSource.WriteError( this.logSourceId, "Unexpected version string {0} encountered in bookmark file {1}.", versionString, bookmarkFile); return(lastEventIndex); } // Get information about the last event that we read string infoLine = string.Empty; try { Utility.PerformIOWithRetries( () => { infoLine = reader.ReadLine(); localBytesRead += infoLine.Length + 2; }, this.methodExecutionInitialRetryIntervalMs, this.methodExecutionMaxRetryCount, this.methodExecutionMaxRetryIntervalMs); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Unable to read information about last event read from bookmark file {0}.", bookmarkFile); return(lastEventIndex); } string[] infoLineParts = infoLine.Split(','); if (infoLineParts.Length != (int)LastEventReadInfoParts.Count) { this.traceSource.WriteError( this.logSourceId, "The information in bookmark file {0} about the last event read is not in the expected format. {1}", bookmarkFile, infoLine); return(lastEventIndex); } string lastEventTimestampString = infoLineParts[(int)LastEventReadInfoParts.LastEventTimestampLong].Trim(); long lastEventTimestampBinary; if (false == long.TryParse(lastEventTimestampString, out lastEventTimestampBinary)) { this.traceSource.WriteError( this.logSourceId, "Unable to retrieve timestamp of last event from bookmark file {0}.", bookmarkFile); return(lastEventIndex); } DateTime lastEventTimestamp = DateTime.FromBinary(lastEventTimestampBinary); string lastEventTimestampDifferentiatorString = infoLineParts[(int)LastEventReadInfoParts.LastEventIndex].Trim(); int lastEventTimestampDifferentiator; if (false == int.TryParse(lastEventTimestampDifferentiatorString, out lastEventTimestampDifferentiator)) { this.traceSource.WriteError( this.logSourceId, "Unable to retrieve timestamp differentiator of last event from bookmark file {0}.", bookmarkFile); return(lastEventIndex); } // record bytes read bytesRead = localBytesRead; lastEventIndex.Set(lastEventTimestamp, lastEventTimestampDifferentiator); } finally { if (null != reader) { reader.Dispose(); } } return(lastEventIndex); }
/// <summary> /// Gets the file position where last event index is recorded. /// </summary> /// <param name="bookmarkFolder"></param> /// <param name="lastEventReadPosition"></param> /// <param name="bytesRead"></param> /// <returns></returns> internal bool GetLastEventReadPosition( string bookmarkFolder, out long lastEventReadPosition, out long bytesRead) { lastEventReadPosition = 0; bytesRead = 0; string bookmarkFile = Path.Combine(bookmarkFolder, BookmarkFileName); if (false == FabricFile.Exists(bookmarkFile)) { // Bookmark file doesn't exist return(false); } StreamReader reader = null; try { // Open the file try { Utility.PerformIOWithRetries( () => { FileStream fileStream = FabricFile.Open(bookmarkFile, FileMode.Open, FileAccess.Read); Helpers.SetIoPriorityHint(fileStream.SafeFileHandle, Kernel32Types.PRIORITY_HINT.IoPriorityHintVeryLow); reader = new StreamReader(fileStream); }, this.methodExecutionInitialRetryIntervalMs, this.methodExecutionMaxRetryCount, this.methodExecutionMaxRetryIntervalMs); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Unable to open bookmark file {0}.", bookmarkFile); return(false); } long localBytesRead = 0; long streamPosition = 0; // Get the version string versionString = string.Empty; try { Utility.PerformIOWithRetries( () => { versionString = reader.ReadLine(); localBytesRead += versionString.Length + 2; streamPosition = localBytesRead; }, this.methodExecutionInitialRetryIntervalMs, this.methodExecutionMaxRetryCount, this.methodExecutionMaxRetryIntervalMs); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Unable to read version information from bookmark file {0}.", bookmarkFile); return(false); } // Check the version if (false == versionString.Equals(BookmarkFileFormatVersionString, StringComparison.Ordinal)) { this.traceSource.WriteError( this.logSourceId, "Unexpected version string {0} encountered in bookmark file {1}.", versionString, bookmarkFile); return(false); } // Get information about the last event that we read string infoLine = string.Empty; try { Utility.PerformIOWithRetries( () => { infoLine = reader.ReadLine(); localBytesRead += infoLine.Length + 2; }, this.methodExecutionInitialRetryIntervalMs, this.methodExecutionMaxRetryCount, this.methodExecutionMaxRetryIntervalMs); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Unable to read information about last event read from bookmark file {0}.", bookmarkFile); return(false); } // record bytes read bytesRead = localBytesRead; lastEventReadPosition = streamPosition; } finally { if (null != reader) { reader.Dispose(); } } return(true); }
/// <summary> /// Creates the bookmark file if it does not exist. /// </summary> /// <param name="bookmarkFolder"></param> /// <param name="bytesWritten"></param> /// <returns></returns> internal bool CreateBookmarkFile( string bookmarkFolder, out long bytesWritten) { FileStream fs = null; StreamWriter writer = null; bytesWritten = 0; string bookmarkFile = Path.Combine(bookmarkFolder, BookmarkFileName); if (true == FabricFile.Exists(bookmarkFile)) { return(true); } try { // Create the bookmark file try { Utility.PerformIOWithRetries( () => { fs = new FileStream(bookmarkFile, FileMode.Create); writer = new StreamWriter(fs); }, this.methodExecutionInitialRetryIntervalMs, this.methodExecutionMaxRetryCount, this.methodExecutionMaxRetryIntervalMs); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Unable to create bookmark file {0} while processing events.", bookmarkFile); return(false); } long localBytesWritten = 0; // Write the version information try { Utility.PerformIOWithRetries( () => { writer.WriteLine(BookmarkFileFormatVersionString); localBytesWritten += BookmarkFileFormatVersionString.Length + 2; writer.Flush(); }, this.methodExecutionInitialRetryIntervalMs, this.methodExecutionMaxRetryCount, this.methodExecutionMaxRetryIntervalMs); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Unable to write version information in bookmark file {0} while processing events.", bookmarkFile); return(false); } // Write the timestamp and index of the last event read and close the file int lastEventIndex = -1; string lastEventReadString = string.Format("{0},{1},{2}", DateTime.MinValue.ToBinary(), DateTime.MinValue.ToString(), lastEventIndex.ToString()); try { Utility.PerformIOWithRetries( () => { writer.WriteLine(lastEventReadString); localBytesWritten += lastEventReadString.Length + 2; writer.Dispose(); fs.Dispose(); }, this.methodExecutionInitialRetryIntervalMs, this.methodExecutionMaxRetryCount, this.methodExecutionMaxRetryIntervalMs); } catch (Exception e) { this.traceSource.WriteExceptionAsError( this.logSourceId, e, "Unable to write last event read {0} in bookmark file {1} while processing events.", lastEventReadString, bookmarkFile); return(false); } // record bytes written bytesWritten = localBytesWritten; } finally { if (null != writer) { writer.Dispose(); } if (null != fs) { fs.Dispose(); } } return(true); }