Exemple #1
0
        //---------------------------------------------------------------------------------------
        // MoveNext will invoke the entire query sub-tree, accumulating results into a hash-
        // table, upon the first call. Then for the first call and all subsequent calls, we will
        // just enumerate the key-set from the hash-table, retrieving groupings of key-elements.
        //

        internal override bool MoveNext(ref IGrouping <TGroupKey, TElement> currentElement, ref TOrderKey currentKey)
        {
            Debug.Assert(_source != null);
            Debug.Assert(_keySelector != null);

            // Lazy-init the mutable state. This also means we haven't yet built our lookup of
            // groupings, so we can go ahead and do that too.
            Mutables mutables = _mutables;

            if (mutables == null)
            {
                mutables = _mutables = new Mutables();

                // Build the hash lookup and start enumerating the lookup at the beginning.
                mutables._hashLookup = BuildHashLookup();
                Debug.Assert(mutables._hashLookup != null);
                mutables._hashLookupIndex = -1;
            }

            // Now, with a hash lookup in hand, we just enumerate the keys. So long
            // as the key-value lookup has elements, we have elements.
            if (++mutables._hashLookupIndex < mutables._hashLookup.Count)
            {
                GroupKeyData value = mutables._hashLookup[mutables._hashLookupIndex].Value;
                currentElement = value._grouping;
                currentKey     = value._orderKey;
                return(true);
            }

            return(false);
        }
Exemple #2
0
        internal override bool MoveNext(ref Pair <TInputOutput, THashKey> currentElement, ref TOrderKey currentKey)
        {
            if (this.m_partitionCount == 1)
            {
                TInputOutput local = default(TInputOutput);
                if (this.m_source.MoveNext(ref local, ref currentKey))
                {
                    currentElement = new Pair <TInputOutput, THashKey>(local, (this.m_keySelector == null) ? default(THashKey) : this.m_keySelector(local));
                    return(true);
                }
                return(false);
            }
            Mutables <TInputOutput, THashKey, TOrderKey> mutables = this.m_mutables;

            if (mutables == null)
            {
                mutables = this.m_mutables = new Mutables <TInputOutput, THashKey, TOrderKey>();
            }
            if (mutables.m_currentBufferIndex == -1)
            {
                this.EnumerateAndRedistributeElements();
            }
            while (mutables.m_currentBufferIndex < this.m_partitionCount)
            {
                if (mutables.m_currentBuffer != null)
                {
                    if (++mutables.m_currentIndex < mutables.m_currentBuffer.Count)
                    {
                        currentElement = mutables.m_currentBuffer.m_chunk[mutables.m_currentIndex];
                        currentKey     = mutables.m_currentKeyBuffer.m_chunk[mutables.m_currentIndex];
                        return(true);
                    }
                    mutables.m_currentIndex     = -1;
                    mutables.m_currentBuffer    = mutables.m_currentBuffer.Next;
                    mutables.m_currentKeyBuffer = mutables.m_currentKeyBuffer.Next;
                }
                else
                {
                    if (mutables.m_currentBufferIndex == this.m_partitionIndex)
                    {
                        this.m_barrier.Wait(this.m_cancellationToken);
                        mutables.m_currentBufferIndex = -1;
                    }
                    mutables.m_currentBufferIndex++;
                    mutables.m_currentIndex = -1;
                    if (mutables.m_currentBufferIndex == this.m_partitionIndex)
                    {
                        mutables.m_currentBufferIndex++;
                    }
                    if (mutables.m_currentBufferIndex < this.m_partitionCount)
                    {
                        mutables.m_currentBuffer    = this.m_valueExchangeMatrix[mutables.m_currentBufferIndex, this.m_partitionIndex];
                        mutables.m_currentKeyBuffer = this.m_keyExchangeMatrix[mutables.m_currentBufferIndex, this.m_partitionIndex];
                    }
                }
            }
            return(false);
        }
Exemple #3
0
            internal override bool MoveNext(ref T currentElement, ref int currentKey)
            {
                Mutables <T> mutables = this.m_mutables;

                if (mutables == null)
                {
                    mutables = this.m_mutables = new Mutables <T>();
                }
                while (true)
                {
                    T[] chunkBuffer = mutables.m_chunkBuffer;
                    int index       = ++mutables.m_currentChunkIndex;
                    if (index < mutables.m_currentChunkSize)
                    {
                        currentElement = chunkBuffer[index];
                        currentKey     = mutables.m_chunkBaseIndex + index;
                        return(true);
                    }
                    lock (this.m_sourceSyncLock)
                    {
                        int num2 = 0;
                        if (this.m_exceptionTracker.Value)
                        {
                            return(false);
                        }
                        try
                        {
                            while ((num2 < mutables.m_nextChunkMaxSize) && this.m_source.MoveNext())
                            {
                                chunkBuffer[num2] = this.m_source.Current;
                                num2++;
                            }
                        }
                        catch
                        {
                            this.m_exceptionTracker.Value = true;
                            throw;
                        }
                        mutables.m_currentChunkSize = num2;
                        if (num2 == 0)
                        {
                            return(false);
                        }
                        mutables.m_chunkBaseIndex  = this.m_currentIndex.Value;
                        this.m_currentIndex.Value += num2;
                    }
                    if ((mutables.m_nextChunkMaxSize < chunkBuffer.Length) && ((mutables.m_chunkCounter++ & 7) == 7))
                    {
                        mutables.m_nextChunkMaxSize *= 2;
                        if (mutables.m_nextChunkMaxSize > chunkBuffer.Length)
                        {
                            mutables.m_nextChunkMaxSize = chunkBuffer.Length;
                        }
                    }
                    mutables.m_currentChunkIndex = -1;
                }
            }
Exemple #4
0
            private bool MoveNextSlowPath()
            {
                Mutables mutables = m_mutables;

                Contract.Assert(mutables != null);
                Contract.Assert(mutables.m_currentPositionInChunk >= mutables.m_currentChunkSize);

                // Move on to the next section.
                int currentSection    = ++mutables.m_currentSection;
                int sectionsRemaining = m_sectionCount - currentSection;

                // If empty, return right away.
                if (sectionsRemaining <= 0)
                {
                    return(false);
                }

                // Compute the offset of the current section from the beginning of the range
                int currentSectionOffset = currentSection * m_partitionCount * m_maxChunkSize;

                mutables.m_currentPositionInChunk = 0;

                // Now do something different based on how many chunks remain.
                if (sectionsRemaining > 1)
                {
                    // We are not on the last section. The size of this chunk is simply m_maxChunkSize.
                    mutables.m_currentChunkSize   = m_maxChunkSize;
                    mutables.m_currentChunkOffset = currentSectionOffset + m_partitionIndex * m_maxChunkSize;
                }
                else
                {
                    // We are on the last section. Compute the size of the chunk to ensure even distribution
                    // of elements.
                    int lastSectionElementCount = m_elementCount - currentSectionOffset;
                    int smallerChunkSize        = lastSectionElementCount / m_partitionCount;
                    int biggerChunkCount        = lastSectionElementCount % m_partitionCount;

                    mutables.m_currentChunkSize = smallerChunkSize;
                    if (m_partitionIndex < biggerChunkCount)
                    {
                        mutables.m_currentChunkSize++;
                    }
                    if (mutables.m_currentChunkSize == 0)
                    {
                        return(false);
                    }

                    mutables.m_currentChunkOffset =
                        currentSectionOffset                                                           // The beginning of this section
                        + m_partitionIndex * smallerChunkSize                                          // + the start of this chunk if all chunks were "smaller"
                        + (m_partitionIndex < biggerChunkCount ? m_partitionIndex : biggerChunkCount); // + the number of "bigger" chunks before this chunk
                }

                return(true);
            }
		public void RegisterMutableAction(Type type, IMutableElement mutableElement)
		{
			if (Mutables.ContainsKey(type))
			{
				Mutables[type] = mutableElement;
			}
			else
			{
				Mutables.Add(type,
					mutableElement);
			}
		}
            internal override bool MoveNext([MaybeNullWhen(false), AllowNull] ref T currentElement, ref int currentKey)
            {
                // Lazily allocate the mutable holder.
                Mutables mutables = _mutables ??= new Mutables();

                // If we are aren't within the chunk, we need to find another.
                if (++mutables._currentPositionInChunk < mutables._currentChunkSize || MoveNextSlowPath())
                {
                    currentKey     = mutables._currentChunkOffset + mutables._currentPositionInChunk;
                    currentElement = _data[currentKey];
                    return(true);
                }

                return(false);
            }
Exemple #7
0
        private void EnumerateAndRedistributeElements()
        {
            Mutables <TInputOutput, THashKey, TOrderKey> mutables = this.m_mutables;

            ListChunk <Pair <TInputOutput, THashKey> >[] chunkArray = new ListChunk <Pair <TInputOutput, THashKey> > [this.m_partitionCount];
            ListChunk <TOrderKey>[] chunkArray2    = new ListChunk <TOrderKey> [this.m_partitionCount];
            TInputOutput            currentElement = default(TInputOutput);
            TOrderKey currentKey = default(TOrderKey);
            int       num        = 0;

            while (this.m_source.MoveNext(ref currentElement, ref currentKey))
            {
                int num2;
                if ((num++ & 0x3f) == 0)
                {
                    CancellationState.ThrowIfCanceled(this.m_cancellationToken);
                }
                THashKey key = default(THashKey);
                if (this.m_keySelector != null)
                {
                    key  = this.m_keySelector(currentElement);
                    num2 = this.m_repartitionStream.GetHashCode(key) % this.m_partitionCount;
                }
                else
                {
                    num2 = this.m_repartitionStream.GetHashCode(currentElement) % this.m_partitionCount;
                }
                ListChunk <Pair <TInputOutput, THashKey> > chunk = chunkArray[num2];
                ListChunk <TOrderKey> chunk2 = chunkArray2[num2];
                if (chunk == null)
                {
                    chunkArray[num2]  = chunk = new ListChunk <Pair <TInputOutput, THashKey> >(0x80);
                    chunkArray2[num2] = chunk2 = new ListChunk <TOrderKey>(0x80);
                }
                chunk.Add(new Pair <TInputOutput, THashKey>(currentElement, key));
                chunk2.Add(currentKey);
            }
            for (int i = 0; i < this.m_partitionCount; i++)
            {
                this.m_valueExchangeMatrix[this.m_partitionIndex, i] = chunkArray[i];
                this.m_keyExchangeMatrix[this.m_partitionIndex, i]   = chunkArray2[i];
            }
            this.m_barrier.Signal();
            mutables.m_currentBufferIndex = this.m_partitionIndex;
            mutables.m_currentBuffer      = chunkArray[this.m_partitionIndex];
            mutables.m_currentKeyBuffer   = chunkArray2[this.m_partitionIndex];
            mutables.m_currentIndex       = -1;
        }
Exemple #8
0
            internal override bool MoveNext(ref T currentElement, ref int currentKey)
            {
                Mutables <T> mutables = this.m_mutables;

                if (mutables == null)
                {
                    mutables = this.m_mutables = new Mutables <T>();
                }
                if ((++mutables.m_currentPositionInChunk >= mutables.m_currentChunkSize) && !this.MoveNextSlowPath())
                {
                    return(false);
                }
                currentKey     = mutables.m_currentChunkOffset + mutables.m_currentPositionInChunk;
                currentElement = this.m_data[currentKey];
                return(true);
            }
        internal override bool MoveNext(ref IGrouping <TGroupKey, TElement> currentElement, ref TOrderKey currentKey)
        {
            Mutables <TSource, TGroupKey, TElement, TOrderKey> mutables = this.m_mutables;

            if (mutables == null)
            {
                mutables = this.m_mutables = new Mutables <TSource, TGroupKey, TElement, TOrderKey>();
                mutables.m_hashLookup      = this.BuildHashLookup();
                mutables.m_hashLookupIndex = -1;
            }
            if (++mutables.m_hashLookupIndex < mutables.m_hashLookup.Count)
            {
                currentElement = new GroupByGrouping <TGroupKey, TElement>(mutables.m_hashLookup[mutables.m_hashLookupIndex]);
                return(true);
            }
            return(false);
        }
Exemple #10
0
        internal override bool MoveNext(ref IGrouping <TGroupKey, TElement> currentElement, ref TOrderKey currentKey)
        {
            Mutables <TSource, TGroupKey, TElement, TOrderKey> mutables = this.m_mutables;

            if (mutables == null)
            {
                mutables = this.m_mutables = new Mutables <TSource, TGroupKey, TElement, TOrderKey>();
                mutables.m_hashLookup      = this.BuildHashLookup();
                mutables.m_hashLookupIndex = -1;
            }
            if (++mutables.m_hashLookupIndex < mutables.m_hashLookup.Count)
            {
                KeyValuePair <Wrapper <TGroupKey>, GroupKeyData <TSource, TGroupKey, TElement, TOrderKey> > pair = mutables.m_hashLookup[mutables.m_hashLookupIndex];
                GroupKeyData <TSource, TGroupKey, TElement, TOrderKey> data = pair.Value;
                currentElement = data.m_grouping;
                currentKey     = data.m_orderKey;
                return(true);
            }
            return(false);
        }
Exemple #11
0
            internal override bool MoveNext(ref T currentElement, ref int currentKey)
            {
                // Lazily allocate the mutable holder.
                Mutables mutables = m_mutables;

                if (mutables == null)
                {
                    mutables = m_mutables = new Mutables();
                }

                // If we are aren't within the chunk, we need to find another.
                if (++mutables.m_currentPositionInChunk < mutables.m_currentChunkSize || MoveNextSlowPath())
                {
                    currentKey     = mutables.m_currentChunkOffset + mutables.m_currentPositionInChunk;
                    currentElement = m_data[currentKey];
                    return(true);
                }

                return(false);
            }
Exemple #12
0
 internal override bool MoveNext(ref TOutput currentElement, ref Pair <TLeftKey, int> currentKey)
 {
     while (true)
     {
         if (this.m_currentRightSource == null)
         {
             this.m_mutables = new Mutables <TLeftInput, TRightInput, TOutput, TLeftKey>();
             if ((this.m_mutables.m_lhsCount++ & 0x3f) == 0)
             {
                 CancellationState.ThrowIfCanceled(this.m_cancellationToken);
             }
             if (!this.m_leftSource.MoveNext(ref this.m_mutables.m_currentLeftElement, ref this.m_mutables.m_currentLeftKey))
             {
                 return(false);
             }
             this.m_currentRightSource = this.m_selectManyOperator.m_rightChildSelector(this.m_mutables.m_currentLeftElement).GetEnumerator();
             if (this.m_selectManyOperator.m_resultSelector == null)
             {
                 this.m_currentRightSourceAsOutput = (IEnumerator <TOutput>) this.m_currentRightSource;
             }
         }
         if (this.m_currentRightSource.MoveNext())
         {
             this.m_mutables.m_currentRightSourceIndex++;
             if (this.m_selectManyOperator.m_resultSelector != null)
             {
                 currentElement = this.m_selectManyOperator.m_resultSelector(this.m_mutables.m_currentLeftElement, this.m_currentRightSource.Current);
             }
             else
             {
                 currentElement = this.m_currentRightSourceAsOutput.Current;
             }
             currentKey = new Pair <TLeftKey, int>(this.m_mutables.m_currentLeftKey, this.m_mutables.m_currentRightSourceIndex);
             return(true);
         }
         this.m_currentRightSource.Dispose();
         this.m_currentRightSource         = null;
         this.m_currentRightSourceAsOutput = null;
     }
 }
        protected T CreateNewInstance(IMap <string, INode> childNodes, IStateTreeNode meta)
        {
            var observables = Mutables.Select(mutable => new ObservableProperty {
                Type = mutable.Kind, Name = mutable.Name, Default = mutable.Default
            }).ToList();

            var volatiles = Volatiles.Select(xvolatile => new Observable.VolatileProperty {
                Type = xvolatile.Kind, Name = xvolatile.Name, Default = xvolatile.Default
            }).ToList();

            var computeds = Views.Select(view => new ComputedProperty {
                Type = view.Kind, Name = view.Name, Compute = view.View
            }).ToList();

            // var actions = Actions.Select(action => new ActionMethod { Name = action.Name, Action = action.Action });

            ObservableTypeDef typeDef = new ObservableTypeDef(observables, volatiles, computeds);

            var instance = ObservableObject <T, INode> .FromAs(typeDef, Proxify, Name, this, meta);

            return(instance);
        }
Exemple #14
0
            private bool MoveNextSlowPath()
            {
                Mutables <T> mutables = this.m_mutables;
                int          num      = ++mutables.m_currentSection;
                int          num2     = this.m_sectionCount - num;

                if (num2 <= 0)
                {
                    return(false);
                }
                int num3 = (num * this.m_partitionCount) * this.m_maxChunkSize;

                mutables.m_currentPositionInChunk = 0;
                if (num2 > 1)
                {
                    mutables.m_currentChunkSize   = this.m_maxChunkSize;
                    mutables.m_currentChunkOffset = num3 + (this.m_partitionIndex * this.m_maxChunkSize);
                }
                else
                {
                    int num4 = this.m_elementCount - num3;
                    int num5 = num4 / this.m_partitionCount;
                    int num6 = num4 % this.m_partitionCount;
                    mutables.m_currentChunkSize = num5;
                    if (this.m_partitionIndex < num6)
                    {
                        mutables.m_currentChunkSize++;
                    }
                    if (mutables.m_currentChunkSize == 0)
                    {
                        return(false);
                    }
                    mutables.m_currentChunkOffset = (num3 + (this.m_partitionIndex * num5)) + ((this.m_partitionIndex < num6) ? this.m_partitionIndex : num6);
                }
                return(true);
            }
Exemple #15
0
            //---------------------------------------------------------------------------------------
            // Just retrieves the current element from our current chunk.
            //

            internal override bool MoveNext(ref T currentElement, ref int currentKey)
            {
                Mutables mutables = m_mutables;

                if (mutables == null)
                {
                    mutables = m_mutables = new Mutables();
                }

                Contract.Assert(mutables.m_chunkBuffer != null);

                // Loop until we've exhausted our data source.
                while (true)
                {
                    // If we have elements remaining in the current chunk, return right away.
                    T[] chunkBuffer       = mutables.m_chunkBuffer;
                    int currentChunkIndex = ++mutables.m_currentChunkIndex;
                    if (currentChunkIndex < mutables.m_currentChunkSize)
                    {
                        Contract.Assert(m_source != null);
                        Contract.Assert(chunkBuffer != null);
                        Contract.Assert(mutables.m_currentChunkSize > 0);
                        Contract.Assert(0 <= currentChunkIndex && currentChunkIndex < chunkBuffer.Length);
                        currentElement = chunkBuffer[currentChunkIndex];
                        currentKey     = mutables.m_chunkBaseIndex + currentChunkIndex;

                        return(true);
                    }

                    // Else, it could be the first time enumerating this object, or we may have
                    // just reached the end of the current chunk and need to grab another one? In either
                    // case, we will look for more data from the underlying enumerator.  Because we
                    // share the same enumerator object, we have to do this under a lock.

                    lock (m_sourceSyncLock)
                    {
                        Contract.Assert(0 <= mutables.m_nextChunkMaxSize && mutables.m_nextChunkMaxSize <= chunkBuffer.Length);

                        // Accumulate a chunk of elements from the input.
                        int i = 0;

                        if (m_exceptionTracker.Value)
                        {
                            return(false);
                        }

                        try
                        {
                            for (; i < mutables.m_nextChunkMaxSize && m_source.MoveNext(); i++)
                            {
                                // Read the current entry into our buffer.
                                chunkBuffer[i] = m_source.Current;
                            }
                        }
                        catch
                        {
                            m_exceptionTracker.Value = true;
                            throw;
                        }

                        // Store the number of elements we fetched from the data source.
                        mutables.m_currentChunkSize = i;

                        // If we've emptied the enumerator, return immediately.
                        if (i == 0)
                        {
                            return(false);
                        }

                        // Increment the shared index for all to see. Throw an exception on overflow.
                        mutables.m_chunkBaseIndex = m_currentIndex.Value;
                        checked
                        {
                            m_currentIndex.Value += i;
                        }
                    }

                    // Each time we access the data source, we grow the chunk size for the next go-round.
                    // We grow the chunksize once per 'chunksPerChunkSize'.
                    if (mutables.m_nextChunkMaxSize < chunkBuffer.Length)
                    {
                        if ((mutables.m_chunkCounter++ & chunksPerChunkSize) == chunksPerChunkSize)
                        {
                            mutables.m_nextChunkMaxSize = mutables.m_nextChunkMaxSize * 2;
                            if (mutables.m_nextChunkMaxSize > chunkBuffer.Length)
                            {
                                mutables.m_nextChunkMaxSize = chunkBuffer.Length;
                            }
                        }
                    }

                    // Finally, reset our index to the beginning; loop around and we'll return the right values.
                    mutables.m_currentChunkIndex = -1;
                }
            }
 private IReadOnlyDictionary <string, IType> ToProperties()
 {
     return(Mutables.ToDictionary(x => x.Name, y => y.Type));
 }
 private object GetMutableDefault(string property)
 {
     return(Mutables.Where(mutable => mutable.Name == property).FirstOrDefault()?.Default);
 }
        //---------------------------------------------------------------------------------------
        // Called when this enumerator is first enumerated; it must walk through the source
        // and redistribute elements to their slot in the exchange matrix.
        //

        private void EnumerateAndRedistributeElements()
        {
            Mutables mutables = m_mutables;

            Contract.Assert(mutables != null);

            ListChunk <Pair <TInputOutput, THashKey> >[] privateBuffers = new ListChunk <Pair <TInputOutput, THashKey> > [m_partitionCount];
            ListChunk <TOrderKey>[] privateKeyBuffers = new ListChunk <TOrderKey> [m_partitionCount];

            TInputOutput element   = default(TInputOutput);
            TOrderKey    key       = default(TOrderKey);
            int          loopCount = 0;

            while (m_source.MoveNext(ref element, ref key))
            {
                if ((loopCount++ & CancellationState.POLL_INTERVAL) == 0)
                {
                    CancellationState.ThrowIfCanceled(m_cancellationToken);
                }

                // Calculate the element's destination partition index, placing it into the
                // appropriate buffer from which partitions will later enumerate.
                int      destinationIndex;
                THashKey elementHashKey = default(THashKey);
                if (m_keySelector != null)
                {
                    elementHashKey   = m_keySelector(element);
                    destinationIndex = m_repartitionStream.GetHashCode(elementHashKey) % m_partitionCount;
                }
                else
                {
                    Contract.Assert(typeof(THashKey) == typeof(NoKeyMemoizationRequired));
                    destinationIndex = m_repartitionStream.GetHashCode(element) % m_partitionCount;
                }

                Contract.Assert(0 <= destinationIndex && destinationIndex < m_partitionCount,
                                "destination partition outside of the legal range of partitions");

                // Get the buffer for the destnation partition, lazily allocating if needed.  We maintain
                // this list in our own private cache so that we avoid accessing shared memory locations
                // too much.  In the original implementation, we'd access the buffer in the matrix ([N,M],
                // where N is the current partition and M is the destination), but some rudimentary
                // performance profiling indicates copying at the end performs better.
                ListChunk <Pair <TInputOutput, THashKey> > buffer = privateBuffers[destinationIndex];
                ListChunk <TOrderKey> keyBuffer = privateKeyBuffers[destinationIndex];
                if (buffer == null)
                {
                    const int INITIAL_PRIVATE_BUFFER_SIZE = 128;
                    Contract.Assert(keyBuffer == null);
                    privateBuffers[destinationIndex]    = buffer = new ListChunk <Pair <TInputOutput, THashKey> >(INITIAL_PRIVATE_BUFFER_SIZE);
                    privateKeyBuffers[destinationIndex] = keyBuffer = new ListChunk <TOrderKey>(INITIAL_PRIVATE_BUFFER_SIZE);
                }

                buffer.Add(new Pair <TInputOutput, THashKey>(element, elementHashKey));
                keyBuffer.Add(key);
            }

            // Copy the local buffers to the shared space and then signal to other threads that
            // we are done.  We can then immediately move on to enumerating the elements we found
            // for the current partition before waiting at the barrier.  If we found a lot, we will
            // hopefully never have to physically wait.
            for (int i = 0; i < m_partitionCount; i++)
            {
                m_valueExchangeMatrix[m_partitionIndex, i] = privateBuffers[i];
                m_keyExchangeMatrix[m_partitionIndex, i]   = privateKeyBuffers[i];
            }

            m_barrier.Signal();

            // Begin at our own buffer.
            mutables.m_currentBufferIndex = m_partitionIndex;
            mutables.m_currentBuffer      = privateBuffers[m_partitionIndex];
            mutables.m_currentKeyBuffer   = privateKeyBuffers[m_partitionIndex];
            mutables.m_currentIndex       = ENUMERATION_NOT_STARTED;
        }
            //---------------------------------------------------------------------------------------
            // Straightforward IEnumerator<T> methods.
            //

            internal override bool MoveNext(ref TOutput currentElement, ref Pair <TLeftKey, int> currentKey)
            {
                while (true)
                {
                    if (_currentRightSource == null)
                    {
                        _mutables = new Mutables();

                        // Check cancellation every few lhs-enumerations in case none of them are producing
                        // any outputs.  Otherwise, we rely on the consumer of this operator to be performing the checks.
                        if ((_mutables._lhsCount++ & CancellationState.POLL_INTERVAL) == 0)
                        {
                            CancellationState.ThrowIfCanceled(_cancellationToken);
                        }

                        // We don't have a "current" right enumerator to use. We have to fetch the next
                        // one. If the left has run out of elements, however, we're done and just return
                        // false right away.

                        if (!_leftSource.MoveNext(ref _mutables._currentLeftElement, ref _mutables._currentLeftKey))
                        {
                            return(false);
                        }

                        // Use the source selection routine to create a right child.
                        IEnumerable <TRightInput> rightChild = _selectManyOperator._rightChildSelector(_mutables._currentLeftElement);

                        Debug.Assert(rightChild != null);
                        _currentRightSource = rightChild.GetEnumerator();

                        Debug.Assert(_currentRightSource != null);

                        // If we have no result selector, we will need to access the Current element of the right
                        // data source as though it is a TOutput. Unfortunately, we know that TRightInput must
                        // equal TOutput (we check it during operator construction), but the type system doesn't.
                        // Thus we would have to cast the result of invoking Current from type TRightInput to
                        // TOutput. This is no good, since the results could be value types. Instead, we save the
                        // enumerator object as an IEnumerator<TOutput> and access that later on.
                        if (_selectManyOperator._resultSelector == null)
                        {
                            _currentRightSourceAsOutput = (IEnumerator <TOutput>)_currentRightSource;
                            Debug.Assert(_currentRightSourceAsOutput == _currentRightSource,
                                         "these must be equal, otherwise the surrounding logic will be broken");
                        }
                    }

                    if (_currentRightSource.MoveNext())
                    {
                        _mutables._currentRightSourceIndex++;

                        // If the inner data source has an element, we can yield it.
                        if (_selectManyOperator._resultSelector != null)
                        {
                            // In the case of a selection function, use that to yield the next element.
                            currentElement = _selectManyOperator._resultSelector(_mutables._currentLeftElement, _currentRightSource.Current);
                        }
                        else
                        {
                            // Otherwise, the right input and output types must be the same. We use the
                            // casted copy of the current right source and just return its current element.
                            Debug.Assert(_currentRightSourceAsOutput != null);
                            currentElement = _currentRightSourceAsOutput.Current;
                        }
                        currentKey = new Pair <TLeftKey, int>(_mutables._currentLeftKey, _mutables._currentRightSourceIndex);

                        return(true);
                    }
                    else
                    {
                        // Otherwise, we have exhausted the right data source. Loop back around and try
                        // to get the next left element, then its right, and so on.
                        _currentRightSource.Dispose();
                        _currentRightSource         = null;
                        _currentRightSourceAsOutput = null;
                    }
                }
            }
        //---------------------------------------------------------------------------------------
        // Retrieves the next element from this partition.  All repartitioning operators across
        // all partitions cooperate in a barrier-style algorithm.  The first time an element is
        // requested, the repartitioning operator will enter the 1st phase: during this phase, it
        // scans its entire input and compute the destination partition for each element.  During
        // the 2nd phase, each partition scans the elements found by all other partitions for
        // it, and yield this to callers.  The only synchronization required is the barrier itself
        // -- all other parts of this algorithm are synchronization-free.
        //
        // Notes: One rather large penalty that this algorithm incurs is higher memory usage and a
        // larger time-to-first-element latency, at least compared with our old implementation; this
        // happens because all input elements must be fetched before we can produce a single output
        // element.  In many cases this isn't too terrible: e.g. a GroupBy requires this to occur
        // anyway, so having the repartitioning operator do so isn't complicating matters much at all.
        //

        internal override bool MoveNext(ref Pair <TInputOutput, THashKey> currentElement, ref TOrderKey currentKey)
        {
            if (m_partitionCount == 1)
            {
                TInputOutput current = default(TInputOutput);

                // If there's only one partition, no need to do any sort of exchanges.
                if (m_source.MoveNext(ref current, ref currentKey))
                {
                    currentElement = new Pair <TInputOutput, THashKey>(
                        current, m_keySelector == null ? default(THashKey) : m_keySelector(current));
                    return(true);
                }

                return(false);
            }

            Mutables mutables = m_mutables;

            if (mutables == null)
            {
                mutables = m_mutables = new Mutables();
            }

            // If we haven't enumerated the source yet, do that now.  This is the first phase
            // of a two-phase barrier style operation.
            if (mutables.m_currentBufferIndex == ENUMERATION_NOT_STARTED)
            {
                EnumerateAndRedistributeElements();
                Contract.Assert(mutables.m_currentBufferIndex != ENUMERATION_NOT_STARTED);
            }

            // Once we've enumerated our contents, we can then go back and walk the buffers that belong
            // to the current partition.  This is phase two.  Note that we slyly move on to the first step
            // of phase two before actually waiting for other partitions.  That's because we can enumerate
            // the buffer we wrote to above, as already noted.
            while (mutables.m_currentBufferIndex < m_partitionCount)
            {
                // If the queue is non-null and still has elements, yield them.
                if (mutables.m_currentBuffer != null)
                {
                    Contract.Assert(mutables.m_currentKeyBuffer != null);

                    if (++mutables.m_currentIndex < mutables.m_currentBuffer.Count)
                    {
                        // Return the current element.
                        currentElement = mutables.m_currentBuffer.m_chunk[mutables.m_currentIndex];
                        Contract.Assert(mutables.m_currentKeyBuffer != null, "expected same # of buffers/key-buffers");
                        currentKey = mutables.m_currentKeyBuffer.m_chunk[mutables.m_currentIndex];
                        return(true);
                    }
                    else
                    {
                        // If the chunk is empty, advance to the next one (if any).
                        mutables.m_currentIndex     = ENUMERATION_NOT_STARTED;
                        mutables.m_currentBuffer    = mutables.m_currentBuffer.Next;
                        mutables.m_currentKeyBuffer = mutables.m_currentKeyBuffer.Next;
                        Contract.Assert(mutables.m_currentBuffer == null || mutables.m_currentBuffer.Count > 0);
                        Contract.Assert((mutables.m_currentBuffer == null) == (mutables.m_currentKeyBuffer == null));
                        Contract.Assert(mutables.m_currentBuffer == null || mutables.m_currentBuffer.Count == mutables.m_currentKeyBuffer.Count);
                        continue; // Go back around and invoke this same logic.
                    }
                }

                // We're done with the current partition.  Slightly different logic depending on whether
                // we're on our own buffer or one that somebody else found for us.
                if (mutables.m_currentBufferIndex == m_partitionIndex)
                {
                    // We now need to wait at the barrier, in case some other threads aren't done.
                    // Once we wake up, we reset our index and will increment it immediately after.
                    m_barrier.Wait(m_cancellationToken);
                    mutables.m_currentBufferIndex = ENUMERATION_NOT_STARTED;
                }

                // Advance to the next buffer.
                mutables.m_currentBufferIndex++;
                mutables.m_currentIndex = ENUMERATION_NOT_STARTED;

                if (mutables.m_currentBufferIndex == m_partitionIndex)
                {
                    // Skip our current buffer (since we already enumerated it).
                    mutables.m_currentBufferIndex++;
                }

                // Assuming we're within bounds, retrieve the next buffer object.
                if (mutables.m_currentBufferIndex < m_partitionCount)
                {
                    mutables.m_currentBuffer    = m_valueExchangeMatrix[mutables.m_currentBufferIndex, m_partitionIndex];
                    mutables.m_currentKeyBuffer = m_keyExchangeMatrix[mutables.m_currentBufferIndex, m_partitionIndex];
                }
            }

            // We're done. No more buffers to enumerate.
            return(false);
        }
Exemple #21
0
        internal override bool MoveNext(ref TOutput currentElement, ref TLeftKey currentKey)
        {
            Mutables <TLeftInput, TLeftKey, TRightInput, THashKey, TOutput> mutables = this.m_mutables;

            if (mutables == null)
            {
                mutables = this.m_mutables = new Mutables <TLeftInput, TLeftKey, TRightInput, THashKey, TOutput>();
                mutables.m_rightHashLookup = new HashLookup <THashKey, Pair <TRightInput, ListChunk <TRightInput> > >(this.m_keyComparer);
                Pair <TRightInput, THashKey> pair = new Pair <TRightInput, THashKey>();
                int num  = 0;
                int num2 = 0;
                while (this.m_rightSource.MoveNext(ref pair, ref num))
                {
                    if ((num2++ & 0x3f) == 0)
                    {
                        CancellationState.ThrowIfCanceled(this.m_cancellationToken);
                    }
                    TRightInput first  = pair.First;
                    THashKey    second = pair.Second;
                    if (second != null)
                    {
                        Pair <TRightInput, ListChunk <TRightInput> > pair2 = new Pair <TRightInput, ListChunk <TRightInput> >();
                        if (!mutables.m_rightHashLookup.TryGetValue(second, ref pair2))
                        {
                            pair2 = new Pair <TRightInput, ListChunk <TRightInput> >(first, null);
                            if (this.m_groupResultSelector != null)
                            {
                                pair2.Second = new ListChunk <TRightInput>(2);
                                pair2.Second.Add(first);
                            }
                            mutables.m_rightHashLookup.Add(second, pair2);
                        }
                        else
                        {
                            if (pair2.Second == null)
                            {
                                pair2.Second = new ListChunk <TRightInput>(2);
                                mutables.m_rightHashLookup[second] = pair2;
                            }
                            pair2.Second.Add(first);
                        }
                    }
                }
            }
            ListChunk <TRightInput> currentRightMatches = mutables.m_currentRightMatches;

            if ((currentRightMatches != null) && (mutables.m_currentRightMatchesIndex == currentRightMatches.Count))
            {
                currentRightMatches = mutables.m_currentRightMatches = currentRightMatches.Next;
                mutables.m_currentRightMatchesIndex = 0;
            }
            if (mutables.m_currentRightMatches == null)
            {
                Pair <TLeftInput, THashKey> pair3 = new Pair <TLeftInput, THashKey>();
                TLeftKey local3 = default(TLeftKey);
                while (this.m_leftSource.MoveNext(ref pair3, ref local3))
                {
                    if ((mutables.m_outputLoopCount++ & 0x3f) == 0)
                    {
                        CancellationState.ThrowIfCanceled(this.m_cancellationToken);
                    }
                    Pair <TRightInput, ListChunk <TRightInput> > pair4 = new Pair <TRightInput, ListChunk <TRightInput> >();
                    TLeftInput local4 = pair3.First;
                    THashKey   key    = pair3.Second;
                    if (((key != null) && mutables.m_rightHashLookup.TryGetValue(key, ref pair4)) && (this.m_singleResultSelector != null))
                    {
                        mutables.m_currentRightMatches      = pair4.Second;
                        mutables.m_currentRightMatchesIndex = 0;
                        currentElement = this.m_singleResultSelector(local4, pair4.First);
                        currentKey     = local3;
                        if (pair4.Second != null)
                        {
                            mutables.m_currentLeft    = local4;
                            mutables.m_currentLeftKey = local3;
                        }
                        return(true);
                    }
                    if (this.m_groupResultSelector != null)
                    {
                        IEnumerable <TRightInput> enumerable = pair4.Second;
                        if (enumerable == null)
                        {
                            enumerable = (IEnumerable <TRightInput>)ParallelEnumerable.Empty <TRightInput>();
                        }
                        currentElement = this.m_groupResultSelector(local4, enumerable);
                        currentKey     = local3;
                        return(true);
                    }
                }
                return(false);
            }
            currentElement = this.m_singleResultSelector(mutables.m_currentLeft, mutables.m_currentRightMatches.m_chunk[mutables.m_currentRightMatchesIndex]);
            currentKey     = mutables.m_currentLeftKey;
            mutables.m_currentRightMatchesIndex++;
            return(true);
        }
		public IMutableElement GetMutableAction(Type type)
		{
			return Mutables.ContainsKey(type)
				? Mutables[type]
				: null;
		}
Exemple #23
0
        //---------------------------------------------------------------------------------------
        // MoveNext implements all the hash-join logic noted earlier. When it is called first, it
        // will execute the entire inner query tree, and build a hash-table lookup. This is the
        // Building phase. Then for the first call and all subsequent calls to MoveNext, we will
        // incrementally perform the Probing phase. We'll keep getting elements from the outer
        // data source, looking into the hash-table we built, and enumerating the full results.
        //
        // This routine supports both inner and outer (group) joins. An outer join will yield a
        // (possibly empty) list of matching elements from the inner instead of one-at-a-time,
        // as we do for inner joins.
        //

        internal override bool MoveNext(ref TOutput currentElement, ref TLeftKey currentKey)
        {
            Contract.Assert(_singleResultSelector != null || _groupResultSelector != null, "expected a compiled result selector");
            Contract.Assert(_leftSource != null);
            Contract.Assert(_rightSource != null);

            // BUILD phase: If we haven't built the hash-table yet, create that first.
            Mutables mutables = _mutables;

            if (mutables == null)
            {
                mutables = _mutables = new Mutables();
#if DEBUG
                int hashLookupCount   = 0;
                int hashKeyCollisions = 0;
#endif
                mutables._rightHashLookup = new HashLookup <THashKey, Pair>(_keyComparer);

                Pair rightPair      = new Pair(default(TRightInput), default(THashKey));
                int  rightKeyUnused = default(int);
                int  i = 0;
                while (_rightSource.MoveNext(ref rightPair, ref rightKeyUnused))
                {
                    if ((i++ & CancellationState.POLL_INTERVAL) == 0)
                    {
                        CancellationState.ThrowIfCanceled(_cancellationToken);
                    }

                    TRightInput rightElement = (TRightInput)rightPair.First;
                    THashKey    rightHashKey = (THashKey)rightPair.Second;

                    // We ignore null keys.
                    if (rightHashKey != null)
                    {
#if DEBUG
                        hashLookupCount++;
#endif

                        // See if we've already stored an element under the current key. If not, we
                        // lazily allocate a pair to hold the elements mapping to the same key.
                        const int INITIAL_CHUNK_SIZE = 2;
                        Pair      currentValue       = new Pair(default(TRightInput), default(ListChunk <TRightInput>));
                        if (!mutables._rightHashLookup.TryGetValue(rightHashKey, ref currentValue))
                        {
                            currentValue = new Pair(rightElement, null);

                            if (_groupResultSelector != null)
                            {
                                // For group joins, we also add the element to the list. This makes
                                // it easier later to yield the list as-is.
                                currentValue.Second = new ListChunk <TRightInput>(INITIAL_CHUNK_SIZE);
                                ((ListChunk <TRightInput>)currentValue.Second).Add((TRightInput)rightElement);
                            }

                            mutables._rightHashLookup.Add(rightHashKey, currentValue);
                        }
                        else
                        {
                            if (currentValue.Second == null)
                            {
                                // Lazily allocate a list to hold all but the 1st value. We need to
                                // re-store this element because the pair is a value type.
                                currentValue.Second = new ListChunk <TRightInput>(INITIAL_CHUNK_SIZE);
                                mutables._rightHashLookup[rightHashKey] = currentValue;
                            }

                            ((ListChunk <TRightInput>)currentValue.Second).Add((TRightInput)rightElement);
#if DEBUG
                            hashKeyCollisions++;
#endif
                        }
                    }
                }

#if DEBUG
                TraceHelpers.TraceInfo("ParallelJoinQueryOperator::MoveNext - built hash table [count = {0}, collisions = {1}]",
                                       hashLookupCount, hashKeyCollisions);
#endif
            }

            // PROBE phase: So long as the source has a next element, return the match.
            ListChunk <TRightInput> currentRightChunk = mutables._currentRightMatches;
            if (currentRightChunk != null && mutables._currentRightMatchesIndex == currentRightChunk.Count)
            {
                currentRightChunk = mutables._currentRightMatches = currentRightChunk.Next;
                mutables._currentRightMatchesIndex = 0;
            }

            if (mutables._currentRightMatches == null)
            {
                // We have to look up the next list of matches in the hash-table.
                Pair     leftPair = new Pair(default(TLeftInput), default(THashKey));
                TLeftKey leftKey  = default(TLeftKey);
                while (_leftSource.MoveNext(ref leftPair, ref leftKey))
                {
                    if ((mutables._outputLoopCount++ & CancellationState.POLL_INTERVAL) == 0)
                    {
                        CancellationState.ThrowIfCanceled(_cancellationToken);
                    }

                    // Find the match in the hash table.
                    Pair       matchValue  = new Pair(default(TRightInput), default(ListChunk <TRightInput>));
                    TLeftInput leftElement = (TLeftInput)leftPair.First;
                    THashKey   leftHashKey = (THashKey)leftPair.Second;

                    // Ignore null keys.
                    if (leftHashKey != null)
                    {
                        if (mutables._rightHashLookup.TryGetValue(leftHashKey, ref matchValue))
                        {
                            // We found a new match. For inner joins, we remember the list in case
                            // there are multiple value under this same key -- the next iteration will pick
                            // them up. For outer joins, we will use the list momentarily.
                            if (_singleResultSelector != null)
                            {
                                mutables._currentRightMatches = (ListChunk <TRightInput>)matchValue.Second;
                                Contract.Assert(mutables._currentRightMatches == null || mutables._currentRightMatches.Count > 0,
                                                "we were expecting that the list would be either null or empty");
                                mutables._currentRightMatchesIndex = 0;

                                // Yield the value.
                                currentElement = _singleResultSelector(leftElement, (TRightInput)matchValue.First);
                                currentKey     = leftKey;

                                // If there is a list of matches, remember the left values for next time.
                                if (matchValue.Second != null)
                                {
                                    mutables._currentLeft    = leftElement;
                                    mutables._currentLeftKey = leftKey;
                                }

                                return(true);
                            }
                        }
                    }

                    // For outer joins, we always yield a result.
                    if (_groupResultSelector != null)
                    {
                        // Grab the matches, or create an empty list if there are none.
                        IEnumerable <TRightInput> matches = (ListChunk <TRightInput>)matchValue.Second;
                        if (matches == null)
                        {
                            matches = ParallelEnumerable.Empty <TRightInput>();
                        }

                        // Generate the current value.
                        currentElement = _groupResultSelector(leftElement, matches);
                        currentKey     = leftKey;
                        return(true);
                    }
                }

                // If we've reached the end of the data source, we're done.
                return(false);
            }

            // Produce the next element and increment our index within the matches.
            Contract.Assert(_singleResultSelector != null);
            Contract.Assert(mutables._currentRightMatches != null);
            Contract.Assert(0 <= mutables._currentRightMatchesIndex && mutables._currentRightMatchesIndex < mutables._currentRightMatches.Count);

            currentElement = _singleResultSelector(
                mutables._currentLeft, mutables._currentRightMatches._chunk[mutables._currentRightMatchesIndex]);
            currentKey = mutables._currentLeftKey;

            mutables._currentRightMatchesIndex++;

            return(true);
        }
Exemple #24
0
        //---------------------------------------------------------------------------------------
        // MoveNext implements all the hash-join logic noted earlier. When it is called first, it
        // will execute the entire inner query tree, and build a hash-table lookup. This is the
        // Building phase. Then for the first call and all subsequent calls to MoveNext, we will
        // incrementally perform the Probing phase. We'll keep getting elements from the outer
        // data source, looking into the hash-table we built, and enumerating the full results.
        //
        // This routine supports both inner and outer (group) joins. An outer join will yield a
        // (possibly empty) list of matching elements from the inner instead of one-at-a-time,
        // as we do for inner joins.
        //

        internal override bool MoveNext(ref TOutput currentElement, ref TOutputKey currentKey)
        {
            Debug.Assert(_resultSelector != null, "expected a compiled result selector");
            Debug.Assert(_leftSource != null);
            Debug.Assert(_rightLookupBuilder != null);

            // BUILD phase: If we haven't built the hash-table yet, create that first.
            Mutables mutables = _mutables;

            if (mutables == null)
            {
                mutables = _mutables = new Mutables();
                mutables._rightHashLookup = _rightLookupBuilder.BuildHashLookup(_cancellationToken);
            }

            // PROBE phase: So long as the source has a next element, return the match.
            ListChunk <Pair <TRightInput, TRightKey> > currentRightChunk = mutables._currentRightMatches;

            if (currentRightChunk != null && mutables._currentRightMatchesIndex == currentRightChunk.Count)
            {
                mutables._currentRightMatches      = currentRightChunk.Next;
                mutables._currentRightMatchesIndex = 0;
            }

            if (mutables._currentRightMatches == null)
            {
                // We have to look up the next list of matches in the hash-table.
                Pair <TLeftInput, THashKey> leftPair = default(Pair <TLeftInput, THashKey>);
                TLeftKey leftKey = default(TLeftKey);
                while (_leftSource.MoveNext(ref leftPair, ref leftKey))
                {
                    if ((mutables._outputLoopCount++ & CancellationState.POLL_INTERVAL) == 0)
                    {
                        CancellationState.ThrowIfCanceled(_cancellationToken);
                    }

                    // Find the match in the hash table.
                    HashLookupValueList <TRightInput, TRightKey> matchValue = default(HashLookupValueList <TRightInput, TRightKey>);
                    TLeftInput leftElement = leftPair.First;
                    THashKey   leftHashKey = leftPair.Second;

                    // Ignore null keys.
                    if (leftHashKey != null)
                    {
                        if (mutables._rightHashLookup.TryGetValue(leftHashKey, ref matchValue))
                        {
                            // We found a new match. We remember the list in case there are multiple
                            // values under this same key -- the next iteration will pick them up.
                            mutables._currentRightMatches = matchValue.Tail;
                            Debug.Assert(mutables._currentRightMatches == null || mutables._currentRightMatches.Count > 0,
                                         "we were expecting that the list would be either null or empty");
                            mutables._currentRightMatchesIndex = 0;

                            // Yield the value.
                            currentElement = _resultSelector(leftElement, matchValue.Head.First);
                            currentKey     = _outputKeyBuilder.Combine(leftKey, matchValue.Head.Second);

                            // If there is a list of matches, remember the left values for next time.
                            if (matchValue.Tail != null)
                            {
                                mutables._currentLeft    = leftElement;
                                mutables._currentLeftKey = leftKey;
                            }

                            return(true);
                        }
                    }
                }

                // If we've reached the end of the data source, we're done.
                return(false);
            }

            // Produce the next element.
            Debug.Assert(mutables._currentRightMatches != null);
            Debug.Assert(0 <= mutables._currentRightMatchesIndex && mutables._currentRightMatchesIndex < mutables._currentRightMatches.Count);

            Pair <TRightInput, TRightKey> rightMatch = mutables._currentRightMatches._chunk[mutables._currentRightMatchesIndex];

            currentElement = _resultSelector(mutables._currentLeft, rightMatch.First);
            currentKey     = _outputKeyBuilder.Combine(mutables._currentLeftKey, rightMatch.Second);

            mutables._currentRightMatchesIndex++;

            return(true);
        }