private static bool RemoveFromIndex( FilterHandle filterCallback, FilterParamIndexBase index, FilterValueSetParam[] @params, int currentLevel, object filterForValue) { using (index.ReadWriteLock.WriteLock.Acquire()) { EventEvaluator eventEvaluator = index.Get(filterForValue); if (eventEvaluator == null) { // This is possible as there can be another path return false; } if (eventEvaluator is FilterHandleSetNode) { var node = (FilterHandleSetNode) eventEvaluator; var found = RemoveFromNode(filterCallback, node, @params, currentLevel); if (!found) { return false; } var isEmpty = node.IsEmpty(); if (isEmpty) { // Since we are holding a write lock to this index, there should not be a chance that // another thread had been adding anything to this FilterHandleSetNode index.Remove(filterForValue); } return true; } var nextIndex = (FilterParamIndexBase) eventEvaluator; FilterParamIndexBase indexFound = null; if (nextIndex is FilterParamIndexLookupableBase) { var baseIndex = (FilterParamIndexLookupableBase) nextIndex; for (var i = 0; i < @params.Length; i++) { var param = @params[i]; if (param.Lookupable.Expression.Equals(baseIndex.Lookupable.Expression) && param.FilterOperator.Equals(baseIndex.FilterOperator)) { var found = RemoveFromIndex(filterCallback, baseIndex, @params, currentLevel + 1, param.FilterForValue); if (found) { indexFound = baseIndex; break; } } } } else { var booleanIndex = (FilterParamIndexBooleanExpr) nextIndex; for (var i = 0; i < @params.Length; i++) { var param = @params[i]; // if boolean-expression then match only if this is the last parameter, // all others considered are higher order and sort ahead if (param.FilterOperator.Equals(FilterOperator.BOOLEAN_EXPRESSION)) { bool found = booleanIndex.RemoveMayNotExist(param.FilterForValue); if (found) { indexFound = booleanIndex; break; } } } } if (indexFound == null) { return false; } var indexIsEmpty = nextIndex.IsEmpty; if (indexIsEmpty) { // Since we are holding a write lock to this index, there should not be a chance that // another thread had been adding anything to this FilterHandleSetNode index.Remove(filterForValue); } return true; } }
/// <summary> /// Add to an index the value to filter for. /// </summary> /// <param name="index">is the index to add to</param> /// <param name="filterForValue">is the filter parameter value to add</param> /// <param name="remainingParameters">any remaining parameters</param> /// <param name="filterCallback">the filter callback</param> /// <param name="lockFactory">the lock factory</param> private static void AddToIndex( ArrayDeque<FilterValueSetParam> remainingParameters, FilterHandle filterCallback, FilterParamIndexBase index, object filterForValue, FilterServiceGranularLockFactory lockFactory) { EventEvaluator eventEvaluator; using (index.ReadWriteLock.ReadLock.Acquire()) { eventEvaluator = index.Get(filterForValue); // The filter parameter value already existed in bean, add and release locks if (eventEvaluator != null) { var added = AddToEvaluator(remainingParameters, filterCallback, eventEvaluator, lockFactory); if (added) { return; } } } // new filter parameter value, need a write lock using (index.ReadWriteLock.WriteLock.Acquire()) { eventEvaluator = index.Get(filterForValue); // It may exist now since another thread could have added the entry if (eventEvaluator != null) { var added = AddToEvaluator(remainingParameters, filterCallback, eventEvaluator, lockFactory); if (added) { return; } // The found eventEvaluator must be converted to a new FilterHandleSetNode var nextIndexInner = (FilterParamIndexBase) eventEvaluator; var newNode = new FilterHandleSetNode(lockFactory.ObtainNew()); newNode.Add(nextIndexInner); index.Remove(filterForValue); index.Put(filterForValue, newNode); AddToNode(remainingParameters, filterCallback, newNode, lockFactory); return; } // The index does not currently have this filterCallback value, // if there are no remaining parameters, create a node if (remainingParameters.IsEmpty()) { var node = new FilterHandleSetNode(lockFactory.ObtainNew()); AddToNode(remainingParameters, filterCallback, node, lockFactory); index.Put(filterForValue, node); return; } // If there are remaining parameters, create a new index for the next parameter var parameterPickedForIndex = remainingParameters.RemoveFirst(); var nextIndex = IndexFactory.CreateIndex(parameterPickedForIndex.Lookupable, lockFactory, parameterPickedForIndex.FilterOperator); index.Put(filterForValue, nextIndex); AddToIndex(remainingParameters, filterCallback, nextIndex, parameterPickedForIndex.FilterForValue, lockFactory); } }