Пример #1
0
        private MultidimensionalPointResult <TPoint> TryGetOrAddVectorInternal(TDimensionValue[] coordinates, int currentDim, bool createIfNotExists)
        {
            TDimensionValue subElementKey = coordinates[currentDim];

            // Try and get the referenced element:
            object subElement;
            bool   subElementExists = this.elements.TryGetValue(subElementKey, out subElement);

            // If the referenced element exists, we can simply proceed:
            if (subElementExists)
            {
                if (this.isLastDimensionLevel)
                {
                    var result = new MultidimensionalPointResult <TPoint>(MultidimensionalPointResultCodes.Success_ExistingPointRetrieved, (TPoint)subElement);
                    return(result);
                }
                else
                {
                    MultidimensionalCubeDimension <TDimensionValue, TPoint> subDim = (MultidimensionalCubeDimension <TDimensionValue, TPoint>)subElement;
                    MultidimensionalPointResult <TPoint> result = subDim.TryGetOrAddVectorInternal(coordinates, currentDim + 1, createIfNotExists);
                    return(result);
                }
            }
            else
            {
                // so - subElement does NOT exist:
                // If we are not to create new elements, we are done:
                if (false == createIfNotExists)
                {
                    var result = new MultidimensionalPointResult <TPoint>(MultidimensionalPointResultCodes.Failure_PointDoesNotExistCreationNotRequested, currentDim);
                    return(result);
                }
                else
                {
                    MultidimensionalPointResult <TPoint> result = this.isLastDimensionLevel
                                                        ? this.TryAddPoint(coordinates, currentDim)
                                                        : this.TryAddSubvector(coordinates, currentDim);
                    return(result);
                }
            }
        }
        private MultidimensionalPointResult <TPoint> TryAddSubvector(TDimensionValue[] coordinates, int currentDim)
        {
            // Note the comment near the top if TryAddPoint(..) about the applied minimal locking strategy.

            // Check if we reached the dimensions count limit. If we did, we give up. Otherwise we start tracking whether we need to undo the increment later:
            if (!this.TryIncSubdimensionsCount())
            {
                return(new MultidimensionalPointResult <TPoint>(MultidimensionalPointResultCodes.Failure_SubdimensionsCountLimitReached, currentDim));
            }

            bool mustRestoreSubdimensionsCount = true;

            try
            {
                TDimensionValue subElementKey = coordinates[currentDim];

                // Do a soft-check to see if we reached the total points limit. If we do, there is no need to bother:
                // (We will do a hard check and pre-booking later when we actually about to create the point.)
                if (_ownerCube.TotalPointsCount >= _ownerCube.TotalPointsCountLimit)
                {
                    return(new MultidimensionalPointResult <TPoint>(MultidimensionalPointResultCodes.Failure_TotalPointsCountLimitReached, failureCoordinateIndex: -1));
                }

                // We are not at the last level. Create the subdimension. Note, we are not under lock, so someone might be creating the same dimention concurrently:
                int  nextDim = currentDim + 1;
                bool isLastDimensionLevel = (nextDim == coordinates.Length - 1);
                var  newSubDim            = new MultidimensionalCubeDimension <TDimensionValue, TPoint>(
                    _ownerCube,
                    _ownerCube.GetSubdimensionsCountLimit(nextDim),
                    isLastDimensionLevel);
                MultidimensionalPointResult <TPoint> newSubDimResult = newSubDim.TryGetOrAddVectorInternal(coordinates, nextDim, createIfNotExists: true);

                // Becasue we have not yet inserted newSubDim into _elements, any operations on newSubDim are not under concurrency.
                // There are no point-vectors yet pointing to the sub-space of newSubDim, so no DimensionValuesCountLimit can be reached.
                // So, hasNewPoint can be false only if TotalPointsCountLimit was reached. We just bail out:
                if (!newSubDimResult.IsSuccess)
                {
                    return(newSubDimResult);
                }

                // The new point has been created and we need to add its sub-space to the list.
                // However, there is a race on someone calling GetOrAddVector(..) with the same coordinates. So newSubDim may or may not already be in the list.
                bool couldInsert = _elements.TryAdd(subElementKey, newSubDim);

                if (couldInsert)
                {
                    // Success. We created and inserted a new sub-space:
                    mustRestoreSubdimensionsCount = false;
                    return(newSubDimResult);
                }
                else
                {
                    // The point was already in the list. It's that other point (created by the race winner) that we want.
                    // We need to discard the sub-space and the point we just created: Decrement total points count and Decrement the dimension value count.
                    // After that we just call TryGetOrAddVectorInternal(..) again on the same recursion level.
                    _ownerCube.DecTotalPointsCount();
                }
            }
            finally
            {
                if (mustRestoreSubdimensionsCount)
                {
                    this.DecSubdimensionsCount();
                }
            }

            MultidimensionalPointResult <TPoint> retryResult = this.TryGetOrAddVectorInternal(coordinates, currentDim, createIfNotExists: true);

            return(retryResult);
        }