Example #1
0
        private MultidimensionalPointResult <TPoint> TryAddPoint(TDimensionValue[] coordinates, int currentDim)
        {
            // We need to create a new sub-element, but we need to make sure that we do not exceed max dimension count in a concurrent situation.
            // To avoid locking as much as possible (it will be inevitable in some situations inside of the concurrent dictionary), we use an
            // interlocked increment of the dimension count early in the process to pre-book the new element. If all creation steps do not
            // complete succesfully, we will undo the increment.
            // Fortunately, it is a relatively rare case:
            // The increment will be successful only if the specified coordinates vector does not (yet) exist, but the max dimension limit is not yet exhaustet.
            // This can occur no more than (approx.) Cm = Md1 * Md2 * ... * Mdn times, where Mdi is the max dimension limit for dimension i.

            // 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
            {
                // We are on the last level and we need to create the actual point. However, before doing that we need to check and pre-book the total
                // count limit using the same pattern as the dimension values limit:
                if (!_ownerCube.TryIncTotalPointsCount())
                {
                    return(new MultidimensionalPointResult <TPoint>(MultidimensionalPointResultCodes.Failure_TotalPointsCountLimitReached, failureCoordinateIndex: -1));
                }

                bool mustRestoreTotalPointsCount = true;
                try
                {
                    TPoint newPoint = _ownerCube.InvokePointsFactory(coordinates);

                    TDimensionValue subElementKey = coordinates[currentDim];
                    bool            couldInsert   = _elements.TryAdd(subElementKey, newPoint);

                    // There is a race on someone calling GetOrAddVector(..) with the same coordinates. So point may or may not already be in the list.
                    if (couldInsert)
                    {
                        mustRestoreTotalPointsCount   = false;
                        mustRestoreSubdimensionsCount = false;
                        return(new MultidimensionalPointResult <TPoint>(MultidimensionalPointResultCodes.Success_NewPointCreated, newPoint));
                    }
                    else
                    {
                        // If the point was already in the list, then that other point created by the race winner is the one we want.
                        TPoint existingPoint = (TPoint)_elements[subElementKey];
                        return(new MultidimensionalPointResult <TPoint>(MultidimensionalPointResultCodes.Success_ExistingPointRetrieved, existingPoint));
                    }
                }
                finally
                {
                    if (mustRestoreTotalPointsCount)
                    {
                        _ownerCube.DecTotalPointsCount();
                    }
                }
            }
            finally
            {
                if (mustRestoreSubdimensionsCount)
                {
                    this.DecSubdimensionsCount();
                }
            }
        }