|
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime;
using System.ServiceModel.Channels;
using System.ServiceModel.Diagnostics;
using System.Threading;
class ProcessingContext
{
internal ProcessingContext next; // for chaining together in free lists
int nodeCount;
QueryProcessor processor;
EvalStack sequenceStack;
EvalStack valueStack;
internal ProcessingContext()
{
this.valueStack = new EvalStack(2, 4);
this.sequenceStack = new EvalStack(1, 2);
this.nodeCount = -1;
}
#if NO
internal int FrameCount
{
get
{
return this.valueStack.FrameCount;
}
}
internal int FramePtr
{
get
{
return this.valueStack.FramePtr;
}
}
#endif
internal StackFrame this[int frameIndex]
{
get
{
return this.valueStack[frameIndex];
}
}
internal int IterationCount
{
get
{
if (-1 == this.nodeCount)
{
this.nodeCount = this.sequenceStack.CalculateNodecount();
if (this.nodeCount == 0 && !this.sequenceStack.InUse)
{
this.nodeCount = 1;
}
}
return this.nodeCount;
}
}
internal int NodeCount
{
get
{
return this.nodeCount;
}
set
{
this.nodeCount = value;
}
}
internal ProcessingContext Next
{
get
{
return this.next;
}
set
{
this.next = value;
}
}
internal QueryProcessor Processor
{
get
{
return this.processor;
}
set
{
this.processor = value;
}
}
internal StackFrame SecondArg
{
get
{
return this.valueStack.SecondArg;
}
}
internal Value[] Sequences
{
get
{
return this.sequenceStack.Buffer;
}
}
internal bool SequenceStackInUse
{
get
{
return this.sequenceStack.InUse;
}
}
internal bool StacksInUse
{
get
{
return (this.valueStack.frames.Count > 0 || this.sequenceStack.frames.Count > 0);
}
}
internal StackFrame TopArg
{
get
{
return this.valueStack.TopArg;
}
}
internal StackFrame TopSequenceArg
{
get
{
return this.sequenceStack.TopArg;
}
}
internal Value[] Values
{
get
{
return this.valueStack.Buffer;
}
}
internal ProcessingContext Clone()
{
return this.processor.CloneContext(this);
}
internal void ClearContext()
{
this.sequenceStack.Clear();
this.valueStack.Clear();
this.nodeCount = -1;
}
internal void CopyFrom(ProcessingContext context)
{
Fx.Assert(null != context, "");
this.processor = context.processor;
if (context.sequenceStack.frames.Count > 0)
{
this.sequenceStack.CopyFrom(ref context.sequenceStack);
}
else
{
this.sequenceStack.Clear();
}
if (context.valueStack.frames.Count > 0)
{
this.valueStack.CopyFrom(ref context.valueStack);
}
else
{
this.valueStack.Clear();
}
this.nodeCount = context.nodeCount;
}
internal NodeSequence CreateSequence()
{
NodeSequence sequence = this.processor.PopSequence();
if (null == sequence)
{
sequence = new NodeSequence();
}
sequence.OwnerContext = this;
sequence.refCount++;
return sequence;
}
internal bool LoadVariable(int var)
{
return this.Processor.LoadVariable(this, var);
}
internal void EvalCodeBlock(Opcode block)
{
this.processor.Eval(block, this);
}
internal bool PeekBoolean(int index)
{
return this.valueStack.PeekBoolean(index);
}
internal double PeekDouble(int index)
{
return this.valueStack.PeekDouble(index);
}
#if NO
internal int PeekInteger(int index)
{
return (int) this.valueStack.PeekInteger(index);
}
#endif
internal NodeSequence PeekSequence(int index)
{
return this.valueStack.PeekSequence(index);
}
internal string PeekString(int index)
{
return this.valueStack.PeekString(index);
}
internal void PopFrame()
{
this.valueStack.PopFrame(this);
}
internal void PopSequenceFrame()
{
this.sequenceStack.PopFrame(this);
this.nodeCount = -1;
}
internal void PopContextSequenceFrame()
{
PopSequenceFrame();
if (!this.sequenceStack.InUse)
this.sequenceStack.contextOnTopOfStack = false;
}
internal void Push(bool boolVal)
{
this.valueStack.Push(boolVal);
}
internal void Push(bool boolVal, int addCount)
{
this.valueStack.Push(boolVal, addCount);
}
#if NO
internal void Push(double doubleVal)
{
this.valueStack.Push(doubleVal);
}
#endif
internal void Push(double doubleVal, int addCount)
{
this.valueStack.Push(doubleVal, addCount);
}
internal void Push(NodeSequence sequence)
{
this.valueStack.Push(sequence);
}
internal void Push(NodeSequence sequence, int addCount)
{
this.valueStack.Push(sequence, addCount);
}
internal void Push(string stringVal)
{
this.valueStack.Push(stringVal);
}
internal void Push(string stringVal, int addCount)
{
this.valueStack.Push(stringVal, addCount);
}
internal void PushFrame()
{
this.valueStack.PushFrame();
}
internal void PopSequenceFrameToValueStack()
{
this.sequenceStack.PopSequenceFrameTo(ref this.valueStack);
this.nodeCount = -1;
}
internal void PushSequence(NodeSequence seq)
{
this.sequenceStack.Push(seq);
this.nodeCount = -1;
}
internal void PushSequenceFrame()
{
this.sequenceStack.PushFrame();
this.nodeCount = -1;
}
internal void PushContextSequenceFrame()
{
if (!this.sequenceStack.InUse)
this.sequenceStack.contextOnTopOfStack = true;
PushSequenceFrame();
}
internal void PushSequenceFrameFromValueStack()
{
this.valueStack.PopSequenceFrameTo(ref this.sequenceStack);
this.nodeCount = -1;
}
internal void ReleaseSequence(NodeSequence sequence)
{
Fx.Assert(null != sequence, "");
if (this == sequence.OwnerContext)
{
sequence.refCount--;
Fx.Assert(sequence.refCount >= 0, "");
if (0 == sequence.refCount)
{
this.processor.ReleaseSequenceToPool(sequence);
}
}
}
internal void Release()
{
this.processor.ReleaseContext(this);
}
internal void ReplaceSequenceAt(int index, NodeSequence sequence)
{
this.sequenceStack.ReplaceAt(index, sequence);
this.nodeCount = -1;
}
internal void SaveVariable(int var, int count)
{
this.Processor.SaveVariable(this, var, count);
}
internal void SetValue(ProcessingContext context, int index, bool val)
{
this.valueStack.SetValue(this, index, val);
}
internal void SetValue(ProcessingContext context, int index, double val)
{
this.valueStack.SetValue(this, index, val);
}
internal void SetValue(ProcessingContext context, int index, string val)
{
this.valueStack.SetValue(this, index, val);
}
internal void SetValue(ProcessingContext context, int index, NodeSequence val)
{
this.valueStack.SetValue(this, index, val);
}
internal void TransferSequenceSize()
{
this.sequenceStack.TransferSequenceSizeTo(ref this.valueStack);
}
internal void TransferSequencePositions()
{
this.sequenceStack.TransferPositionsTo(ref this.valueStack);
}
#region IQueryBufferPool Members
#if NO
public virtual void Reset()
{
this.valueStack.Clear();
this.valueStack.Trim();
this.sequenceStack.Clear();
this.sequenceStack.Trim();
}
public virtual void Trim()
{
this.valueStack.Trim();
this.sequenceStack.Trim();
}
#endif
#endregion
}
internal enum QueryProcessingFlags : byte
{
None = 0x00,
Match = 0x01,
Message = 0x02,
//Select = 0x04,
}
internal class QueryProcessor : ProcessingContext
{
SeekableXPathNavigator contextNode; // original context node off which everything started
ProcessingContext contextPool;
INodeCounter counter;
QueryProcessingFlags flags;
QueryMatcher matcher;
Message message;
bool matchMessageBody;
int refCount;
bool result; // for singleton matches...
XPathResult queryResult; // for singleton queries...
QueryBranchResultSet resultPool;
Collection<MessageFilter> matchList;
ICollection<MessageFilter> matchSet; // for inverse queries that produce multiple matches
ICollection<KeyValuePair<MessageQuery, XPathResult>> resultSet; // for inverse queries that produce multiple query results
NodeSequence sequencePool;
//string selectResults;
SubExprVariable[] subExprVars;
string messageAction;
//string messageAddress;
//string messageVia;
string messageId;
string messageSoapUri;
string messageTo;
internal QueryProcessor(QueryMatcher matcher)
: base()
{
this.Processor = this;
this.matcher = matcher;
this.flags = QueryProcessingFlags.Match;
// PERF, Microsoft, see if we can just let these to their default init
this.messageAction = null;
//this.messageAddress = null;
//this.messageVia = null;
this.messageId = null;
this.messageSoapUri = null;
this.messageTo = null;
if (matcher.SubExprVarCount > 0)
{
this.subExprVars = new SubExprVariable[matcher.SubExprVarCount];
}
}
internal string Action
{
get
{
return this.messageAction;
}
set
{
this.messageAction = value;
}
}
#if NO
internal string Address
{
get
{
return this.messageAddress;
}
set
{
this.messageAddress = value;
}
}
#endif
// IMPORTANT: Either ContextNode.get or CounterMarker.get MUST be called before this.counter
// can be considered valid.
internal SeekableXPathNavigator ContextNode
{
get
{
if (null == this.contextNode)
{
if (null != this.message)
{
this.contextNode = this.matcher.CreateMessageNavigator(this.message, this.matchMessageBody);
}
else
{
#pragma warning suppress 56503 // Microsoft, property is more readable for this
throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.Unexpected));
}
this.counter = this.contextNode as INodeCounter;
if (null == this.counter)
{
this.counter = DummyNodeCounter.Dummy;
}
}
return this.contextNode;
}
set
{
this.contextNode = value;
this.counter = value as INodeCounter;
}
}
internal Message ContextMessage
{
get
{
return this.message;
}
set
{
this.message = value;
if (null != value)
{
this.flags |= QueryProcessingFlags.Message;
}
else
{
this.flags &= ~QueryProcessingFlags.Message;
}
}
}
// IMPORTANT: Either ContextNode.get or CounterMarker.get MUST be called before this.counter
// can be considered valid.
internal int CounterMarker
{
get
{
if (this.counter == null)
{
this.counter = this.ContextNode as INodeCounter;
if (this.counter == null)
this.counter = DummyNodeCounter.Dummy;
}
return this.counter.CounterMarker;
}
set
{
this.counter.CounterMarker = value;
}
}
#if NO
internal QueryProcessingFlags Flags
{
get
{
return this.flags;
}
}
internal bool HasContextNode
{
get
{
return (null != this.contextNode);
}
}
#endif
internal bool MatchBody
{
#if NO
get
{
return this.matchMessageBody;
}
#endif
set
{
this.matchMessageBody = value;
}
}
internal QueryMatcher Matcher
{
get
{
return this.matcher;
}
}
internal ICollection<KeyValuePair<MessageQuery, XPathResult>> ResultSet
{
get
{
return this.resultSet;
}
set
{
this.resultSet = value;
}
}
internal string MessageId
{
get
{
return this.messageId;
}
set
{
this.messageId = value;
}
}
internal bool Result
{
get
{
return this.result;
}
set
{
this.result = value;
}
}
internal XPathResult QueryResult
{
get
{
return this.queryResult;
}
set
{
this.queryResult = value;
}
}
internal Collection<MessageFilter> MatchList
{
get
{
return this.matchList;
}
}
internal ICollection<MessageFilter> MatchSet
{
get
{
return this.matchSet;
}
set
{
this.matchSet = value;
}
}
internal string SoapUri
{
get
{
return this.messageSoapUri;
}
set
{
this.messageSoapUri = value;
}
}
internal string ToHeader
{
get
{
return this.messageTo;
}
set
{
this.messageTo = value;
}
}
#if NO
internal string Via
{
get
{
return this.messageVia;
}
set
{
this.messageVia = value;
}
}
#endif
internal void AddRef()
{
Interlocked.Increment(ref this.refCount);
}
internal void ClearProcessor()
{
base.ClearContext();
this.flags = QueryProcessingFlags.Match;
this.messageAction = null;
//this.messageAddress = null;
//this.messageVia = null;
this.messageId = null;
this.messageSoapUri = null;
this.messageTo = null;
int exprCount = this.matcher.SubExprVarCount;
if (exprCount == 0)
{
// No vars. Recycle entire subexpression cache
this.subExprVars = null;
return;
}
SubExprVariable[] vars = this.subExprVars; // save locally for speed
if (vars == null)
{
// Allocate space for sub-expressions
this.subExprVars = new SubExprVariable[exprCount];
return;
}
int varCount = vars.Length;
// The # of subexpressions changed since this processor was last used.
if (varCount != exprCount)
{
this.subExprVars = new SubExprVariable[exprCount];
return;
}
if (varCount == 1)
{
NodeSequence seq = vars[0].seq;
if (seq != null)
{
this.ReleaseSequenceToPool(seq);
}
return;
}
// We can reuse the sub-expression cache
// Clear out the sub-expression results from an earlier run, and return sequences to pool
for (int i = 0; i < varCount; ++i)
{
NodeSequence seq = vars[i].seq;
if (seq != null && seq.refCount > 0)
{
this.ReleaseSequenceToPool(seq);
}
}
Array.Clear(vars, 0, vars.Length);
}
internal ProcessingContext CloneContext(ProcessingContext srcContext)
{
ProcessingContext context = this.PopContext();
if (null == context)
{
context = new ProcessingContext();
}
context.CopyFrom(srcContext);
return context;
}
internal QueryBranchResultSet CreateResultSet()
{
QueryBranchResultSet resultSet = this.PopResultSet();
if (null == resultSet)
{
resultSet = new QueryBranchResultSet();
}
else
{
resultSet.Clear();
}
return resultSet;
}
internal int ElapsedCount(int marker)
{
return this.counter.ElapsedCount(marker);
}
internal void EnsureFilterCollection()
{
this.resultSet = null;
if (null == this.matchSet)
{
if (null == this.matchList)
{
this.matchList = new Collection<MessageFilter>();
}
else
{
this.matchList.Clear();
}
this.matchSet = this.matchList;
}
}
internal void Eval(Opcode block)
{
Opcode op = block;
try
{
// Walk over and evaulate the entire trace
while (null != op)
{
op = op.Eval(this);
}
}
catch (XPathNavigatorException e)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(op));
}
catch (NavigatorInvalidBodyAccessException e)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(op));
}
}
internal void Eval(Opcode block, ProcessingContext context)
{
Opcode op = block;
try
{
// Walk over and evaulate the entire trace
while (null != op)
{
op = op.Eval(context);
}
}
catch (XPathNavigatorException e)
{
throw TraceUtility.ThrowHelperError(e.Process(op), this.message);
}
catch (NavigatorInvalidBodyAccessException e)
{
throw TraceUtility.ThrowHelperError(e.Process(op), this.message);
}
}
//
// Set up the query processor to match messages
//
internal void Eval(Opcode block, Message message, bool matchBody)
{
this.result = false;
this.ContextNode = null;
this.ContextMessage = message;
this.MatchBody = matchBody;
this.Eval(block);
this.message = null;
this.contextNode = null;
}
internal void Eval(Opcode block, SeekableXPathNavigator navigator)
{
this.result = false;
this.ContextNode = navigator;
this.ContextMessage = null;
this.Eval(block);
}
internal bool LoadVariable(ProcessingContext context, int var)
{
if (this.subExprVars[var].seq == null)
{
return false;
}
int iter = context.IterationCount;
this.counter.IncreaseBy(iter * this.subExprVars[var].count);
NodeSequence seq = this.subExprVars[var].seq;
context.PushSequenceFrame();
for (int i = 0; i < iter; ++i)
{
seq.refCount++;
context.PushSequence(seq);
}
return true;
}
internal ProcessingContext PopContext()
{
ProcessingContext context = this.contextPool;
if (null != context)
{
this.contextPool = context.Next;
context.Next = null;
}
return context;
}
internal NodeSequence PopSequence()
{
NodeSequence sequence = this.sequencePool;
if (null != sequence)
{
this.sequencePool = sequence.Next;
sequence.Next = null;
}
return sequence;
}
internal QueryBranchResultSet PopResultSet()
{
QueryBranchResultSet resultSet = this.resultPool;
if (null != resultSet)
{
this.resultPool = resultSet.Next;
resultSet.Next = null;
}
return resultSet;
}
internal void PushContext(ProcessingContext context)
{
Fx.Assert(null != context, "");
context.Next = this.contextPool;
this.contextPool = context;
}
internal void PushResultSet(QueryBranchResultSet resultSet)
{
Fx.Assert(null != resultSet, "");
resultSet.Next = this.resultPool;
this.resultPool = resultSet;
}
internal bool ReleaseRef()
{
return (Interlocked.Decrement(ref this.refCount) == 0);
}
internal void ReleaseContext(ProcessingContext context)
{
Fx.Assert(null != context, "");
this.PushContext(context);
}
internal void ReleaseResults(QueryBranchResultSet resultSet)
{
Fx.Assert(null != resultSet, "");
this.PushResultSet(resultSet);
}
internal void ReleaseSequenceToPool(NodeSequence sequence)
{
if (NodeSequence.Empty != sequence)
{
sequence.Reset(this.sequencePool);
this.sequencePool = sequence;
}
}
internal void SaveVariable(ProcessingContext context, int var, int count)
{
NodeSequence seq = context.Sequences[context.TopSequenceArg.basePtr].Sequence;
if (seq == null)
seq = CreateSequence();
seq.OwnerContext = null;
this.subExprVars[var].seq = seq;
this.subExprVars[var].count = count;
}
#region IQueryBufferPool Members
#if NO
public override void Reset()
{
base.Release();
// Trim local pools by releasing all references
while (null != this.PopResultSet());
this.resultPool = null;
while (null != this.PopSequence());
this.sequencePool = null;
while (null != this.PopContext());
this.contextPool = null;
}
public override void Trim()
{
// Trim stacks
base.Trim();
// Trim local pools individually
QueryBranchResultSet result = this.resultPool;
while (null != result)
{
result.Trim();
result = result.Next;
}
NodeSequence sequence = this.sequencePool;
while (null != sequencePool)
{
sequencePool.Trim();
sequence = sequence.Next;
}
ProcessingContext context = this.contextPool;
while (null != context)
{
context.Trim();
context = context.Next;
}
}
#endif
#endregion
struct SubExprVariable
{
internal NodeSequence seq;
internal int count;
}
}
#if NO
internal struct QueryStatistics
{
int backupCapacity;
int nodeCapacity;
int seqStackCapacity;
int seqFrameCapacity;
int valFrameCapacity;
int valStackCapacity;
internal QueryStatistics()
{
this.backupCapacity = 8;
this.nodeCapacity = 8;
this.seqFrameCapacity = 2;
this.seqStackCapacity = 4;
this.valFrameCapacity = 2;
this.valStackCapacity = 4;
}
internal int BackupCapacity
{
get
{
return this.backupCapacity;
}
}
internal int NodeCapacity
{
get
{
return this.nodeCapacity;
}
}
internal int SeqFrameCapacity
{
get
{
return this.seqFrameCapacity;
}
}
internal int SeqStackCapacity
{
get
{
return this.seqStackCapacity;
}
}
internal int ValFrameCapacity
{
get
{
return this.valFrameCapacity;
}
}
internal int ValStackCapacity
{
get
{
return this.valStackCapacity;
}
}
}
#endif
}
|