PageRenderTime 39ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/referencesource/System.Core/System/Linq/Parallel/QueryOperators/PartitionerQueryOperator.cs

https://github.com/kumpera/mono
C# | 276 lines | 184 code | 49 blank | 43 comment | 26 complexity | eed9570c6e880cb8ba9a7d79efef3d46 MD5 | raw file
Possible License(s): GPL-2.0, CC-BY-SA-3.0, Unlicense
  1. // ==++==
  2. //
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. //
  5. // ==--==
  6. // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
  7. //
  8. // PartitionerQueryOperator.cs
  9. //
  10. // <OWNER>Microsoft</OWNER>
  11. //
  12. // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  13. using System;
  14. using System.Collections.Generic;
  15. using System.Linq;
  16. using System.Text;
  17. using System.Collections.Concurrent;
  18. using System.Linq.Parallel;
  19. using System.Diagnostics.Contracts;
  20. using System.Threading;
  21. #if SILVERLIGHT
  22. using System.Core; // for System.Core.SR
  23. #endif
  24. namespace System.Linq.Parallel
  25. {
  26. /// <summary>
  27. /// A QueryOperator that represents the output of the query partitioner.AsParallel().
  28. /// </summary>
  29. internal class PartitionerQueryOperator<TElement> : QueryOperator<TElement>
  30. {
  31. private Partitioner<TElement> m_partitioner; // The partitioner to use as data source.
  32. internal PartitionerQueryOperator(Partitioner<TElement> partitioner)
  33. : base(false, QuerySettings.Empty)
  34. {
  35. m_partitioner = partitioner;
  36. }
  37. internal bool Orderable
  38. {
  39. get { return m_partitioner is OrderablePartitioner<TElement>; }
  40. }
  41. internal override QueryResults<TElement> Open(QuerySettings settings, bool preferStriping)
  42. {
  43. // Notice that the preferStriping argument is not used. Partitioner<T> does not support
  44. // striped partitioning.
  45. return new PartitionerQueryOperatorResults(m_partitioner, settings);
  46. }
  47. //---------------------------------------------------------------------------------------
  48. // Returns an enumerable that represents the query executing sequentially.
  49. //
  50. internal override IEnumerable<TElement> AsSequentialQuery(CancellationToken token)
  51. {
  52. using (IEnumerator<TElement> enumerator = m_partitioner.GetPartitions(1)[0])
  53. {
  54. while (enumerator.MoveNext())
  55. {
  56. yield return enumerator.Current;
  57. }
  58. }
  59. }
  60. //---------------------------------------------------------------------------------------
  61. // The state of the order index of the results returned by this operator.
  62. //
  63. internal override OrdinalIndexState OrdinalIndexState
  64. {
  65. get { return GetOrdinalIndexState(m_partitioner); }
  66. }
  67. /// <summary>
  68. /// Determines the OrdinalIndexState for a partitioner
  69. /// </summary>
  70. internal static OrdinalIndexState GetOrdinalIndexState(Partitioner<TElement> partitioner)
  71. {
  72. OrderablePartitioner<TElement> orderablePartitioner = partitioner as OrderablePartitioner<TElement>;
  73. if (orderablePartitioner == null)
  74. {
  75. return OrdinalIndexState.Shuffled;
  76. }
  77. if (orderablePartitioner.KeysOrderedInEachPartition)
  78. {
  79. if (orderablePartitioner.KeysNormalized)
  80. {
  81. return OrdinalIndexState.Correct;
  82. }
  83. else
  84. {
  85. return OrdinalIndexState.Increasing;
  86. }
  87. }
  88. else
  89. {
  90. return OrdinalIndexState.Shuffled;
  91. }
  92. }
  93. //---------------------------------------------------------------------------------------
  94. // Whether this operator performs a premature merge that would not be performed in
  95. // a similar sequential operation (i.e., in LINQ to Objects).
  96. //
  97. internal override bool LimitsParallelism
  98. {
  99. get { return false; }
  100. }
  101. /// <summary>
  102. /// QueryResults for a PartitionerQueryOperator
  103. /// </summary>
  104. private class PartitionerQueryOperatorResults : QueryResults<TElement>
  105. {
  106. private Partitioner<TElement> m_partitioner; // The data source for the query
  107. private QuerySettings m_settings; // Settings collected from the query
  108. internal PartitionerQueryOperatorResults(Partitioner<TElement> partitioner, QuerySettings settings)
  109. {
  110. m_partitioner = partitioner;
  111. m_settings = settings;
  112. }
  113. internal override void GivePartitionedStream(IPartitionedStreamRecipient<TElement> recipient)
  114. {
  115. Contract.Assert(m_settings.DegreeOfParallelism.HasValue);
  116. int partitionCount = m_settings.DegreeOfParallelism.Value;
  117. OrderablePartitioner<TElement> orderablePartitioner = m_partitioner as OrderablePartitioner<TElement>;
  118. // If the partitioner is not orderable, it will yield zeros as order keys. The order index state
  119. // is irrelevant.
  120. OrdinalIndexState indexState = (orderablePartitioner != null)
  121. ? GetOrdinalIndexState(orderablePartitioner)
  122. : OrdinalIndexState.Shuffled;
  123. PartitionedStream<TElement, int> partitions = new PartitionedStream<TElement, int>(
  124. partitionCount,
  125. Util.GetDefaultComparer<int>(),
  126. indexState);
  127. if (orderablePartitioner != null)
  128. {
  129. IList<IEnumerator<KeyValuePair<long, TElement>>> partitionerPartitions =
  130. orderablePartitioner.GetOrderablePartitions(partitionCount);
  131. if (partitionerPartitions == null)
  132. {
  133. throw new InvalidOperationException(SR.GetString(SR.PartitionerQueryOperator_NullPartitionList));
  134. }
  135. if (partitionerPartitions.Count != partitionCount)
  136. {
  137. throw new InvalidOperationException(SR.GetString(SR.PartitionerQueryOperator_WrongNumberOfPartitions));
  138. }
  139. for (int i = 0; i < partitionCount; i++)
  140. {
  141. IEnumerator<KeyValuePair<long, TElement>> partition = partitionerPartitions[i];
  142. if (partition == null)
  143. {
  144. throw new InvalidOperationException(SR.GetString(SR.PartitionerQueryOperator_NullPartition));
  145. }
  146. partitions[i] = new OrderablePartitionerEnumerator(partition);
  147. }
  148. }
  149. else
  150. {
  151. IList<IEnumerator<TElement>> partitionerPartitions =
  152. m_partitioner.GetPartitions(partitionCount);
  153. if (partitionerPartitions == null)
  154. {
  155. throw new InvalidOperationException(SR.GetString(SR.PartitionerQueryOperator_NullPartitionList));
  156. }
  157. if (partitionerPartitions.Count != partitionCount)
  158. {
  159. throw new InvalidOperationException(SR.GetString(SR.PartitionerQueryOperator_WrongNumberOfPartitions));
  160. }
  161. for (int i = 0; i < partitionCount; i++)
  162. {
  163. IEnumerator<TElement> partition = partitionerPartitions[i];
  164. if (partition == null)
  165. {
  166. throw new InvalidOperationException(SR.GetString(SR.PartitionerQueryOperator_NullPartition));
  167. }
  168. partitions[i] = new PartitionerEnumerator(partition);
  169. }
  170. }
  171. recipient.Receive<int>(partitions);
  172. }
  173. }
  174. /// <summary>
  175. /// Enumerator that converts an enumerator over key-value pairs exposed by a partitioner
  176. /// to a QueryOperatorEnumerator used by PLINQ internally.
  177. /// </summary>
  178. private class OrderablePartitionerEnumerator : QueryOperatorEnumerator<TElement, int>
  179. {
  180. private IEnumerator<KeyValuePair<long, TElement>> m_sourceEnumerator;
  181. internal OrderablePartitionerEnumerator(IEnumerator<KeyValuePair<long, TElement>> sourceEnumerator)
  182. {
  183. m_sourceEnumerator = sourceEnumerator;
  184. }
  185. internal override bool MoveNext(ref TElement currentElement, ref int currentKey)
  186. {
  187. if (!m_sourceEnumerator.MoveNext()) return false;
  188. KeyValuePair<long, TElement> current = m_sourceEnumerator.Current;
  189. currentElement = current.Value;
  190. checked
  191. {
  192. currentKey = (int)current.Key;
  193. }
  194. return true;
  195. }
  196. protected override void Dispose(bool disposing)
  197. {
  198. Contract.Assert(m_sourceEnumerator != null);
  199. m_sourceEnumerator.Dispose();
  200. }
  201. }
  202. /// <summary>
  203. /// Enumerator that converts an enumerator over key-value pairs exposed by a partitioner
  204. /// to a QueryOperatorEnumerator used by PLINQ internally.
  205. /// </summary>
  206. private class PartitionerEnumerator : QueryOperatorEnumerator<TElement, int>
  207. {
  208. private IEnumerator<TElement> m_sourceEnumerator;
  209. internal PartitionerEnumerator(IEnumerator<TElement> sourceEnumerator)
  210. {
  211. m_sourceEnumerator = sourceEnumerator;
  212. }
  213. internal override bool MoveNext(ref TElement currentElement, ref int currentKey)
  214. {
  215. if (!m_sourceEnumerator.MoveNext()) return false;
  216. currentElement = m_sourceEnumerator.Current;
  217. currentKey = 0;
  218. return true;
  219. }
  220. protected override void Dispose(bool disposing)
  221. {
  222. Contract.Assert(m_sourceEnumerator != null);
  223. m_sourceEnumerator.Dispose();
  224. }
  225. }
  226. }
  227. }