/// <summary> /// Extends the <see cref="ArchiveFile"/> by the specified number of <see cref="ArchiveDataBlock"/>s. /// </summary> /// <param name="dataBlocksToAdd">Number of <see cref="ArchiveDataBlock"/>s to add to the <see cref="ArchiveFile"/>.</param> public void Extend(int dataBlocksToAdd) { // Extend the FAT. lock (m_dataBlockPointers) { for (int i = 1; i <= dataBlocksToAdd; i++) { m_dataBlockPointers.Add(new ArchiveDataBlockPointer(m_parent, m_dataBlockPointers.Count)); } m_dataBlockCount = m_dataBlockPointers.Count; } Save(); // Initialize newly added data blocks. ArchiveDataBlock dataBlock; for (int i = m_dataBlockCount - dataBlocksToAdd; i < m_dataBlockCount; i++) { dataBlock = new ArchiveDataBlock(m_parent, i, -1); dataBlock.Reset(); } }
/// <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> /// Extends the <see cref="ArchiveFile"/> by the specified number of <see cref="ArchiveDataBlock"/>s. /// </summary> /// <param name="dataBlocksToAdd">Number of <see cref="ArchiveDataBlock"/>s to add to the <see cref="ArchiveFile"/>.</param> public void Extend(int dataBlocksToAdd) { // Extend the FAT. lock (m_dataBlockPointers) { for (int i = 1; i <= dataBlocksToAdd; i++) { m_dataBlockPointers.Add(new ArchiveDataBlockPointer(m_parent, m_dataBlockPointers.Count)); } m_dataBlockCount = m_dataBlockPointers.Count; } Save(); // Initialize newly added data blocks. ArchiveDataBlock dataBlock; for (int i = m_dataBlockCount - dataBlocksToAdd; i < m_dataBlockCount; i++) { dataBlock = new ArchiveDataBlock(m_parent, i, -1); dataBlock.Reset(); } }