// Monitors for roll-over notifications private void m_rolloverWatcher_Elapsed(object sender, ElapsedEventArgs e) { // Don't start another rollover activity if one is already in progress... if (Monitor.TryEnter(m_watcherLock)) { try { // Read the inter-process communications file for changes in roll-over state if ((object)m_archiveFile != null && (object)m_archiveFile.IntercomFile != null && m_archiveFile.IntercomFile.IsOpen) { m_archiveFile.IntercomFile.Load(); IntercomRecord record = m_archiveFile.IntercomFile.Read(1); if ((object)record != null) { // Pause processing if (record.RolloverInProgress && m_archiveFile.IsOpen) { // Notify internal archive file components about the pending rollover m_archiveFile.RolloverWaitHandle.Reset(); // Raise roll-over start event (sets m_rolloverInProgress flag) m_archiveFile.OnRolloverStart(); // Wait for pending to reads to yield m_archiveFile.WaitForReadersRelease(); // Close the active archive file stream so it can be rolled-over m_archiveFile.CloseStream(); } // Resume processing if (!record.RolloverInProgress && !m_archiveFile.IsOpen) { // Open new active archive file stream m_archiveFile.OpenStream(); // Raise roll-over complete event (resets m_rolloverInProgress flag) m_archiveFile.OnRolloverComplete(); // Notify waiting internal archive components that rollover is complete m_archiveFile.RolloverWaitHandle.Set(); } } } } catch (ThreadAbortException) { throw; } catch (Exception ex) { OnDataReadException(new InvalidOperationException("Exception encountered during roll-over processing: " + ex.Message, ex)); } finally { Monitor.Exit(m_watcherLock); } } }
/// <summary> /// Opens the <see cref="ArchiveFile"/> for use. /// </summary> /// <exception cref="InvalidOperationException">One or all of the <see cref="StateFile"/>, <see cref="IntercomFile"/> or <see cref="MetadataFile"/> properties are not set.</exception> public void Open() { if (!IsOpen) { // Check for the existence of dependencies. if ((object)m_stateFile == null || (object)m_intercomFile == null || (object)m_metadataFile == null) throw (new InvalidOperationException("One or more of the dependency files are not specified.")); // Validate file type against its name. if (Path.GetExtension(m_fileName).ToNonNullString().ToLower() == StandbyFileExtension) m_fileType = ArchiveFileType.Standby; else if (Regex.IsMatch(m_fileName.ToLower(), string.Format(".+_.+_to_.+\\{0}$", FileExtension))) m_fileType = ArchiveFileType.Historic; else m_fileType = ArchiveFileType.Active; // Get the absolute path for the file name. m_fileName = FilePath.GetAbsolutePath(m_fileName); // Create the directory if it does not exist. if (!Directory.Exists(FilePath.GetDirectoryName(m_fileName))) Directory.CreateDirectory(FilePath.GetDirectoryName(m_fileName)); // Validate a roll-over is not in progress when opening archive as read-only if (m_fileType == ArchiveFileType.Active && m_fileAccessMode == FileAccess.Read) { // Open intercom file if closed. if (!m_intercomFile.IsOpen) m_intercomFile.Open(); m_intercomFile.Load(); IntercomRecord record = m_intercomFile.Read(1); int waitCount = 0; while ((object)record != null && record.RolloverInProgress && waitCount < 30) { Thread.Sleep(1000); m_intercomFile.Load(); record = m_intercomFile.Read(1); waitCount++; } } OpenStream(); // Open state file if closed. if (!m_stateFile.IsOpen) m_stateFile.Open(); // Open intercom file if closed. if (!m_intercomFile.IsOpen) m_intercomFile.Open(); // Open metadata file if closed. if (!m_metadataFile.IsOpen) m_metadataFile.Open(); // Don't proceed further for standby and historic files. if (m_fileType != ArchiveFileType.Active) return; // Start internal process queues. m_currentDataQueue.Start(); m_historicDataQueue.Start(); m_outOfSequenceDataQueue.Start(); // Create data block lookup list. if (m_stateFile.RecordsInMemory > 0) m_dataBlocks = new List<ArchiveDataBlock>(new ArchiveDataBlock[m_stateFile.RecordsInMemory]); else m_dataBlocks = new List<ArchiveDataBlock>(new ArchiveDataBlock[m_stateFile.RecordsOnDisk]); // Validate the dependency files. SyncStateFile(null); if (m_intercomFile.FileAccessMode != FileAccess.Read) { // Ensure that "rollover in progress" is not set. IntercomRecord system = m_intercomFile.Read(1); if ((object)system == null) system = new IntercomRecord(1); system.RolloverInProgress = false; m_intercomFile.Write(1, system); } // Start the memory conservation process. if (m_conserveMemory) { m_conserveMemoryTimer.Interval = DataBlockCheckInterval; m_conserveMemoryTimer.Start(); } if (m_fileType == ArchiveFileType.Active) { // Start preparing the list of historic files. m_buildHistoricFileListThread = new Thread(BuildHistoricFileList); m_buildHistoricFileListThread.Priority = ThreadPriority.Lowest; m_buildHistoricFileListThread.Start(); // Start file watchers to monitor file system changes. if (m_monitorNewArchiveFiles) { if ((object)m_currentLocationFileWatcher != null) { m_currentLocationFileWatcher.Filter = HistoricFilesSearchPattern; m_currentLocationFileWatcher.Path = FilePath.GetDirectoryName(m_fileName); m_currentLocationFileWatcher.EnableRaisingEvents = true; } if (Directory.Exists(m_archiveOffloadLocation) && (object)m_offloadLocationFileWatcher != null) { m_offloadLocationFileWatcher.Filter = HistoricFilesSearchPattern; m_offloadLocationFileWatcher.Path = m_archiveOffloadLocation; m_offloadLocationFileWatcher.EnableRaisingEvents = true; } } } } }