Beispiel #1
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);
        }
Beispiel #2
0
        /// <summary>
        /// Returns all <see cref="ArchiveDataBlock"/>s in the <see cref="ArchiveFile"/> for the specified <paramref name="historianID"/> with <see cref="ArchiveDataPoint"/>s between the specified <paramref name="startTime"/> and <paramref name="endTime"/>.
        /// </summary>
        /// <param name="historianID">Historian identifier.</param>
        /// <param name="startTime">Start <see cref="TimeTag"/>.</param>
        /// <param name="endTime">End <see cref="TimeTag"/>.</param>
        /// <param name="preRead">true to pre-read data to locate write cursor.</param>
        /// <returns>A collection of <see cref="ArchiveDataBlock"/>s.</returns>
        public List <ArchiveDataBlock> FindDataBlocks(int historianID, TimeTag startTime, TimeTag endTime, bool preRead = true)
        {
            if ((object)startTime == null)
            {
                startTime = TimeTag.MaxValue;
            }

            if ((object)endTime == null)
            {
                endTime = TimeTag.MaxValue;
            }

            List <ArchiveDataBlockPointer> blockPointers;

            lock (m_dataBlockPointers)
            {
                // Get all block pointers for given point ID over specified time range
                blockPointers = m_dataBlockPointers.FindAll(dataBlockPointer => dataBlockPointer.Matches(historianID, startTime, endTime));

                // Look for pointer to data block on the borders of the specified range which may contain data
                if (!(startTime == TimeTag.MinValue || endTime == TimeTag.MaxValue))
                {
                    // There are 2 different search criteria for this:

                    // 1) If matching data block pointers have been found, then find data block pointer before the first matching data block pointer.
                    //    or
                    // 2) Find the last data block pointer in the time range of TimeTag.MinValue to m_searchEndTime.

                    TimeTag searchEndTime = endTime;

                    if (blockPointers.Count > 0)
                    {
                        searchEndTime = new TimeTag(blockPointers.First().StartTime.Value - 1.0D);
                    }

                    ArchiveDataBlockPointer borderMatch = m_dataBlockPointers.LastOrDefault(dataBlockPointer => dataBlockPointer.Matches(historianID, TimeTag.MinValue, searchEndTime));

                    if ((object)borderMatch != null)
                    {
                        blockPointers.Insert(0, borderMatch);
                    }
                }
            }

            // Return list of data blocks for given block pointers
            return(blockPointers.Select(pointer => pointer.GetDataBlock(preRead)).ToList());
        }
Beispiel #3
0
            /// <summary>
            /// Initializes <see cref="VariableTableRegion"/> by parsing the specified <paramref name="buffer"/> containing a binary image.
            /// </summary>
            /// <param name="buffer">Buffer containing binary image to parse.</param>
            /// <param name="startIndex">0-based starting index in the <paramref name="buffer"/> to start parsing.</param>
            /// <param name="length">Valid number of bytes within <paramref name="buffer"/> from <paramref name="startIndex"/>.</param>
            /// <returns>The number of bytes used for initialization in the <paramref name="buffer"/> (i.e., the number of bytes parsed).</returns>
            /// <exception cref="ArgumentNullException"><paramref name="buffer"/> is null.</exception>
            /// <exception cref="ArgumentOutOfRangeException">
            /// <paramref name="startIndex"/> or <paramref name="length"/> is less than 0 -or-
            /// <paramref name="startIndex"/> and <paramref name="length"/> will exceed <paramref name="buffer"/> length.
            /// </exception>
            public int ParseBinaryImage(byte[] buffer, int startIndex, int length)
            {
                buffer.ValidateParameters(startIndex, length);

                ArchiveDataBlockPointer blockPointer;

                // Set parsing cursor beyond old-style visual basic array descriptor
                int index = startIndex + ArrayDescriptorLength;

                for (int i = 0; i < m_parent.m_dataBlockCount; i++)
                {
                    blockPointer = new ArchiveDataBlockPointer(m_parent.m_parent, i);
                    index       += blockPointer.ParseBinaryImage(buffer, index, length - (index - startIndex));
                    m_parent.m_dataBlockPointers.Add(blockPointer);
                }

                return(index - startIndex);
            }
Beispiel #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));
        }
Beispiel #5
0
        /// <summary>
        /// Returns an <see cref="ArchiveDataBlock"/> for writing <see cref="ArchiveDataPoint"/>s for the specified <paramref name="historianID"/>.
        /// </summary>
        /// <param name="historianID">Historian identifier for which the <see cref="ArchiveDataBlock"/> is being requested.</param>
        /// <param name="dataTime"><see cref="TimeTag"/> of the <see cref="ArchiveDataPoint"/> to be written to the <see cref="ArchiveDataBlock"/>.</param>
        /// <param name="blockIndex"><see cref="ArchiveDataBlock.Index"/> of the <see cref="ArchiveDataBlock"/> last used for writing <see cref="ArchiveDataPoint"/>s for the <paramref name="historianID"/>.</param>
        /// <returns><see cref="ArchiveDataBlock"/> object if available; otherwise null if all <see cref="ArchiveDataBlock"/>s have been allocated.</returns>
        internal ArchiveDataBlock RequestDataBlock(int historianID, TimeTag dataTime, int blockIndex)
        {
            ArchiveDataBlock        dataBlock        = null;
            ArchiveDataBlockPointer dataBlockPointer = null;

            if (blockIndex >= 0 && blockIndex < m_dataBlockCount)
            {
                // Valid data block index is specified, so retrieve the corresponding data block.
                lock (m_dataBlockPointers)
                {
                    dataBlockPointer = m_dataBlockPointers[blockIndex];
                }

                dataBlock = dataBlockPointer.DataBlock;

                if (!dataBlockPointer.IsAllocated && dataBlock.SlotsUsed > 0)
                {
                    // Clear existing data from the data block since it is unallocated.
                    dataBlock.Reset();
                }
                else if (dataBlockPointer.IsAllocated && (dataBlockPointer.HistorianID != historianID || (dataBlockPointer.HistorianID == historianID && dataBlock.SlotsAvailable == 0)))
                {
                    // Search for a new data block since the suggested data block cannot be used.
                    blockIndex = -1;
                }
            }

            if (blockIndex < 0)
            {
                // Negative data block index is specified indicating a search must be performed for a data block.
                dataBlock = FindLastDataBlock(historianID);

                if ((object)dataBlock != null && dataBlock.SlotsAvailable == 0)
                {
                    // Previously used data block is full.
                    dataBlock = null;
                }

                if ((object)dataBlock == null)
                {
                    // Look for the first unallocated data block.
                    dataBlock = FindDataBlock(-1);

                    if ((object)dataBlock == null)
                    {
                        // Extend the file for historic writes only.
                        if (m_parent.FileType == ArchiveFileType.Historic)
                        {
                            Extend();
                            dataBlock = m_dataBlockPointers[m_dataBlockPointers.Count - 1].DataBlock;
                        }
                    }
                    else
                    {
                        // Reset the unallocated data block if there is data in it.
                        if (dataBlock.SlotsUsed > 0)
                        {
                            dataBlock.Reset();
                        }
                    }
                }

                // Get the pointer to the data block so that its information can be updated if necessary.
                if ((object)dataBlock == null)
                {
                    dataBlockPointer = null;
                }
                else
                {
                    lock (m_dataBlockPointers)
                    {
                        dataBlockPointer = m_dataBlockPointers[dataBlock.Index];
                    }
                }
            }

            if ((object)dataBlockPointer != null && !dataBlockPointer.IsAllocated)
            {
                // Mark the data block as allocated.
                dataBlockPointer.HistorianID = historianID;
                dataBlockPointer.StartTime   = dataTime;

                // Set the file start time if not set.
                if (m_fileStartTime == TimeTag.MinValue)
                {
                    m_fileStartTime = dataTime;
                }

                // Persist data block information to disk.
                lock (m_parent.FileData)
                {
                    // We'll write information about the just allocated data block to the file.
                    m_parent.FileData.Seek(DataLength + ArrayDescriptorLength + (dataBlockPointer.Index * ArchiveDataBlockPointer.FixedLength), SeekOrigin.Begin);
                    dataBlockPointer.CopyBinaryImageToStream(m_parent.FileData);

                    // We'll also write the fixed part of the FAT data that resides at the end.
                    m_parent.FileData.Seek(-m_fixedTableRegion.BinaryLength, SeekOrigin.End);

                    // Copy generated binary image to stream
                    m_fixedTableRegion.CopyBinaryImageToStream(m_parent.FileData);

                    if (!m_parent.CacheWrites)
                    {
                        m_parent.FileData.Flush();
                    }
                }

                // Re-fetch the data block with updated information after allocation.
                dataBlock = dataBlockPointer.DataBlock;
            }

            return(dataBlock);
        }
            /// <summary>
            /// Initializes <see cref="VariableTableRegion"/> by parsing the specified <paramref name="buffer"/> containing a binary image.
            /// </summary>
            /// <param name="buffer">Buffer containing binary image to parse.</param>
            /// <param name="startIndex">0-based starting index in the <paramref name="buffer"/> to start parsing.</param>
            /// <param name="length">Valid number of bytes within <paramref name="buffer"/> from <paramref name="startIndex"/>.</param>
            /// <returns>The number of bytes used for initialization in the <paramref name="buffer"/> (i.e., the number of bytes parsed).</returns>
            /// <exception cref="ArgumentNullException"><paramref name="buffer"/> is null.</exception>
            /// <exception cref="ArgumentOutOfRangeException">
            /// <paramref name="startIndex"/> or <paramref name="length"/> is less than 0 -or- 
            /// <paramref name="startIndex"/> and <paramref name="length"/> will exceed <paramref name="buffer"/> length.
            /// </exception>
            public int ParseBinaryImage(byte[] buffer, int startIndex, int length)
            {
                buffer.ValidateParameters(startIndex, length);

                ArchiveDataBlockPointer blockPointer;

                // Set parsing cursor beyond old-style visual basic array descriptor
                int index = startIndex + ArrayDescriptorLength;

                for (int i = 0; i < m_parent.m_dataBlockCount; i++)
                {
                    blockPointer = new ArchiveDataBlockPointer(m_parent.m_parent, i);
                    index += blockPointer.ParseBinaryImage(buffer, index, length - (index - startIndex));
                    m_parent.m_dataBlockPointers.Add(blockPointer);
                }

                return (index - startIndex);
            }