Skip to content

Commit d356685

Browse files
authored
Precompute the BitsetCacheKey hashCode (#132875)
1 parent 768396d commit d356685

File tree

1 file changed

+28
-17
lines changed

1 file changed

+28
-17
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/accesscontrol/DocumentSubsetBitsetCache.java

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,8 @@ public DocumentSubsetBitsetCache(Settings settings, ThreadPool threadPool) {
151151
}
152152

153153
@Override
154-
public void onClose(IndexReader.CacheKey ownerCoreCacheKey) {
155-
final Set<BitsetCacheKey> keys = keysByIndex.remove(ownerCoreCacheKey);
154+
public void onClose(IndexReader.CacheKey indexKey) {
155+
final Set<BitsetCacheKey> keys = keysByIndex.remove(indexKey);
156156
if (keys != null) {
157157
// Because this Set has been removed from the map, and the only update to the set is performed in a
158158
// Map#compute call, it should not be possible to get a concurrent modification here.
@@ -164,10 +164,10 @@ public void onClose(IndexReader.CacheKey ownerCoreCacheKey) {
164164
* Cleanup (synchronize) the internal state when an object is removed from the primary cache
165165
*/
166166
private void onCacheEviction(RemovalNotification<BitsetCacheKey, BitSet> notification) {
167-
final BitsetCacheKey bitsetKey = notification.getKey();
168-
final IndexReader.CacheKey indexKey = bitsetKey.index;
169-
if (keysByIndex.getOrDefault(indexKey, Set.of()).contains(bitsetKey) == false) {
170-
// If the bitsetKey isn't in the lookup map, then there's nothing to synchronize
167+
final BitsetCacheKey cacheKey = notification.getKey();
168+
final IndexReader.CacheKey indexKey = cacheKey.indexKey;
169+
if (keysByIndex.getOrDefault(indexKey, Set.of()).contains(cacheKey) == false) {
170+
// If the cacheKey isn't in the lookup map, then there's nothing to synchronize
171171
return;
172172
}
173173
// We push this to a background thread, so that it reduces the risk of blocking searches, but also so that the lock management is
@@ -177,9 +177,9 @@ private void onCacheEviction(RemovalNotification<BitsetCacheKey, BitSet> notific
177177
cleanupExecutor.submit(() -> {
178178
try (ReleasableLock ignored = cacheEvictionLock.acquire()) {
179179
// it's possible for the key to be back in the cache if it was immediately repopulated after it was evicted, so check
180-
if (bitsetCache.get(bitsetKey) == null) {
180+
if (bitsetCache.get(cacheKey) == null) {
181181
// key is no longer in the cache, make sure it is no longer in the lookup map either.
182-
Optional.ofNullable(keysByIndex.get(indexKey)).ifPresent(set -> set.remove(bitsetKey));
182+
Optional.ofNullable(keysByIndex.get(indexKey)).ifPresent(set -> set.remove(cacheKey));
183183
}
184184
}
185185
});
@@ -325,12 +325,17 @@ public Map<String, Object> usageStats() {
325325

326326
private static final class BitsetCacheKey {
327327

328-
final IndexReader.CacheKey index;
328+
final IndexReader.CacheKey indexKey;
329329
final Query query;
330+
final int hashCode;
330331

331-
private BitsetCacheKey(IndexReader.CacheKey index, Query query) {
332-
this.index = index;
332+
private BitsetCacheKey(IndexReader.CacheKey indexKey, Query query) {
333+
this.indexKey = indexKey;
333334
this.query = query;
335+
// compute the hashCode eagerly, since it's used multiple times in the cache implementation anyway -- the query here will
336+
// be a ConstantScoreQuery around a BooleanQuery, and BooleanQuery already *lazily* caches the hashCode, so this isn't
337+
// altogether that much faster in reality, but it makes it more explicit here that we're doing this
338+
this.hashCode = computeHashCode();
334339
}
335340

336341
@Override
@@ -342,17 +347,23 @@ public boolean equals(Object other) {
342347
return false;
343348
}
344349
final BitsetCacheKey that = (BitsetCacheKey) other;
345-
return Objects.equals(this.index, that.index) && Objects.equals(this.query, that.query);
350+
return Objects.equals(this.indexKey, that.indexKey) && Objects.equals(this.query, that.query);
351+
}
352+
353+
private int computeHashCode() {
354+
int result = indexKey.hashCode();
355+
result = 31 * result + query.hashCode();
356+
return result;
346357
}
347358

348359
@Override
349360
public int hashCode() {
350-
return Objects.hash(index, query);
361+
return hashCode;
351362
}
352363

353364
@Override
354365
public String toString() {
355-
return getClass().getSimpleName() + "(" + index + "," + query + ")";
366+
return getClass().getSimpleName() + "(" + indexKey + "," + query + ")";
356367
}
357368
}
358369

@@ -362,15 +373,15 @@ public String toString() {
362373
*/
363374
void verifyInternalConsistency() {
364375
this.bitsetCache.keys().forEach(bck -> {
365-
final Set<BitsetCacheKey> set = this.keysByIndex.get(bck.index);
376+
final Set<BitsetCacheKey> set = this.keysByIndex.get(bck.indexKey);
366377
if (set == null) {
367378
throw new IllegalStateException(
368-
"Key [" + bck + "] is in the cache, but there is no entry for [" + bck.index + "] in the lookup map"
379+
"Key [" + bck + "] is in the cache, but there is no entry for [" + bck.indexKey + "] in the lookup map"
369380
);
370381
}
371382
if (set.contains(bck) == false) {
372383
throw new IllegalStateException(
373-
"Key [" + bck + "] is in the cache, but the lookup entry for [" + bck.index + "] does not contain that key"
384+
"Key [" + bck + "] is in the cache, but the lookup entry for [" + bck.indexKey + "] does not contain that key"
374385
);
375386
}
376387
});

0 commit comments

Comments
 (0)