Ejemplo n.º 1
0
        /// <summary>
        /// Writes the <paramref name="dataPoint"/> to the <see cref="ArchiveDataBlock"/>.
        /// </summary>
        /// <param name="dataPoint"><see cref="IDataPoint"/> to write.</param>
        /// <param name="exception">Any <see cref="Exception"/> that may have been encountered while writing.</param>
        /// <returns>
        /// <c>true</c> if data point was written; otherwise, <c>false</c>.
        /// </returns>
        public bool Write(IDataPoint dataPoint, out Exception exception)
        {
            exception = null;

            try
            {
                TimeTag value = dataPoint.Time;

                // Do not attempt to write values with a bad timestamp, this will just throw an exception
                if (value.CompareTo(TimeTag.MinValue) < 0 || value.CompareTo(TimeTag.MaxValue) > 0)
                {
                    exception = new TimeTagException("Skipping data write for point: Bad time tag, value must between 01/01/1995 and 01/19/2063");
                }
                else
                {
                    if (SlotsAvailable > 0)
                    {
                        // We have enough space to write the provided point data to the data block.
                        m_lastActivityTime = DateTime.UtcNow;

                        lock (m_parent.FileData)
                        {
                            // Write the data.
                            if (m_writeCursor != m_parent.FileData.Position)
                            {
                                m_parent.FileData.Seek(m_writeCursor, SeekOrigin.Begin);
                            }

                            dataPoint.CopyBinaryImageToStream(m_parent.FileData);

                            // Update the write cursor.
                            m_writeCursor = m_parent.FileData.Position;

                            // Flush the data if configured.
                            if (!m_parent.CacheWrites)
                            {
                                m_parent.FileData.Flush();
                            }
                        }
                    }
                    else
                    {
                        exception = new InvalidOperationException("Skipping data write for point: No slots available for writing new data");
                    }
                }
            }
            catch (Exception ex)
            {
                exception = new InvalidOperationException($"Skipping data write for point: {ex.Message}", ex);
            }

            if ((object)exception == null)
            {
                return(true);
            }

            OnDataWriteException(exception);

            return(false);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Initializes <see cref="ArchiveDataPoint"/> from the specified <paramref name="buffer"/>.
        /// </summary>
        /// <param name="buffer">Binary image to be used for initializing <see cref="ArchiveDataPoint"/>.</param>
        /// <param name="startIndex">0-based starting index of initialization data in the <paramref name="buffer"/>.</param>
        /// <param name="length">Valid number of bytes in <paramref name="buffer"/> from <paramref name="startIndex"/>.</param>
        /// <returns>Number of bytes used from the <paramref name="buffer"/> for initializing <see cref="ArchiveDataPoint"/>.</returns>
        public virtual int ParseBinaryImage(byte[] buffer, int startIndex, int length)
        {
            if (length >= FixedLength)
            {
                // Binary image has sufficient data.
                Flags = LittleEndian.ToInt16(buffer, startIndex + 4);
                Value = LittleEndian.ToSingle(buffer, startIndex + 6);

                TimeTag value = new TimeTag(LittleEndian.ToInt32(buffer, startIndex) +                         // Seconds
                                            ((decimal)(m_flags.GetMaskedValue(MillisecondMask) >> 5) / 1000)); // Milliseconds

                // Make sure to properly validate timestamps for newly initialized or possibly corrupted blocks
                if (value.CompareTo(TimeTag.MinValue) < 0 || value.CompareTo(TimeTag.MaxValue) > 0)
                {
                    value = TimeTag.MinValue;
                }

                Time = value;

                return(FixedLength);
            }

            // Binary image does not have sufficient data.
            return(0);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Tests if the <paramref name="dataBlockPointer"/> matches the specified search criteria.
        /// </summary>
        /// <param name="dataBlockPointer"><see cref="ArchiveDataBlockPointer"/> to test.</param>
        /// <param name="historianID">Desired historian ID.</param>
        /// <param name="startTime">Desired start time.</param>
        /// <param name="endTime">Desired end time.</param>
        /// <returns><c>true</c> if the specified <paramref name="dataBlockPointer"/> is for <paramref name="historianID"/> and falls within the <paramref name="startTime"/> and <paramref name="endTime"/>; otherwise <c>false</c>.</returns>
        public static bool Matches(this ArchiveDataBlockPointer dataBlockPointer, int historianID, TimeTag startTime, TimeTag endTime)
        {
            // Note: The StartTime value of the pointer is ignored if m_searchStartTime = TimeTag.MinValue and
            //       m_searchEndTime = TimeTag.MaxValue. In this case only the PointID value is compared. This
            //       comes in handy when the first or last pointer is to be found from the list of pointers for
            //       a point ID in addition to all the pointers for a point ID.
            if ((object)dataBlockPointer != null)
            {
                return(dataBlockPointer.HistorianID == historianID &&
                       (startTime.CompareTo(TimeTag.MinValue) == 0 || dataBlockPointer.StartTime.CompareTo(startTime) >= 0) &&
                       (endTime.CompareTo(TimeTag.MaxValue) == 0 || dataBlockPointer.StartTime.CompareTo(endTime) <= 0));
            }

            return(false);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Compares the current <see cref="ArchiveDataBlockPointer"/> object to <paramref name="obj"/>.
        /// </summary>
        /// <param name="obj">Object against which the current <see cref="ArchiveDataBlockPointer"/> object is to be compared.</param>
        /// <returns>
        /// Negative value if the current <see cref="ArchiveDataBlockPointer"/> object is less than <paramref name="obj"/>,
        /// Zero if the current <see cref="ArchiveDataBlockPointer"/> object is equal to <paramref name="obj"/>,
        /// Positive value if the current <see cref="ArchiveDataBlockPointer"/> object is greater than <paramref name="obj"/>.
        /// </returns>
        public virtual int CompareTo(object obj)
        {
            ArchiveDataBlockPointer other = obj as ArchiveDataBlockPointer;

            if ((object)other == null)
            {
                return(1);
            }

            int result = m_historianID.CompareTo(other.HistorianID);

            if (result != 0)
            {
                return(result);
            }

            return(m_startTime.CompareTo(other.StartTime));
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Compares the current <see cref="ArchiveDataPoint"/> object to <paramref name="obj"/>.
        /// </summary>
        /// <param name="obj">Object against which the current <see cref="ArchiveDataPoint"/> object is to be compared.</param>
        /// <returns>
        /// Negative value if the current <see cref="ArchiveDataPoint"/> object is less than <paramref name="obj"/>,
        /// Zero if the current <see cref="ArchiveDataPoint"/> object is equal to <paramref name="obj"/>,
        /// Positive value if the current <see cref="ArchiveDataPoint"/> object is greater than <paramref name="obj"/>.
        /// </returns>
        public virtual int CompareTo(object obj)
        {
            ArchiveDataPoint other = obj as ArchiveDataPoint;

            if (other == null)
            {
                return(1);
            }
            else
            {
                int result = m_historianID.CompareTo(other.HistorianID);
                if (result != 0)
                {
                    return(result);
                }
                else
                {
                    return(m_time.CompareTo(other.Time));
                }
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Initializes <see cref="ArchiveDataPoint"/> from the specified <paramref name="buffer"/>.
        /// </summary>
        /// <param name="buffer">Binary image to be used for initializing <see cref="ArchiveDataPoint"/>.</param>
        /// <param name="startIndex">0-based starting index of initialization data in the <paramref name="buffer"/>.</param>
        /// <param name="length">Valid number of bytes in <paramref name="buffer"/> from <paramref name="startIndex"/>.</param>
        /// <returns>Number of bytes used from the <paramref name="buffer"/> for initializing <see cref="ArchiveDataPoint"/>.</returns>
        public virtual int ParseBinaryImage(byte[] buffer, int startIndex, int length)
        {
            if (length >= FixedLength)
            {
                // Binary image has sufficient data.
                Flags = LittleEndian.ToInt16(buffer, startIndex + 4);
                Value = LittleEndian.ToSingle(buffer, startIndex + 6);

                TimeTag value = new TimeTag(LittleEndian.ToInt32(buffer, startIndex) +       // Seconds
                        ((decimal)(m_flags.GetMaskedValue(MillisecondMask) >> 5) / 1000));   // Milliseconds

                // Make sure to properly validate timestamps for newly initialized or possibly corrupted blocks
                if (value.CompareTo(TimeTag.MinValue) < 0 || value.CompareTo(TimeTag.MaxValue) > 0)
                    value = TimeTag.MinValue;

                Time = value;

                return FixedLength;
            }
            
            // Binary image does not have sufficient data.
            return 0;
        }
Ejemplo n.º 7
0
 private bool FindHistoricArchiveFileForWrite(Info fileInfo, TimeTag searchTime)
 {
     return ((object)fileInfo != null &&
             searchTime.CompareTo(fileInfo.StartTimeTag) >= 0 &&
             searchTime.CompareTo(fileInfo.EndTimeTag) <= 0);
 }
Ejemplo n.º 8
0
 private bool FindHistoricArchiveFileForRead(Info fileInfo, TimeTag startTime, TimeTag endTime)
 {
     return ((object)fileInfo != null &&
         ((startTime.CompareTo(fileInfo.StartTimeTag) >= 0 && startTime.CompareTo(fileInfo.EndTimeTag) <= 0) ||
         (endTime.CompareTo(fileInfo.StartTimeTag) >= 0 && endTime.CompareTo(fileInfo.EndTimeTag) <= 0) ||
         (startTime.CompareTo(fileInfo.StartTimeTag) < 0 && endTime.CompareTo(fileInfo.EndTimeTag) > 0)));
 }
Ejemplo n.º 9
0
        // Read data implementation
        private IEnumerable<IDataPoint> ReadData(IEnumerable<int> historianIDs, TimeTag startTime, TimeTag endTime, IDataPoint resumeFrom, bool timeSorted)
        {
            // Yield to archive rollover process.
            m_rolloverWaitHandle.WaitOne();

            // 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.CompareTo(endTime) > 0)
                throw new ArgumentException("End Time precedes Start Time in the specified time span");

            List<Info> dataFiles = new List<Info>();
            bool pendingRollover = false;
            bool usingActiveFile = false;

            if (startTime.CompareTo(m_fat.FileStartTime) < 0)
            {
                // Data is to be read from historic file(s) - make sure that the list has been built
                if (m_buildHistoricFileListThread.IsAlive)
                    m_buildHistoricFileListThread.Join();

                lock (m_historicArchiveFiles)
                {
                    dataFiles.AddRange(m_historicArchiveFiles.FindAll(info => FindHistoricArchiveFileForRead(info, startTime, endTime)));
                }
            }

            if (endTime.CompareTo(m_fat.FileStartTime) >= 0)
            {
                // Data is to be read from the active file.
                Info activeFileInfo = new Info(m_fileName)
                {
                    StartTimeTag = m_fat.FileStartTime,
                    EndTimeTag = m_fat.FileEndTime
                };

                dataFiles.Add(activeFileInfo);
            }

            // Read data from all qualifying files.
            foreach (Info dataFile in dataFiles)
            {
                ArchiveFile file = null;

                try
                {
                    if (string.Compare(dataFile.FileName, m_fileName, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        // Read data from current file.
                        usingActiveFile = true;
                        file = this;

                        // Atomically increment total number of readers for active file
                        Interlocked.Increment(ref m_activeFileReaders);

                        // Handle race conditions between rollover
                        // and incrementing the active readers
                        while (m_rolloverInProgress)
                        {
                            Interlocked.Decrement(ref m_activeFileReaders);
                            m_rolloverWaitHandle.WaitOne();
                            Interlocked.Increment(ref m_activeFileReaders);
                        }
                    }
                    else
                    {
                        // Read data from historic file.
                        usingActiveFile = false;
                        file = new ArchiveFile();
                        file.FileName = dataFile.FileName;
                        file.StateFile = m_stateFile;
                        file.IntercomFile = m_intercomFile;
                        file.MetadataFile = m_metadataFile;
                        file.FileAccessMode = FileAccess.Read;
                        file.Open();
                    }

                    // Create new data point scanner for the desired points in this file and given time range
                    IArchiveFileScanner scanner;

                    if (timeSorted)
                        scanner = new TimeSortedArchiveFileScanner();
                    else
                        scanner = new ArchiveFileScanner();

                    scanner.FileAllocationTable = file.Fat;
                    scanner.HistorianIDs = historianIDs;
                    scanner.StartTime = startTime;
                    scanner.EndTime = endTime;
                    scanner.ResumeFrom = resumeFrom;
                    scanner.DataReadExceptionHandler = (sender, e) => OnDataReadException(e.Argument);

                    // Reset resumeFrom to scan from beginning after picking up where left off from roll over
                    resumeFrom = null;

                    // Return data points
                    foreach (IDataPoint dataPoint in scanner.Read())
                    {
                        yield return dataPoint;

                        // If a rollover needs to happen, we need to relinquish read lock and close file
                        if (m_rolloverInProgress)
                        {
                            resumeFrom = dataPoint;
                            pendingRollover = true;
                            break;
                        }
                    }
                }
                finally
                {
                    if (usingActiveFile)
                    {
                        // Atomically decrement active file reader count to signal in-process code that read is complete or yielded
                        Interlocked.Decrement(ref m_activeFileReaders);
                    }
                    else if ((object)file != null)
                    {
                        file.Dispose();
                    }
                }

                if (pendingRollover)
                    break;
            }

            if (pendingRollover)
            {
                // Recurse into this function with an updated start time and last read point ID so that read can
                // resume right where it left off - recursed function call will wait until rollover is complete
                foreach (IDataPoint dataPoint in ReadData(historianIDs, startTime, endTime, resumeFrom, timeSorted))
                {
                    yield return dataPoint;
                }
            }
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Tests if the <paramref name="dataBlockPointer"/> matches the specified search criteria.
        /// </summary>
        /// <param name="dataBlockPointer"><see cref="ArchiveDataBlockPointer"/> to test.</param>
        /// <param name="historianID">Desired historian ID.</param>
        /// <param name="startTime">Desired start time.</param>
        /// <param name="endTime">Desired end time.</param>
        /// <returns><c>true</c> if the specified <paramref name="dataBlockPointer"/> is for <paramref name="historianID"/> and falls within the <paramref name="startTime"/> and <paramref name="endTime"/>; otherwise <c>false</c>.</returns>
        public static bool Matches(this ArchiveDataBlockPointer dataBlockPointer, int historianID, TimeTag startTime, TimeTag endTime)
        {
            // Note: The StartTime value of the pointer is ignored if m_searchStartTime = TimeTag.MinValue and
            //       m_searchEndTime = TimeTag.MaxValue. In this case only the PointID value is compared. This
            //       comes in handy when the first or last pointer is to be found from the list of pointers for
            //       a point ID in addition to all the pointers for a point ID.
            if ((object)dataBlockPointer != null)
                return dataBlockPointer.HistorianID == historianID &&
                        (startTime.CompareTo(TimeTag.MinValue) == 0 || dataBlockPointer.StartTime.CompareTo(startTime) >= 0) &&
                        (endTime.CompareTo(TimeTag.MaxValue) == 0 || dataBlockPointer.StartTime.CompareTo(endTime) <= 0);

            return false;
        }