Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / System / Linq / Parallel / QueryOperators / QueryOperator.cs / 1305376 / QueryOperator.cs
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// QueryOperator.cs
//
// [....]
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics.Contracts;
namespace System.Linq.Parallel
{
///
/// This is the abstract base class for all query operators in the system. It
/// implements the ParallelQuery{T} type so that it can be bound as the source
/// of parallel queries and so that it can be returned as the result of parallel query
/// operations. Not much is in here, although it does serve as the "entry point" for
/// opening all query operators: it will lazily analyze and cache a plan the first
/// time the tree is opened, and will open the tree upon calls to GetEnumerator.
///
/// Notes:
/// This class implements ParallelQuery so that any parallel query operator
/// can bind to the parallel query provider overloads. This allows us to string
/// together operators w/out the user always specifying AsParallel, e.g.
/// Select(Where(..., ...), ...), and so forth.
///
///
internal abstract class QueryOperator : ParallelQuery
{
protected bool m_outputOrdered;
internal QueryOperator(QuerySettings settings)
:this(false, settings)
{
}
internal QueryOperator(bool isOrdered, QuerySettings settings)
:base(settings)
{
m_outputOrdered = isOrdered;
}
//----------------------------------------------------------------------------------------
// Opening the query operator will do whatever is necessary to begin enumerating its
// results. This includes in some cases actually introducing parallelism, enumerating
// other query operators, and so on. This is abstract and left to the specific concrete
// operator classes to implement.
//
// Arguments:
// settings - various flags and settings to control query execution
// preferStriping - flag representing whether the caller prefers striped partitioning
// over range partitioning
//
// Return Values:
// Either a single enumerator, or a partition (for partition parallelism).
//
internal abstract QueryResults Open(QuerySettings settings, bool preferStriping);
//---------------------------------------------------------------------------------------
// The GetEnumerator method is the standard IEnumerable mechanism for walking the
// contents of a query. Note that GetEnumerator is only ever called on the root node:
// we then proceed by calling Open on all of the subsequent query nodes.
//
// Arguments:
// usePipelining - whether the returned enumerator will pipeline (i.e. return
// control to the caller when the query is spawned) or not
// (i.e. use the calling thread to execute the query). Note
// that there are some conditions during which this hint will
// be ignored -- currently, that happens only if a sort is
// found anywhere in the query graph.
// suppressOrderPreservation - whether to shut order preservation off, regardless
// of the contents of the query
//
// Return Value:
// An enumerator that retrieves elements from the query output.
//
// Notes:
// The default mode of execution is to pipeline the query execution with respect
// to the GetEnumerator caller (aka the consumer). An overload is available
// that can be used to override the default with an explicit choice.
//
public override IEnumerator GetEnumerator()
{
// Buffering is unspecified and order preservation is not suppressed.
return GetEnumerator(null, false);
}
public IEnumerator GetEnumerator(ParallelMergeOptions? mergeOptions)
{
// Pass through the value supplied for pipelining, and do not suppress
// order preservation by default.
return GetEnumerator(mergeOptions, false);
}
//---------------------------------------------------------------------------------------
// Is the output of this operator ordered?
//
internal bool OutputOrdered
{
get { return m_outputOrdered; }
}
internal virtual IEnumerator GetEnumerator(ParallelMergeOptions? mergeOptions, bool suppressOrderPreservation)
{
// Return a dummy enumerator that will call back GetOpenedEnumerator() on 'this' QueryOperator
// the first time the user calls MoveNext(). We do this to prevent executing the query if user
// never calls MoveNext().
return new QueryOpeningEnumerator(this, mergeOptions, suppressOrderPreservation);
}
//---------------------------------------------------------------------------------------
// The GetOpenedEnumerator method return an enumerator that walks the contents of a query.
// The enumerator will be "opened", which means that PLINQ will start executing the query
// immediately, even before the user calls MoveNext() for the first time.
//
internal IEnumerator GetOpenedEnumerator(ParallelMergeOptions? mergeOptions, bool suppressOrder, bool forEffect,
QuerySettings querySettings)
{
// If the top-level enumerator forces a premature merge, run the query sequentially.
if (querySettings.ExecutionMode.Value == ParallelExecutionMode.Default && LimitsParallelism)
{
IEnumerable opSequential = AsSequentialQuery(querySettings.CancellationState.ExternalCancellationToken);
return ExceptionAggregator.WrapEnumerable(opSequential, querySettings.CancellationState).GetEnumerator();
}
QueryResults queryResults = GetQueryResults(querySettings);
if (mergeOptions == null)
{
mergeOptions = querySettings.MergeOptions;
}
Contract.Assert(mergeOptions != null);
// Top-level pre-emptive cancellation test.
// This handles situations where cancellation has occured before execution commences
// The handling for in-execution occurs in QueryTaskGroupState.QueryEnd()
if(querySettings.CancellationState.MergedCancellationToken.IsCancellationRequested)
{
if (querySettings.CancellationState.ExternalCancellationToken.IsCancellationRequested)
throw new OperationCanceledException(querySettings.CancellationState.ExternalCancellationToken);
else
throw new OperationCanceledException();
}
bool orderedMerge = OutputOrdered && !suppressOrder;
PartitionedStreamMerger merger = new PartitionedStreamMerger(forEffect, mergeOptions.GetValueOrDefault(),
querySettings.TaskScheduler,
orderedMerge,
querySettings.CancellationState,
querySettings.QueryId);
queryResults.GivePartitionedStream(merger); // hook up the data flow between the operator-executors, starting from the merger.
if (forEffect)
{
return null;
}
return merger.MergeExecutor.GetEnumerator();
}
// This method is called only once on the 'head operator' which is the last specified operator in the query
// This method then recursively uses Open() to prepare itself and the other enumerators.
private QueryResults GetQueryResults(QuerySettings querySettings)
{
TraceHelpers.TraceInfo("[timing]: {0}: starting execution - QueryOperator<>::GetQueryResults", DateTime.Now.Ticks);
// All mandatory query settings must be specified
Contract.Assert(querySettings.TaskScheduler != null);
Contract.Assert(querySettings.DegreeOfParallelism.HasValue);
Contract.Assert(querySettings.ExecutionMode.HasValue);
// Now just open the query tree's root operator, supplying a specific DOP
return Open(querySettings, false);
}
//----------------------------------------------------------------------------------------
// Executes the query and returns the results in an array.
//
internal TOutput[] ExecuteAndGetResultsAsArray()
{
QuerySettings querySettings =
SpecifiedQuerySettings
.WithPerExecutionSettings()
.WithDefaults();
QueryLifecycle.LogicalQueryExecutionBegin(querySettings.QueryId);
try
{
if (querySettings.ExecutionMode.Value == ParallelExecutionMode.Default && LimitsParallelism)
{
IEnumerable opSequential = AsSequentialQuery(querySettings.CancellationState.ExternalCancellationToken);
IEnumerable opSequentialWithCancelChecks = CancellableEnumerable.Wrap(opSequential, querySettings.CancellationState.ExternalCancellationToken);
return ExceptionAggregator.WrapEnumerable(opSequentialWithCancelChecks, querySettings.CancellationState).ToArray();
}
QueryResults results = GetQueryResults(querySettings);
if (results.IsIndexible && OutputOrdered)
{
// The special array-based merge performs better if the output is ordered, because
// it does not have to pay for ordering. In the unordered case, we it appears that
// the stop-and-go merge performs a little better.
ArrayMergeHelper merger = new ArrayMergeHelper(SpecifiedQuerySettings, results);
merger.Execute();
TOutput[] output = merger.GetResultsAsArray();
querySettings.CleanStateAtQueryEnd();
return output;
}
else
{
PartitionedStreamMerger merger =
new PartitionedStreamMerger(false, ParallelMergeOptions.FullyBuffered, querySettings.TaskScheduler,
OutputOrdered, querySettings.CancellationState, querySettings.QueryId);
results.GivePartitionedStream(merger);
TOutput[] output = merger.MergeExecutor.GetResultsAsArray();
querySettings.CleanStateAtQueryEnd();
return output;
}
}
finally
{
QueryLifecycle.LogicalQueryExecutionEnd(querySettings.QueryId);
}
}
//---------------------------------------------------------------------------------------
// Returns an enumerable that represents the query executing sequentially.
//
// Note that iterating the returned enumerable will not wrap exceptions AggregateException.
// Before this enumerable is returned to the user, we must wrap it with an
// ExceptionAggregator.
//
internal abstract IEnumerable AsSequentialQuery(CancellationToken token);
//----------------------------------------------------------------------------------------
// Whether this operator performs a premature merge.
//
internal abstract bool LimitsParallelism { get; }
//----------------------------------------------------------------------------------------
// The state of the order index of the results returned by this operator.
//
internal abstract OrdinalIndexState OrdinalIndexState { get; }
//---------------------------------------------------------------------------------------
// A helper method that executes the query rooted at the openedChild operator, and returns
// the results as ListQueryResults.
//
internal static ListQueryResults ExecuteAndCollectResults(
PartitionedStream openedChild,
int partitionCount,
bool outputOrdered,
bool useStriping,
QuerySettings settings)
{
TaskScheduler taskScheduler = settings.TaskScheduler;
MergeExecutor executor = MergeExecutor.Execute(
openedChild, false, ParallelMergeOptions.FullyBuffered, taskScheduler, outputOrdered,
settings.CancellationState, settings.QueryId);
return new ListQueryResults(executor.GetResultsAsArray(), partitionCount, useStriping);
}
//----------------------------------------------------------------------------------------
// Returns a QueryOperator for any IEnumerable data source. This will just do a
// cast and return a reference to the same data source if the source is another query
// operator, but will lazily allocate a scan operation and return that otherwise.
//
// Arguments:
// source - any enumerable data source to be wrapped
//
// Return Value:
// A query operator.
//
internal static QueryOperator AsQueryOperator(IEnumerable source)
{
Contract.Assert(source != null);
// Just try casting the data source to a query operator, in the case that
// our child is just another query operator.
QueryOperator sourceAsOperator = source as QueryOperator;
if (sourceAsOperator == null)
{
OrderedParallelQuery orderedQuery = source as OrderedParallelQuery;
if (orderedQuery != null)
{
// We have to handle OrderedParallelQuery specially. In all other cases,
// ParallelQuery *is* the QueryOperator. But, OrderedParallelQuery
// is not QueryOperator, it only has a reference to one. Ideally, we
// would want SortQueryOperator to inherit from OrderedParallelQuery,
// but that conflicts with other constraints on our class hierarchy.
sourceAsOperator = (QueryOperator)orderedQuery.SortOperator;
}
else
{
// If the cast failed, then the data source is a real piece of data. We
// just construct a new scan operator on top of it.
sourceAsOperator = new ScanQueryOperator(source);
}
}
Contract.Assert(sourceAsOperator != null);
return sourceAsOperator;
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DtrList.cs
- IRCollection.cs
- Memoizer.cs
- PersistChildrenAttribute.cs
- Vector3DIndependentAnimationStorage.cs
- IDataContractSurrogate.cs
- SQLBytes.cs
- VirtualDirectoryMappingCollection.cs
- TransactionProxy.cs
- EmptyTextWriter.cs
- ExpressionPrefixAttribute.cs
- StructuralType.cs
- StateManagedCollection.cs
- CompatibleIComparer.cs
- ExecutedRoutedEventArgs.cs
- OleDbEnumerator.cs
- ObjectStateEntryBaseUpdatableDataRecord.cs
- HwndSource.cs
- DrawingDrawingContext.cs
- TableCell.cs
- GridItemPatternIdentifiers.cs
- ResourceReader.cs
- BamlVersionHeader.cs
- TcpClientSocketManager.cs
- PageHandlerFactory.cs
- AccessKeyManager.cs
- WorkflowInstance.cs
- DesignerTransaction.cs
- SourceFileBuildProvider.cs
- UniqueConstraint.cs
- ListBoxChrome.cs
- WebPartDisplayModeCancelEventArgs.cs
- SqlTrackingQuery.cs
- DataServiceConfiguration.cs
- IssuedSecurityTokenProvider.cs
- GeometryGroup.cs
- NavigatorInput.cs
- TreeViewEvent.cs
- PermissionListSet.cs
- DbFunctionCommandTree.cs
- XmlStreamStore.cs
- LazyTextWriterCreator.cs
- CommonDialog.cs
- SortDescription.cs
- CodeTypeMemberCollection.cs
- ResourcePermissionBase.cs
- XmlILStorageConverter.cs
- InternalCache.cs
- ApplicationHost.cs
- ClockGroup.cs
- SystemIPInterfaceProperties.cs
- RotateTransform.cs
- EventManager.cs
- DataStorage.cs
- ToolboxItemAttribute.cs
- BuildResultCache.cs
- Fonts.cs
- IteratorFilter.cs
- BamlResourceSerializer.cs
- InternalUserCancelledException.cs
- ByteKeyFrameCollection.cs
- SqlDataSourceCache.cs
- SQLInt16Storage.cs
- DataGridViewCellStateChangedEventArgs.cs
- XmlSchemaNotation.cs
- StringDictionary.cs
- CodeExpressionStatement.cs
- QuaternionKeyFrameCollection.cs
- URLAttribute.cs
- basecomparevalidator.cs
- UnsafeNetInfoNativeMethods.cs
- StaticTextPointer.cs
- filewebrequest.cs
- QuaternionAnimationBase.cs
- UndoManager.cs
- ConditionedDesigner.cs
- SByteConverter.cs
- AsyncCallback.cs
- ImageField.cs
- TextEditorParagraphs.cs
- AttributeUsageAttribute.cs
- CompModSwitches.cs
- ConnectionManagementElementCollection.cs
- FilterException.cs
- SelectionRangeConverter.cs
- WsdlContractConversionContext.cs
- IpcClientChannel.cs
- HealthMonitoringSectionHelper.cs
- Calendar.cs
- WebPartManagerDesigner.cs
- DateTimeAutomationPeer.cs
- BitmapEffectGroup.cs
- TextDpi.cs
- MethodBuilder.cs
- PluralizationService.cs
- ParseElementCollection.cs
- ButtonChrome.cs
- GradientStop.cs
- ProfileSection.cs
- ExceptionRoutedEventArgs.cs