diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/accesscontrol/DocumentSubsetBitsetCache.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/accesscontrol/DocumentSubsetBitsetCache.java index 1177ff68c34c4..18c13860efd6a 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/accesscontrol/DocumentSubsetBitsetCache.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/accesscontrol/DocumentSubsetBitsetCache.java @@ -55,32 +55,34 @@ /** * This is a cache for {@link BitSet} instances that are used with the {@link DocumentSubsetReader}. * It is bounded by memory size and access time. - * + *
* DLS uses {@link BitSet} instances to track which documents should be visible to the user ("live") and which should not ("dead"). * This means that there is a bit for each document in a Lucene index (ES shard). * Consequently, an index with 10 million document will use more than 1Mb of bitset memory for every unique DLS query, and an index * with 1 billion documents will use more than 100Mb of memory per DLS query. * Because DLS supports templating queries based on user metadata, there may be many distinct queries in use for each index, even if * there is only a single active role. - * + *
* The primary benefit of the cache is to avoid recalculating the "live docs" (visible documents) when a user performs multiple * consecutive queries across one or more large indices. Given the memory examples above, the cache is only useful if it can hold at * least 1 large (100Mb or more ) {@code BitSet} during a user's active session, and ideally should be capable of support multiple * simultaneous users with distinct DLS queries. - * + *
* For this reason the default memory usage (weight) for the cache set to 10% of JVM heap ({@link #CACHE_SIZE_SETTING}), so that it * automatically scales with the size of the Elasticsearch deployment, and can provide benefit to most use cases without needing * customisation. On a 32Gb heap, a 10% cache would be 3.2Gb which is large enough to store BitSets representing 25 billion docs. - * + *
* However, because queries can be templated by user metadata and that metadata can change frequently, it is common for the
- * effetively lifetime of a single DLS query to be relatively short. We do not want to sacrifice 10% of heap to a cache that is storing
- * BitSets that are not longer needed, so we set the TTL on this cache to be 2 hours ({@link #CACHE_TTL_SETTING}). This time has been
+ * effective lifetime of a single DLS query to be relatively short. We do not want to sacrifice 10% of heap to a cache that is storing
+ * BitSets that are no longer needed, so we set the TTL on this cache to be 2 hours ({@link #CACHE_TTL_SETTING}). This time has been
* chosen so that it will retain BitSets that are in active use during a user's session, but not be an ongoing drain on memory.
*
* @see org.elasticsearch.index.cache.bitset.BitsetFilterCache
*/
public final class DocumentSubsetBitsetCache implements IndexReader.ClosedListener, Closeable, Accountable {
+ private static final Logger logger = LogManager.getLogger(DocumentSubsetBitsetCache.class);
+
/**
* The TTL defaults to 2 hours. We default to a large cache size ({@link #CACHE_SIZE_SETTING}), and aggressively
* expire unused entries so that the cache does not hold on to memory unnecessarily.
@@ -102,8 +104,6 @@ public final class DocumentSubsetBitsetCache implements IndexReader.ClosedListen
private static final BitSet NULL_MARKER = new FixedBitSet(0);
- private static final Logger logger = LogManager.getLogger(DocumentSubsetBitsetCache.class);
-
/**
* When a {@link BitSet} is evicted from {@link #bitsetCache}, we need to also remove it from {@link #keysByIndex}.
* We use a {@link ReentrantReadWriteLock} to control atomicity here - the "read" side represents potential insertions to the
@@ -130,7 +130,8 @@ public DocumentSubsetBitsetCache(Settings settings, ThreadPool threadPool) {
* @param cleanupExecutor An executor on which the cache cleanup tasks can be run. Due to the way the cache is structured internally,
* it is sometimes necessary to run an asynchronous task to synchronize the internal state.
*/
- protected DocumentSubsetBitsetCache(Settings settings, ExecutorService cleanupExecutor) {
+ // visible for testing
+ DocumentSubsetBitsetCache(Settings settings, ExecutorService cleanupExecutor) {
final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
this.cacheEvictionLock = new ReleasableLock(readWriteLock.writeLock());
this.cacheModificationLock = new ReleasableLock(readWriteLock.readLock());
@@ -171,7 +172,7 @@ private void onCacheEviction(RemovalNotificationnull liveDocs then that would mean that no docs are marked as deleted,
- // but that isn't the case. No docs match with the role query and therefore all docs are marked as deleted
+ // If we were to return a null liveDocs then that would mean that no docs are marked as deleted,
+ // but that isn't the case. No docs match with the role query and therefore all docs are marked as deleted.
return new Bits.MatchNoBits(in.maxDoc());
} else if (roleQueryBits instanceof MatchAllBitSet) {
return actualLiveDocs;
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/DocumentPermissions.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/DocumentPermissions.java
index 92bb037888495..bf9e73e4518ac 100644
--- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/DocumentPermissions.java
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/DocumentPermissions.java
@@ -106,7 +106,7 @@ public boolean hasStoredScript() throws IOException {
/**
* Creates a {@link BooleanQuery} to be used as filter to restrict access to documents.
- * Document permission queries are used to create an boolean query.
+ * Document permission queries are used to create a boolean query.
* If the document permissions are limited, then there is an additional filter added restricting access to documents only allowed by the
* limited queries.
*
diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/accesscontrol/DocumentSubsetBitsetCacheTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/accesscontrol/DocumentSubsetBitsetCacheTests.java
index 5369c95ad6fa7..0645ea8b43b16 100644
--- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/accesscontrol/DocumentSubsetBitsetCacheTests.java
+++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/accesscontrol/DocumentSubsetBitsetCacheTests.java
@@ -54,6 +54,7 @@
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
@@ -62,8 +63,6 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
-import static java.util.Collections.emptyList;
-import static java.util.Collections.emptyMap;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
@@ -525,26 +524,13 @@ private void runTestOnIndex(CheckedBiConsumer true,
null,
- emptyMap(),
+ Map.of(),
MapperMetrics.NOOP
);
SearchExecutionContext searchExecutionContext = spy(realSearchExecutionContext);
@@ -154,7 +151,7 @@ public void testDLS() throws Exception {
if (doc % 11 == 0) {
iw.deleteDocuments(new Term("id", id));
} else {
- if (commitAfter % commitAfter == 0) {
+ if (doc % commitAfter == 0) {
iw.commit();
}
valuesHitCount[valueIndex]++;
@@ -172,7 +169,7 @@ public void testDLS() throws Exception {
String termQuery = "{\"term\": {\"field\": \"" + values[i] + "\"} }";
IndicesAccessControl.IndexAccessControl indexAccessControl = new IndicesAccessControl.IndexAccessControl(
FieldPermissions.DEFAULT,
- DocumentPermissions.filteredBy(singleton(new BytesArray(termQuery)))
+ DocumentPermissions.filteredBy(Set.of(new BytesArray(termQuery)))
);
SecurityIndexReaderWrapper wrapper = new SecurityIndexReaderWrapper(
s -> searchExecutionContext,
@@ -184,7 +181,7 @@ public void testDLS() throws Exception {
@Override
protected IndicesAccessControl getIndicesAccessControl() {
- return new IndicesAccessControl(true, singletonMap("_index", indexAccessControl));
+ return new IndicesAccessControl(true, Map.of("_index", indexAccessControl));
}
};
@@ -237,9 +234,9 @@ public void testDLSWithLimitedPermissions() throws Exception {
FieldPermissions.DEFAULT,
DocumentPermissions.filteredBy(queries)
);
- queries = singleton(new BytesArray("{\"terms\" : { \"f1\" : [\"fv11\", \"fv21\", \"fv31\"] } }"));
+ queries = Set.of(new BytesArray("{\"terms\" : { \"f1\" : [\"fv11\", \"fv21\", \"fv31\"] } }"));
if (restrictiveLimitedIndexPermissions) {
- queries = singleton(new BytesArray("{\"terms\" : { \"f1\" : [\"fv11\", \"fv31\"] } }"));
+ queries = Set.of(new BytesArray("{\"terms\" : { \"f1\" : [\"fv11\", \"fv31\"] } }"));
}
IndicesAccessControl.IndexAccessControl limitedIndexAccessControl = new IndicesAccessControl.IndexAccessControl(
FieldPermissions.DEFAULT,
@@ -271,7 +268,7 @@ public void testDLSWithLimitedPermissions() throws Exception {
null,
() -> true,
null,
- emptyMap(),
+ Map.of(),
MapperMetrics.NOOP
);
SearchExecutionContext searchExecutionContext = spy(realSearchExecutionContext);
@@ -289,13 +286,13 @@ public void testDLSWithLimitedPermissions() throws Exception {
@Override
protected IndicesAccessControl getIndicesAccessControl() {
- IndicesAccessControl indicesAccessControl = new IndicesAccessControl(true, singletonMap("_index", indexAccessControl));
+ IndicesAccessControl indicesAccessControl = new IndicesAccessControl(true, Map.of("_index", indexAccessControl));
if (noFilteredIndexPermissions) {
return indicesAccessControl;
}
IndicesAccessControl limitedByIndicesAccessControl = new IndicesAccessControl(
true,
- singletonMap("_index", limitedIndexAccessControl)
+ Map.of("_index", limitedIndexAccessControl)
);
return indicesAccessControl.limitIndicesAccessControl(limitedByIndicesAccessControl);
}
@@ -492,11 +489,7 @@ public void testDLSWithNestedDocs() throws Exception {
@Override
protected IndicesAccessControl getIndicesAccessControl() {
- IndicesAccessControl indicesAccessControl = new IndicesAccessControl(
- true,
- singletonMap(indexSettings().getIndex().getName(), indexAccessControl)
- );
- return indicesAccessControl;
+ return new IndicesAccessControl(true, Map.of(indexSettings().getIndex().getName(), indexAccessControl));
}
};
@@ -522,6 +515,6 @@ protected IndicesAccessControl getIndicesAccessControl() {
private static MappingLookup createMappingLookup(List