private void PrepareForRollover() { try { DriveInfo archiveDrive = new DriveInfo(Path.GetPathRoot(m_fileName)); if (archiveDrive.AvailableFreeSpace < archiveDrive.TotalSize * (1 - ((double)m_fileOffloadThreshold / 100))) { // We'll start offloading historic files if we've reached the offload threshold. OffloadHistoricFiles(); } OnRolloverPreparationStart(); // Opening and closing a new archive file in "standby" mode will create a "standby" archive file. ArchiveFile standbyArchiveFile = new ArchiveFile(); standbyArchiveFile.FileName = StandbyArchiveFileName; standbyArchiveFile.FileSize = m_fileSize; standbyArchiveFile.DataBlockSize = m_dataBlockSize; standbyArchiveFile.StateFile = m_stateFile; standbyArchiveFile.IntercomFile = m_intercomFile; standbyArchiveFile.MetadataFile = m_metadataFile; try { standbyArchiveFile.Open(); } catch (Exception) { string standbyFileName = standbyArchiveFile.FileName; standbyArchiveFile.Close(); // We didn't succeed in creating a "standby" archive file, so we'll delete it if it was created // partially (might happen if there isn't enough disk space or thread is aborted). This is to // ensure that this preparation processes is kicked off again until a valid "standby" archive // file is successfully created. if (File.Exists(standbyFileName)) { File.Delete(standbyFileName); } throw; // Rethrow the exception so the appropriate action is taken. } finally { standbyArchiveFile.Dispose(); } OnRolloverPreparationComplete(); } catch (ThreadAbortException) { // This thread must die now... } catch (Exception ex) { OnRolloverPreparationException(ex); } }
/// <summary> /// Reads <see cref="ArchiveData"/> points. /// </summary> /// <param name="historianID">Historian identifier for which <see cref="ArchiveData"/> points are to be retrieved.</param> /// <param name="startTime">Start <see cref="TimeTag"/> (in GMT) for the <see cref="ArchiveData"/> points to be retrieved.</param> /// <param name="endTime">End <see cref="TimeTag"/> (in GMT) for the <see cref="ArchiveData"/> points to be retrieved.</param> /// <returns><see cref="IEnumerable{T}"/> object containing zero or more <see cref="ArchiveData"/> points.</returns> public IEnumerable<IDataPoint> ReadData(int historianID, TimeTag startTime, TimeTag endTime) { // Ensure that the current file is open. if (!IsOpen) throw new InvalidOperationException(string.Format("\"{0}\" file is not open.", m_fileName)); // Ensure that the current file is active. if (m_fileType != ArchiveFileType.Active) throw new InvalidOperationException("Data can only be directly read from files that are Active."); // Ensure that the start and end time are valid. if (startTime > endTime) throw new ArgumentException("End Time preceeds Start Time in the specified timespan."); // Yeild to the rollover process if it is in progress. m_rolloverWaitHandle.WaitOne(); List<Info> dataFiles = new List<Info>(); if (startTime < m_fat.FileStartTime) { // Data is to be read from historic file(s). if (m_buildHistoricFileListThread.IsAlive) m_buildHistoricFileListThread.Join(); m_readSearchStartTimeTag = startTime; m_readSearchEndTimeTag = endTime; lock (m_historicArchiveFiles) { dataFiles.AddRange(m_historicArchiveFiles.FindAll(FindHistoricArchiveFileForRead)); } } if (endTime >= m_fat.FileStartTime) { // Data is to be read from the active file. Info activeFileInfo = new Info(); activeFileInfo.FileName = m_fileName; activeFileInfo.StartTimeTag = m_fat.FileStartTime; activeFileInfo.EndTimeTag = m_fat.FileEndTime; dataFiles.Add(activeFileInfo); } // Read data from all qualifying files. foreach (Info dataFile in dataFiles) { ArchiveFile file = new ArchiveFile(); IList<ArchiveDataBlock> dataBlocks; try { file.FileName = dataFile.FileName; file.StateFile = m_stateFile; file.IntercomFile = m_intercomFile; file.MetadataFile = m_metadataFile; file.Open(); dataBlocks = file.Fat.FindDataBlocks(historianID, startTime, endTime); if (dataBlocks.Count > 0) { // Data block before the first data block matching the search criteria might contain some data // for the specified search criteria, so look for such a data block and process its data. lock (file.Fat.DataBlockPointers) { for (int i = dataBlocks[0].Index - 1; i >= 0; i--) { if (file.Fat.DataBlockPointers[i].HistorianID == historianID) { foreach (ArchiveData data in file.Fat.DataBlockPointers[i].DataBlock.Read()) { if (data.Time >= startTime) yield return data; } break; } } } // Read data from rest of the data blocks and scan the last data block for data matching the // the search criteria as it may contain data beyond the timespan specified in the search. for (int i = 0; i < dataBlocks.Count; i++) { if (i < dataBlocks.Count - 1) { // Read all the data. foreach (ArchiveData data in dataBlocks[i].Read()) { yield return data; } } else { // Scan through the data block. foreach (ArchiveData data in dataBlocks[i].Read()) { if (data.Time <= endTime) yield return data; else yield break; } } } } } finally { if (file.IsOpen) { file.Close(); } } } }