/// <summary> /// Add a filter callback according to the filter specification to the top node returning /// information to be used to remove the filter callback. /// </summary> /// <param name="valueSet">is the filter definition</param> /// <param name="filterCallback">is the callback to be added</param> /// <param name="topNode">node to be added to any subnode beneath it</param> /// <param name="lockFactory">lock factory</param> public static void Add( FilterValueSetParam[][] valueSet, FilterHandle filterCallback, FilterHandleSetNode topNode, FilterServiceGranularLockFactory lockFactory) { if (ExecutionPathDebugLog.IsDebugEnabled && log.IsDebugEnabled) { log.Debug( ".add (" + Thread.CurrentThread.ManagedThreadId + ") Adding filter callback, " + " topNode=" + topNode + " filterCallback=" + filterCallback); } if (valueSet.Length == 0) { AddToNode(new ArrayDeque<FilterValueSetParam>(1), filterCallback, topNode, lockFactory); } else { var remainingParameters = new ArrayDeque<FilterValueSetParam>(); for (var i = 0; i < valueSet.Length; i++) { remainingParameters.Clear(); remainingParameters.AddAll(valueSet[i]); AddToNode(remainingParameters, filterCallback, topNode, lockFactory); } } }
/// <summary>Add to the current node building up the tree path information.</summary> /// <param name="remainingParameters">any remaining parameters</param> /// <param name="filterCallback">the filter callback</param> /// <param name="currentNode">is the node to add to</param> /// <param name="lockFactory">the lock factory</param> private static void AddToNode( ArrayDeque<FilterValueSetParam> remainingParameters, FilterHandle filterCallback, FilterHandleSetNode currentNode, FilterServiceGranularLockFactory lockFactory) { // If no parameters are specified, add to current node, and done if (remainingParameters.IsEmpty()) { using (currentNode.NodeRWLock.WriteLock.Acquire()) { currentNode.Add(filterCallback); } return; } // Need to find an existing index that matches one of the filter parameters Pair<FilterValueSetParam, FilterParamIndexBase> pair; using (currentNode.NodeRWLock.ReadLock.Acquire()) { pair = IndexHelper.FindIndex(remainingParameters, currentNode.Indizes); // Found an index matching a filter parameter if (pair != null) { remainingParameters.Remove(pair.First); var filterForValue = pair.First.FilterForValue; var index = pair.Second; AddToIndex(remainingParameters, filterCallback, index, filterForValue, lockFactory); return; } } // An index for any of the filter parameters was not found, create one using (currentNode.NodeRWLock.WriteLock.Acquire()) { pair = IndexHelper.FindIndex(remainingParameters, currentNode.Indizes); // Attempt to find an index again this time under a write lock if (pair != null) { remainingParameters.Remove(pair.First); var filterForValue = pair.First.FilterForValue; var indexInner = pair.Second; AddToIndex(remainingParameters, filterCallback, indexInner, filterForValue, lockFactory); return; } // No index found that matches any parameters, create a new one // Pick the next parameter for an index var parameterPickedForIndex = remainingParameters.RemoveFirst(); var index = IndexFactory.CreateIndex(parameterPickedForIndex.Lookupable, lockFactory, parameterPickedForIndex.FilterOperator); currentNode.Add(index); AddToIndex(remainingParameters, filterCallback, index, parameterPickedForIndex.FilterForValue, lockFactory); } }
public void TestMultithreaded() { var topNode = new FilterHandleSetNode(new SlimReaderWriterLock()); PerformMultithreadedTest(topNode, 2, 1000, 1); PerformMultithreadedTest(topNode, 3, 1000, 1); PerformMultithreadedTest(topNode, 4, 1000, 1); PerformMultithreadedTest(new FilterHandleSetNode(new SlimReaderWriterLock()), 2, 1000, 1); PerformMultithreadedTest(new FilterHandleSetNode(new SlimReaderWriterLock()), 3, 1000, 1); PerformMultithreadedTest(new FilterHandleSetNode(new SlimReaderWriterLock()), 4, 1000, 1); }
/// <summary> /// Add a new event type to the index and use the specified node for the root node of its subtree. /// If the event type already existed, the method will throw an IllegalStateException. /// </summary> /// <param name="eventType">is the event type to be added to the index</param> /// <param name="rootNode">is the root node of the subtree for filter constant indizes and callbacks</param> public void Add( EventType eventType, FilterHandleSetNode rootNode) { using (eventTypesRWLock.WriteLock.Acquire()) { if (eventTypes.ContainsKey(eventType)) { throw new IllegalStateException("Event type already in index, add not performed, type=" + eventType); } eventTypes.Put(eventType, rootNode); } }
public SupportIndexTreeBuilderRunnable( EventType eventType, FilterHandleSetNode topNode, IList <FilterSpecActivatable> testFilterSpecs, IList <EventBean> matchedEvents, IList <EventBean> unmatchedEvents, IReaderWriterLockManager rwLockManager) { this.eventType = eventType; this.topNode = topNode; this.testFilterSpecs = testFilterSpecs; this.matchedEvents = matchedEvents; this.unmatchedEvents = unmatchedEvents; this.lockFactory = new FilterServiceGranularLockFactoryReentrant(rwLockManager); }
public void SetUp() { SupportBean testBean = new SupportBean(); testEventBean = SupportEventBeanFactory .GetInstance(container) .CreateObject(testBean); testEventType = testEventBean.EventType; handleSetNode = new FilterHandleSetNode(new SlimReaderWriterLock()); filterCallback = new SupportFilterHandle(); handleSetNode.Add(filterCallback); testIndex = new EventTypeIndex(new FilterServiceGranularLockFactoryReentrant( container.RWLockManager())); testIndex.Add(testEventType, handleSetNode); }
private void PerformMultithreadedTest( FilterHandleSetNode topNode, int numberOfThreads, int numberOfRunnables, int numberOfSecondsSleep) { log.Info(".PerformMultithreadedTest Loading thread pool work queue,numberOfRunnables={0}", numberOfRunnables); var pool = Executors.NewMultiThreadedExecutor(numberOfThreads); //var pool = new ThreadPoolExecutor(0, numberOfThreads, 99999, // TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); for (var i = 0; i < numberOfRunnables; i++) { var runnable = new SupportIndexTreeBuilderRunnable( eventType, topNode, testFilterSpecs, matchedEvents, unmatchedEvents, container.RWLockManager()); pool.Submit(() => runnable.Run()); } log.Info(".PerformMultithreadedTest Starting thread pool, threads={0}", numberOfThreads); //pool.CorePoolSize = numberOfThreads; // Sleep X seconds Sleep(numberOfSecondsSleep); log.Info(".PerformMultithreadedTest Completed, numberOfRunnables={0} numberOfThreads={1} completed={2}", numberOfRunnables, numberOfThreads, pool.NumExecuted); pool.Shutdown(); pool.AwaitTermination(1, TimeUnit.SECONDS); Assert.IsTrue(pool.NumExecuted == numberOfRunnables); }
private void MatchType( EventType eventType, EventBean eventBean, ICollection<FilterHandle> matches, ExprEvaluatorContext ctx) { FilterHandleSetNode rootNode = null; using (eventTypesRWLock.ReadLock.Acquire()) { rootNode = eventTypes.Get(eventType); } // If the top class node is null, no filters have yet been registered for this event type. // In this case, log a message and done. if (rootNode == null) { return; } rootNode.MatchEvent(eventBean, matches, ctx); }
/// <summary> /// Add a filter to the event type index structure, and to the filter subtree. /// Throws an IllegalStateException exception if the callback is already registered. /// </summary> /// <param name="valueSet">is the filter information</param> /// <param name="filterCallback">is the callback</param> /// <param name="lockFactory">lock factory</param> /// <param name="eventType">event type</param> public void Add( EventType eventType, FilterValueSetParam[][] valueSet, FilterHandle filterCallback, FilterServiceGranularLockFactory lockFactory) { // Check if a filter tree exists for this event type var rootNode = eventTypeIndex.Get(eventType); // Make sure we have a root node if (rootNode == null) { using (callbacksLock.Acquire()) { rootNode = eventTypeIndex.Get(eventType); if (rootNode == null) { rootNode = new FilterHandleSetNode(lockFactory.ObtainNew()); eventTypeIndex.Add(eventType, rootNode); } } } // Now add to tree IndexTreeBuilderAdd.Add(valueSet, filterCallback, rootNode, lockFactory); }
/// <summary> /// Remove an filterCallback from the given top node. The IndexTreePath instance passed in must be the /// same as obtained when the same filterCallback was added. /// </summary> /// <param name="filterCallback">filter callback to be removed</param> /// <param name="topNode">The top tree node beneath which the filterCallback was added</param> /// <param name="eventType">event type</param> /// <param name="params">params</param> public static void Remove( EventType eventType, FilterHandle filterCallback, FilterValueSetParam[] @params, FilterHandleSetNode topNode) { if (ExecutionPathDebugLog.IsDebugEnabled && Log.IsDebugEnabled) { Log.Debug( ".remove (" + Thread.CurrentThread.ManagedThreadId + ") Removing filterCallback " + " type " + eventType.Name + " topNode=" + topNode + " filterCallback=" + filterCallback); } var isRemoved = RemoveFromNode(filterCallback, topNode, @params, 0); if (!isRemoved) { Log.Warn( ".removeFromNode (" + Thread.CurrentThread.ManagedThreadId + ") Could not find the filterCallback to be removed within the supplied node, params=" + @params.RenderAny() + " filterCallback=" + filterCallback); } }
public void SetUp() { lockFactory = new FilterServiceGranularLockFactoryReentrant( container.RWLockManager()); eventType = SupportEventTypeFactory .GetInstance(container) .CreateBeanType(typeof(SupportBean)); topNode = new FilterHandleSetNode(new SlimReaderWriterLock()); filterCallbacks = new List <FilterHandle>(); testFilterSpecs = new List <FilterSpecActivatable>(); matchedEvents = new List <EventBean>(); unmatchedEvents = new List <EventBean>(); // Any int and double value specified here must match only the current filter spec not any other filter spec testFilterSpecs.Add(MakeSpec(new object[] { "IntPrimitive", FilterOperator.GREATER_OR_EQUAL, 100000 })); matchedEvents.Add(MakeEvent(9999999, -1)); unmatchedEvents.Add(MakeEvent(0, -1)); testFilterSpecs.Add( MakeSpec( new object[] { "IntPrimitive", FilterOperator.GREATER_OR_EQUAL, 10, "DoublePrimitive", FilterOperator.EQUAL, 0.5 })); matchedEvents.Add(MakeEvent(10, 0.5)); unmatchedEvents.Add(MakeEvent(0, 0.5)); testFilterSpecs.Add(MakeSpec(new object[] { "DoublePrimitive", FilterOperator.EQUAL, 0.8 })); matchedEvents.Add(MakeEvent(-1, 0.8)); unmatchedEvents.Add(MakeEvent(-1, 0.1)); testFilterSpecs.Add( MakeSpec( new object[] { "DoublePrimitive", FilterOperator.EQUAL, 99.99, "IntPrimitive", FilterOperator.LESS, 1 })); matchedEvents.Add(MakeEvent(0, 99.99)); unmatchedEvents.Add(MakeEvent(2, 0.5)); testFilterSpecs.Add( MakeSpec( new object[] { "DoublePrimitive", FilterOperator.GREATER, .99, "IntPrimitive", FilterOperator.EQUAL, 5001 })); matchedEvents.Add(MakeEvent(5001, 1.1)); unmatchedEvents.Add(MakeEvent(5002, 0.98)); testFilterSpecs.Add(MakeSpec(new object[] { "IntPrimitive", FilterOperator.LESS, -99000 })); matchedEvents.Add(MakeEvent(-99001, -1)); unmatchedEvents.Add(MakeEvent(-98999, -1)); testFilterSpecs.Add( MakeSpec( new object[] { "IntPrimitive", FilterOperator.GREATER_OR_EQUAL, 11, "DoublePrimitive", FilterOperator.GREATER, 888.0 })); matchedEvents.Add(MakeEvent(11, 888.001)); unmatchedEvents.Add(MakeEvent(10, 888)); testFilterSpecs.Add( MakeSpec( new object[] { "IntPrimitive", FilterOperator.EQUAL, 973, "DoublePrimitive", FilterOperator.EQUAL, 709.0 })); matchedEvents.Add(MakeEvent(973, 709)); unmatchedEvents.Add(MakeEvent(0, 0.5)); testFilterSpecs.Add( MakeSpec( new object[] { "IntPrimitive", FilterOperator.EQUAL, 973, "DoublePrimitive", FilterOperator.EQUAL, 655.0 })); matchedEvents.Add(MakeEvent(973, 655)); unmatchedEvents.Add(MakeEvent(33838, 655.5)); }
public void SetUp() { testEvaluator = new SupportEventEvaluator(); testNode = new FilterHandleSetNode(new SlimReaderWriterLock()); }
private static bool RemoveFromNode( FilterHandle filterCallback, FilterHandleSetNode currentNode, FilterValueSetParam[] @params, int currentLevel) { // No remaining filter parameters if (currentLevel == @params.Length) { using (currentNode.NodeRWLock.WriteLock.Acquire()) { return currentNode.Remove(filterCallback); } } if (currentLevel > @params.Length) { Log.Warn( ".removeFromNode (" + Thread.CurrentThread.ManagedThreadId + ") Current level exceed parameter length, node=" + currentNode + " filterCallback=" + filterCallback); return false; } // Remove from index using (currentNode.NodeRWLock.WriteLock.Acquire()) { FilterParamIndexBase indexFound = null; // find matching index foreach (var index in currentNode.Indizes) { for (var i = 0; i < @params.Length; i++) { var param = @params[i]; var indexMatch = false; if (index is FilterParamIndexLookupableBase) { var baseIndex = (FilterParamIndexLookupableBase) index; if (param.Lookupable.Expression.Equals(baseIndex.Lookupable.Expression) && param.FilterOperator.Equals(baseIndex.FilterOperator)) { indexMatch = true; } } else if (index is FilterParamIndexBooleanExpr && param.FilterOperator == FilterOperator.BOOLEAN_EXPRESSION) { indexMatch = true; } if (indexMatch) { bool found = RemoveFromIndex(filterCallback, index, @params, currentLevel + 1, param.FilterForValue); if (found) { indexFound = index; break; } } } if (indexFound != null) { break; } } if (indexFound == null) { return false; } // Remove the index if the index is now empty if (indexFound.IsEmpty) { var isRemoved = currentNode.Remove(indexFound); if (!isRemoved) { Log.Warn( ".removeFromNode (" + Thread.CurrentThread.ManagedThreadId + ") Could not find the index in index list for removal, index=" + indexFound + " filterCallback=" + filterCallback); return true; } } return true; } }
public void TestBuildWithMatch() { var topNode = new FilterHandleSetNode(new SlimReaderWriterLock()); // Add some parameter-less expression var filterSpec = MakeFilterValues(); IndexTreeBuilderAdd.Add(filterSpec, testFilterCallback[0], topNode, lockFactory); Assert.IsTrue(topNode.Contains(testFilterCallback[0])); // Attempt a match topNode.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 1); matches.Clear(); // Add a filter that won't match, with a single parameter matching against an int filterSpec = MakeFilterValues("IntPrimitive", FilterOperator.EQUAL, 100); IndexTreeBuilderAdd.Add(filterSpec, testFilterCallback[1], topNode, lockFactory); Assert.IsTrue(topNode.Indizes.Count == 1); Assert.IsTrue(topNode.Indizes[0].CountExpensive == 1); // Match again topNode.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 1); matches.Clear(); // Add a filter that will match filterSpec = MakeFilterValues("IntPrimitive", FilterOperator.EQUAL, 50); IndexTreeBuilderAdd.Add(filterSpec, testFilterCallback[2], topNode, lockFactory); Assert.IsTrue(topNode.Indizes.Count == 1); Assert.IsTrue(topNode.Indizes[0].CountExpensive == 2); // match topNode.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 2); matches.Clear(); // Add some filter against a double filterSpec = MakeFilterValues("DoublePrimitive", FilterOperator.LESS, 1.1); IndexTreeBuilderAdd.Add(filterSpec, testFilterCallback[3], topNode, lockFactory); Assert.IsTrue(topNode.Indizes.Count == 2); Assert.IsTrue(topNode.Indizes[0].CountExpensive == 2); Assert.IsTrue(topNode.Indizes[1].CountExpensive == 1); topNode.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 3); matches.Clear(); filterSpec = MakeFilterValues("DoublePrimitive", FilterOperator.LESS_OR_EQUAL, 0.5); IndexTreeBuilderAdd.Add(filterSpec, testFilterCallback[4], topNode, lockFactory); Assert.IsTrue(topNode.Indizes.Count == 3); Assert.IsTrue(topNode.Indizes[0].CountExpensive == 2); Assert.IsTrue(topNode.Indizes[1].CountExpensive == 1); Assert.IsTrue(topNode.Indizes[2].CountExpensive == 1); topNode.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 4); matches.Clear(); // Add an filterSpec against double and string filterSpec = MakeFilterValues("DoublePrimitive", FilterOperator.LESS, 1.1, "TheString", FilterOperator.EQUAL, "jack"); IndexTreeBuilderAdd.Add(filterSpec, testFilterCallback[5], topNode, lockFactory); Assert.IsTrue(topNode.Indizes.Count == 3); Assert.IsTrue(topNode.Indizes[0].CountExpensive == 2); Assert.IsTrue(topNode.Indizes[1].CountExpensive == 1); Assert.IsTrue(topNode.Indizes[2].CountExpensive == 1); var nextLevelSetNode = (FilterHandleSetNode)topNode.Indizes[1].Get(1.1d); Assert.IsTrue(nextLevelSetNode != null); Assert.IsTrue(nextLevelSetNode.Indizes.Count == 1); topNode.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 5); matches.Clear(); filterSpec = MakeFilterValues("DoublePrimitive", FilterOperator.LESS, 1.1, "TheString", FilterOperator.EQUAL, "beta"); IndexTreeBuilderAdd.Add(filterSpec, testFilterCallback[6], topNode, lockFactory); topNode.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 5); matches.Clear(); filterSpec = MakeFilterValues("DoublePrimitive", FilterOperator.LESS, 1.1, "TheString", FilterOperator.EQUAL, "jack"); IndexTreeBuilderAdd.Add(filterSpec, testFilterCallback[7], topNode, lockFactory); Assert.IsTrue(nextLevelSetNode.Indizes.Count == 1); var nodeTwo = (FilterHandleSetNode)nextLevelSetNode.Indizes[0].Get("jack"); Assert.IsTrue(nodeTwo.FilterCallbackCount == 2); topNode.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 6); matches.Clear(); // Try depth first filterSpec = MakeFilterValues("TheString", FilterOperator.EQUAL, "jack", "LongPrimitive", FilterOperator.EQUAL, 10L, "ShortPrimitive", FilterOperator.EQUAL, (short)20); IndexTreeBuilderAdd.Add(filterSpec, testFilterCallback[8], topNode, lockFactory); topNode.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 7); matches.Clear(); // Add an filterSpec in the middle filterSpec = MakeFilterValues("LongPrimitive", FilterOperator.EQUAL, 10L, "TheString", FilterOperator.EQUAL, "jack"); IndexTreeBuilderAdd.Add(filterSpec, testFilterCallback[9], topNode, lockFactory); filterSpec = MakeFilterValues("LongPrimitive", FilterOperator.EQUAL, 10L, "TheString", FilterOperator.EQUAL, "jim"); IndexTreeBuilderAdd.Add(filterSpec, testFilterCallback[10], topNode, lockFactory); filterSpec = MakeFilterValues("LongPrimitive", FilterOperator.EQUAL, 10L, "TheString", FilterOperator.EQUAL, "joe"); IndexTreeBuilderAdd.Add(filterSpec, testFilterCallback[11], topNode, lockFactory); topNode.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 8); matches.Clear(); }
public void TestBuildMatchRemove() { var top = new FilterHandleSetNode(new SlimReaderWriterLock()); // Add a parameter-less filter var filterSpecNoParams = MakeFilterValues(); IndexTreeBuilderAdd.Add(filterSpecNoParams, testFilterCallback[0], top, lockFactory); // Try a match top.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 1); matches.Clear(); // Remove filter IndexTreeBuilderRemove.Remove(eventType, testFilterCallback[0], filterSpecNoParams[0], top); // Match should not be found top.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 0); matches.Clear(); // Add a depth-first filterSpec var filterSpecOne = MakeFilterValues( "TheString", FilterOperator.EQUAL, "jack", "LongPrimitive", FilterOperator.EQUAL, 10L, "ShortPrimitive", FilterOperator.EQUAL, (short)20); IndexTreeBuilderAdd.Add(filterSpecOne, testFilterCallback[1], top, lockFactory); var filterSpecTwo = MakeFilterValues( "TheString", FilterOperator.EQUAL, "jack", "LongPrimitive", FilterOperator.EQUAL, 10L, "ShortPrimitive", FilterOperator.EQUAL, (short)20); IndexTreeBuilderAdd.Add(filterSpecTwo, testFilterCallback[2], top, lockFactory); var filterSpecThree = MakeFilterValues( "TheString", FilterOperator.EQUAL, "jack", "LongPrimitive", FilterOperator.EQUAL, 10L); IndexTreeBuilderAdd.Add(filterSpecThree, testFilterCallback[3], top, lockFactory); var filterSpecFour = MakeFilterValues( "TheString", FilterOperator.EQUAL, "jack"); IndexTreeBuilderAdd.Add(filterSpecFour, testFilterCallback[4], top, lockFactory); var filterSpecFive = MakeFilterValues( "LongPrimitive", FilterOperator.EQUAL, 10L); IndexTreeBuilderAdd.Add(filterSpecFive, testFilterCallback[5], top, lockFactory); top.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 5); matches.Clear(); // Remove some of the nodes IndexTreeBuilderRemove.Remove(eventType, testFilterCallback[2], filterSpecTwo[0], top); top.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 4); matches.Clear(); // Remove some of the nodes IndexTreeBuilderRemove.Remove(eventType, testFilterCallback[4], filterSpecFour[0], top); top.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 3); matches.Clear(); // Remove some of the nodes IndexTreeBuilderRemove.Remove(eventType, testFilterCallback[5], filterSpecFive[0], top); top.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 2); matches.Clear(); // Remove some of the nodes IndexTreeBuilderRemove.Remove(eventType, testFilterCallback[1], filterSpecOne[0], top); top.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 1); matches.Clear(); // Remove some of the nodes IndexTreeBuilderRemove.Remove(eventType, testFilterCallback[3], filterSpecThree[0], top); top.MatchEvent(eventBean, matches, null); Assert.IsTrue(matches.Count == 0); matches.Clear(); }
/// <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); } }