Skip to content

Commit 8a9e06e

Browse files
committed
some cleanup, added code comments
1 parent 41d24f2 commit 8a9e06e

File tree

8 files changed

+146
-122
lines changed

8 files changed

+146
-122
lines changed

metadata-io/src/main/java/com/linkedin/metadata/search/client/CacheEvictionService.java

+37-19
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@
1111
import org.springframework.cache.Cache;
1212
import org.springframework.cache.CacheManager;
1313

14+
/**
15+
* A framework to enable search cache invalidation. The cache keys in the search cache are queries
16+
* of different forms and when an entity is modified, there isnt a simple direct correlation of that
17+
* entity to the queries in the cache (except for fully evaluating that search). This service
18+
* provides a mechanism to implement some a CacheKeyMatcher that implements some approximations to
19+
* check if a cache key is likely related to some entity that was updated and clear those entries.
20+
* The evict method can be called when entities are updated and it is important for those updates to
21+
* be visible in the UI without waiting for cache expiration. The eviction is disabled by default
22+
* and enabled via a spring application property searchService.enableEviction
23+
*/
1424
@RequiredArgsConstructor
1525
@Slf4j
1626
public class CacheEvictionService {
@@ -37,7 +47,9 @@ public void invalidate(String cacheName) {
3747
}
3848
}
3949

40-
public void evict(CacheKeyMatcher matcher){
50+
// Runs all cache keys through the supplied matcher implementation and clear the cache keys
51+
// identified by the matcher.
52+
public void evict(CacheKeyMatcher matcher) {
4153

4254
if (cachingEnabled && enableEviction) {
4355
Collection<String> cacheNames = cacheManager.getCacheNames();
@@ -50,18 +62,26 @@ public void evict(CacheKeyMatcher matcher){
5062
for (Object key : keys) {
5163
if (matcher.match(cacheName, key)) {
5264
cache.evict(key);
53-
evictCount ++;
65+
evictCount++;
5466
log.debug("From cache '{}' evicting key {}", cacheName, key);
5567
}
5668
}
57-
if (evictCount>0){
69+
if (evictCount > 0) {
5870
log.info("Evicted {} keys from cache {}", evictCount, cacheName);
5971
}
6072
}
6173
}
6274
}
6375
}
6476

77+
// Use a UrnCacheKeyMatcher implement to evict cache keys that are likely related to the supplied
78+
// list of urns
79+
public void evict(List<Urn> urns) {
80+
log.info("Attempting eviction of search cache due to updates to {}", urns);
81+
UrnCacheKeyMatcher matcher = new UrnCacheKeyMatcher(urns);
82+
evict(matcher);
83+
}
84+
6585
private Set<Object> getKeys(String cacheName) {
6686
// Enumerating cache keys is not part of the standard Cache interface, but needs is native cache
6787
// implementation
@@ -86,22 +106,20 @@ private Set<Object> getKeys(String cacheName) {
86106
return Collections.emptySet();
87107
}
88108

89-
//Useful during matcher debugging, but voluminous
90-
private void dumpCache(String message){
109+
// Useful during matcher debugging, but voluminous
110+
private void dumpCache(String message) {
91111
log.debug("Begin Dump {}", message);
92-
cacheManager.getCacheNames()
93-
.forEach(cacheName -> {
94-
log.debug("Dump cache: {}", cacheName);
95-
Cache cache = cacheManager.getCache(cacheName);
96-
getKeys(cacheName).forEach(key -> {
97-
log.debug(" key {} : {}", key, cache.get(key));
98-
});
99-
});
100-
}
101-
102-
public void evict(List<Urn> urns) {
103-
log.info("Attempting eviction of search cache due to updates to {}", urns);
104-
UrnCacheKeyMatcher matcher = new UrnCacheKeyMatcher(urns);
105-
evict(matcher);
112+
cacheManager
113+
.getCacheNames()
114+
.forEach(
115+
cacheName -> {
116+
log.debug("Dump cache: {}", cacheName);
117+
Cache cache = cacheManager.getCache(cacheName);
118+
getKeys(cacheName)
119+
.forEach(
120+
key -> {
121+
log.debug(" key {} : {}", key, cache.get(key));
122+
});
123+
});
106124
}
107125
}

metadata-io/src/main/java/com/linkedin/metadata/search/client/CachingEntitySearchService.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@
3030

3131
@RequiredArgsConstructor
3232
public class CachingEntitySearchService {
33-
static final String ENTITY_SEARCH_SERVICE_SEARCH_CACHE_NAME = "entitySearchServiceSearch";
34-
static final String ENTITY_SEARCH_SERVICE_AUTOCOMPLETE_CACHE_NAME =
33+
public static final String ENTITY_SEARCH_SERVICE_SEARCH_CACHE_NAME = "entitySearchServiceSearch";
34+
public static final String ENTITY_SEARCH_SERVICE_AUTOCOMPLETE_CACHE_NAME =
3535
"entitySearchServiceAutoComplete";
36-
static final String ENTITY_SEARCH_SERVICE_BROWSE_CACHE_NAME = "entitySearchServiceBrowse";
37-
static final String ENTITY_SEARCH_SERVICE_SCROLL_CACHE_NAME = "entitySearchServiceScroll";
36+
public static final String ENTITY_SEARCH_SERVICE_BROWSE_CACHE_NAME = "entitySearchServiceBrowse";
37+
public static final String ENTITY_SEARCH_SERVICE_SCROLL_CACHE_NAME = "entitySearchServiceScroll";
3838

3939
private final CacheManager cacheManager;
4040
private final EntitySearchService

metadata-io/src/main/java/com/linkedin/metadata/search/client/UrnCacheKeyMatcher.java

+29-9
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ public boolean match(String cacheName, Object key) {
4848
}
4949

5050
private boolean matchSearchServiceScrollCacheKey(Object key) {
51-
Octet<?, List<String>, String, String, ?, ?, List<String>, ?> cacheKey
52-
= (Octet<?, List<String>, String, String, ?, ?, List<String>, ?>) key;
51+
Octet<?, List<String>, String, String, ?, ?, List<String>, ?> cacheKey =
52+
(Octet<?, List<String>, String, String, ?, ?, List<String>, ?>) key;
53+
// For reference - cache key contents
5354
// @Nonnull OperationContext opContext,
5455
// @Nonnull List<String> entities,
5556
// @Nonnull String query,
@@ -63,34 +64,53 @@ private boolean matchSearchServiceScrollCacheKey(Object key) {
6364
String query = (String) cacheKey.getValue(2);
6465
List<String> facets = (List<String>) cacheKey.getValue(6);
6566

66-
//Facets may contain urns. Since the check for urns in filters is similar, can append it to the filter.
67-
return isKeyImpactedByEntity(entitiesInCacheKey, query, filter + " " + String.join(" ",facets ));
67+
// Facets may contain urns. Since the check for urns in filters is similar, can append it to the
68+
// filter.
69+
return isKeyImpactedByEntity(
70+
entitiesInCacheKey, query, filter + " " + String.join(" ", facets));
6871
}
6972

7073
private boolean matchSearchServiceCacheKey(Object key) {
7174
Septet<?, List<String>, ?, String, ?, ?, ?> cacheKey =
7275
(Septet<?, List<String>, ?, String, ?, ?, ?>) key;
76+
// For reference
77+
// @Nonnull OperationContext opContext,
78+
// @Nonnull List<String> entityNames,
79+
// @Nonnull String query,
80+
// @Nullable Filter filters,
81+
// List<SortCriterion> sortCriteria,
82+
// @Nonnull List<String> facets
83+
// querySize
7384

7485
List<String> entitiesInCacheKey = (List<String>) cacheKey.getValue(1);
7586
String filter = (String) cacheKey.getValue(3);
7687
String query = (String) cacheKey.getValue(2);
88+
List<String> facets = (List<String>) cacheKey.getValue(5);
89+
90+
// Facets may contain urns. Since the check for urns in filters is similar, can append it to the
91+
// filter.
92+
if (filter == null) {
93+
filter = "";
94+
}
95+
filter += " " + String.join(" ", facets);
7796

7897
return isKeyImpactedByEntity(entitiesInCacheKey, query, filter);
7998
}
8099

81-
boolean isKeyImpactedByEntity(List<String> entitiesInCacheKey, String query, String filter){
100+
boolean isKeyImpactedByEntity(List<String> entitiesInCacheKey, String query, String filter) {
82101
boolean entityMatch = entitiesInCacheKey.stream().anyMatch(entityTypes::contains);
83102
if (!entityMatch) {
84103
return false;
85104
}
86105

87-
if (filter == null){ //No filter, but already established there is an entity match
106+
if (filter == null) { // No filter, but already established there is an entity match
88107
return true;
89108
}
90109

91-
// Ignoring query for now. A query could make this cache entry more targeted, but till there is a quick way to
92-
// evaluate if the entities that were updated are affected by this query, ignoring it may mean some cache entries
93-
// are invalidated even if they may not be a match, and an uncached query result will still be fetched.
110+
// Ignoring query for now. A query could make this cache entry more targeted, but till there is
111+
// a quick way to evaluate if the entities that were updated are affected by this query,
112+
// ignoring it may mean some cache entries are invalidated even if they may not be a match,
113+
// and an uncached query result will still be fetched.
94114

95115
boolean containsUrn = filter.contains("urn:li");
96116
if (!containsUrn) {

0 commit comments

Comments
 (0)