/// <summary> /// Reads the history for a single node which has already been validated. /// </summary> protected virtual ServiceResult HistoryRead( ISystemContext context, NodeState source, HistoryReadDetails details, TimestampsToReturn timestampsToReturn, bool releaseContinuationPoints, HistoryReadValueId nodesToRead, HistoryReadResult result) { // check for variable. BaseVariableState variable = source as BaseVariableState; if (variable == null) { return StatusCodes.BadHistoryOperationUnsupported; } // check for access. lock (Lock) { if ((variable.AccessLevel & AccessLevels.HistoryRead) == 0) { return StatusCodes.BadNotReadable; } } // handle read raw. ReadRawModifiedDetails readRawDetails = details as ReadRawModifiedDetails; if (readRawDetails != null) { return HistoryReadRaw( context, variable, readRawDetails, timestampsToReturn, releaseContinuationPoints, nodesToRead, result); } // handle read processed. ReadProcessedDetails readProcessedDetails = details as ReadProcessedDetails; if (readProcessedDetails != null) { return HistoryReadProcessed( context, variable, readProcessedDetails, timestampsToReturn, releaseContinuationPoints, nodesToRead, result); } // handle read processed. ReadAtTimeDetails readAtTimeDetails = details as ReadAtTimeDetails; if (readAtTimeDetails != null) { return HistoryReadAtTime( context, variable, readAtTimeDetails, timestampsToReturn, releaseContinuationPoints, nodesToRead, result); } return StatusCodes.BadHistoryOperationUnsupported; }
/// <summary> /// Reads the history for the specified nodes. /// </summary> public virtual void HistoryRead( OperationContext context, HistoryReadDetails details, TimestampsToReturn timestampsToReturn, bool releaseContinuationPoints, IList<HistoryReadValueId> nodesToRead, IList<HistoryReadResult> results, IList<ServiceResult> errors) { ServerSystemContext systemContext = m_systemContext.Copy(context); IDictionary<NodeId,NodeState> operationCache = new NodeIdDictionary<NodeState>(); List<ReadWriteOperationState> nodesToValidate = new List<ReadWriteOperationState>(); List<ReadWriteOperationState> readsToComplete = new List<ReadWriteOperationState>(); lock (Lock) { for (int ii = 0; ii < nodesToRead.Count; ii++) { HistoryReadValueId nodeToRead = nodesToRead[ii]; // skip items that have already been processed. if (nodeToRead.Processed) { continue; } // check for valid handle. NodeState source = GetManagerHandle(systemContext, nodeToRead.NodeId, operationCache) as NodeState; if (source == null) { continue; } // owned by this node manager. nodeToRead.Processed = true; // only variables supported. BaseVariableState variable = source as BaseVariableState; if (variable == null) { errors[ii] = StatusCodes.BadHistoryOperationUnsupported; continue; } results[ii] = new HistoryReadResult(); ReadWriteOperationState operation = new ReadWriteOperationState(); operation.Source = source; operation.Index = ii; // check if the node is ready for reading. if (source.ValidationRequired) { // must validate node in a seperate operation. errors[ii] = StatusCodes.BadNodeIdUnknown; nodesToValidate.Add(operation); continue; } // read the data. readsToComplete.Add(operation); } // validates the nodes (reads values from the underlying data source if required). for (int ii = 0; ii < nodesToValidate.Count; ii++) { ReadWriteOperationState operation = nodesToValidate[ii]; if (!ValidateNode(systemContext, operation.Source)) { continue; } readsToComplete.Add(operation); } } // reads the data without holding onto the lock. for (int ii = 0; ii < readsToComplete.Count; ii++) { ReadWriteOperationState operation = readsToComplete[ii]; errors[operation.Index] = HistoryRead( systemContext, operation.Source, details, timestampsToReturn, releaseContinuationPoints, nodesToRead[operation.Index], results[operation.Index]); } }