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); }