This closes #3089
This commit is contained in:
commit
aa0b6f6e5a
|
@ -53,9 +53,11 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
|
|||
private T defaultmatch;
|
||||
|
||||
/**
|
||||
* all the matches
|
||||
* the matches; separate wildcard matches from exact matches to reduce the searching necessary with a
|
||||
* large number of exact matches
|
||||
*/
|
||||
private final Map<String, Match<T>> matches = new HashMap<>();
|
||||
private final Map<String, Match<T>> wildcardMatches = new HashMap<>();
|
||||
private final Map<String, Match<T>> exactMatches = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Certain values cannot be removed after installed.
|
||||
|
@ -83,7 +85,8 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
|
|||
/**
|
||||
* Need a lock instead of using multiple {@link ConcurrentHashMap}s.
|
||||
* <p>
|
||||
* We could have a race between the state of {@link #matches} and {@link #cache}:
|
||||
* We could have a race between the state of {@link #wildcardMatches}, {@link #exactMatches},
|
||||
* and {@link #cache}:
|
||||
* <p>
|
||||
* Thread1: calls {@link #addMatch(String, T)}: i. cleans cache; ii. adds match to Map.<br>
|
||||
* Thread2: could add an (out-dated) entry to the cache between 'i. clean cache' and 'ii. add
|
||||
|
@ -145,9 +148,13 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
|
|||
public List<T> values() {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
ArrayList<T> values = new ArrayList<>(matches.size());
|
||||
ArrayList<T> values = new ArrayList<>(wildcardMatches.size() + exactMatches.size());
|
||||
|
||||
for (Match<T> matchValue : matches.values()) {
|
||||
for (Match<T> matchValue : wildcardMatches.values()) {
|
||||
values.add(matchValue.getValue());
|
||||
}
|
||||
|
||||
for (Match<T> matchValue : exactMatches.values()) {
|
||||
values.add(matchValue.getValue());
|
||||
}
|
||||
|
||||
|
@ -172,14 +179,23 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
|
|||
lock.writeLock().lock();
|
||||
try {
|
||||
String modifiedMatch = matchModifier.modify(match);
|
||||
clearCache();
|
||||
// an exact match (i.e. one without wildcards) won't impact any other matches so no need to clear the cache
|
||||
if (usesWildcards(modifiedMatch)) {
|
||||
clearCache();
|
||||
} else if (modifiedMatch != null && cache.containsKey(modifiedMatch)) {
|
||||
cache.remove(modifiedMatch);
|
||||
}
|
||||
|
||||
if (immutableMatch) {
|
||||
immutables.add(modifiedMatch);
|
||||
}
|
||||
Match.verify(modifiedMatch, wildcardConfiguration);
|
||||
Match<T> match1 = new Match<>(modifiedMatch, value, wildcardConfiguration);
|
||||
matches.put(modifiedMatch, match1);
|
||||
if (usesWildcards(modifiedMatch)) {
|
||||
wildcardMatches.put(modifiedMatch, match1);
|
||||
} else {
|
||||
exactMatches.put(modifiedMatch, match1);
|
||||
}
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
|
@ -190,6 +206,10 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
|
|||
}
|
||||
}
|
||||
|
||||
private boolean usesWildcards(String modifiedMatch) {
|
||||
return modifiedMatch == null ? false : (modifiedMatch.contains(wildcardConfiguration.getAnyWordsString()) || modifiedMatch.contains(wildcardConfiguration.getSingleWordString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCacheSize() {
|
||||
return cache.size();
|
||||
|
@ -277,11 +297,15 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
|
|||
logger.debug("Cannot remove match " + modMatch + " since it came from a main config");
|
||||
} else {
|
||||
/**
|
||||
* clear the cache before removing the match. This will force any thread at
|
||||
* {@link #getMatch(String)} to get the lock to recompute.
|
||||
* Clear the cache before removing the match, but only if the match used wildcards. This
|
||||
* will force any thread at {@link #getMatch(String)} to get the lock to recompute.
|
||||
*/
|
||||
clearCache();
|
||||
matches.remove(modMatch);
|
||||
if (usesWildcards(modMatch)) {
|
||||
clearCache();
|
||||
wildcardMatches.remove(modMatch);
|
||||
} else {
|
||||
exactMatches.remove(modMatch);
|
||||
}
|
||||
onChange();
|
||||
}
|
||||
} finally {
|
||||
|
@ -329,7 +353,7 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
|
|||
try {
|
||||
clearCache();
|
||||
listeners.clear();
|
||||
matches.clear();
|
||||
clearMatches();
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
|
@ -341,7 +365,7 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
|
|||
try {
|
||||
clearCache();
|
||||
immutables.clear();
|
||||
matches.clear();
|
||||
clearMatches();
|
||||
for (Map.Entry<String, T> entry : entries) {
|
||||
addMatch(entry.getKey(), entry.getValue(), true, false);
|
||||
}
|
||||
|
@ -362,6 +386,11 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
|
|||
cache.clear();
|
||||
}
|
||||
|
||||
private void clearMatches() {
|
||||
wildcardMatches.clear();
|
||||
exactMatches.clear();
|
||||
}
|
||||
|
||||
private void onChange() {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
|
@ -388,7 +417,11 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
|
|||
private Map<String, Match<T>> getPossibleMatches(final String match) {
|
||||
HashMap<String, Match<T>> possibleMatches = new HashMap<>();
|
||||
|
||||
for (Entry<String, Match<T>> entry : matches.entrySet()) {
|
||||
if (exactMatches.containsKey(match)) {
|
||||
possibleMatches.put(match, exactMatches.get(match));
|
||||
}
|
||||
|
||||
for (Entry<String, Match<T>> entry : wildcardMatches.entrySet()) {
|
||||
Match<T> entryMatch = entry.getValue();
|
||||
if (entryMatch.getPattern().matcher(match).matches()) {
|
||||
possibleMatches.put(entry.getKey(), entryMatch);
|
||||
|
|
|
@ -65,6 +65,18 @@ public class RepositoryTest extends ActiveMQTestBase {
|
|||
Assert.assertEquals("abd#", repo.getMatch("a.b.d"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheWithWildcards() throws Throwable {
|
||||
HierarchicalObjectRepository<String> repo = new HierarchicalObjectRepository<>();
|
||||
|
||||
repo.addMatch("#", "root");
|
||||
Assert.assertEquals("root", repo.getMatch("b"));
|
||||
|
||||
repo.addMatch("b", "leaf");
|
||||
Assert.assertEquals("leaf", repo.getMatch("b"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMatchingDocsCustomUnderscorDelimiter() throws Throwable {
|
||||
WildcardConfiguration wildcardConfiguration = new WildcardConfiguration();
|
||||
|
|
Loading…
Reference in New Issue