Skip to content

Commit 2ba6aed

Browse files
committed
Optimize index lookup for single default project case
We can avoid using the volatile field when there is only a single default project. Relates: elastic#123662
1 parent 9a37fbf commit 2ba6aed

File tree

2 files changed

+19
-45
lines changed

2 files changed

+19
-45
lines changed

server/src/main/java/org/elasticsearch/cluster/metadata/Metadata.java

Lines changed: 15 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1848,6 +1848,10 @@ public Metadata fromXContent(XContentParser parser) throws IOException {
18481848
* Attempt to find a project for the supplied {@link Index}.
18491849
*/
18501850
public Optional<ProjectMetadata> lookupProject(Index index) {
1851+
if (isSingleProject()) {
1852+
final var project = projectMetadata.get(DEFAULT_PROJECT_ID);
1853+
return project.hasIndex(index) ? Optional.of(project) : Optional.empty();
1854+
}
18511855
return getProjectLookup().project(index);
18521856
}
18531857

@@ -1866,6 +1870,9 @@ public ProjectMetadata projectFor(Index index) {
18661870
* @throws org.elasticsearch.index.IndexNotFoundException if the index does not exist in any project
18671871
*/
18681872
public IndexMetadata indexMetadata(Index index) {
1873+
if (isSingleProject()) {
1874+
return projectMetadata.get(DEFAULT_PROJECT_ID).getIndexSafe(index);
1875+
}
18691876
return projectFor(index).getIndexSafe(index);
18701877
}
18711878

@@ -1874,6 +1881,9 @@ public IndexMetadata indexMetadata(Index index) {
18741881
* throwing when either the project or the index is not found.
18751882
*/
18761883
public Optional<IndexMetadata> findIndex(Index index) {
1884+
if (isSingleProject()) {
1885+
return Optional.ofNullable(projectMetadata.get(DEFAULT_PROJECT_ID).index(index));
1886+
}
18771887
return lookupProject(index).map(projectMetadata -> projectMetadata.index(index));
18781888
}
18791889

@@ -1883,56 +1893,24 @@ ProjectLookup getProjectLookup() {
18831893
* That means it is possible that we will generate multiple lookup objects if there are multiple concurrent callers
18841894
* Those lookup objects will be identical, and the double assignment will be safe, but there is the cost of building the lookup
18851895
* more than once.
1886-
* In the single project case building the lookup is cheap, and synchronization would be costly.
1896+
* The single default project case has special handling and does not go through the project lookup.
18871897
* In the multiple project case, it might be cheaper to synchronize, but the long term solution is to maintain the lookup table
18881898
* as projects/indices are added/removed rather than rebuild it each time the cluster-state/metadata object changes.
18891899
*/
18901900
if (this.projectLookup == null) {
1891-
if (this.isSingleProject()) {
1892-
projectLookup = new SingleProjectLookup(getSingleProject());
1893-
} else {
1894-
projectLookup = new MultiProjectLookup();
1895-
}
1901+
assert isSingleProject() == false;
1902+
projectLookup = new ProjectLookup();
18961903
}
18971904
return projectLookup;
18981905
}
18991906

19001907
/**
19011908
* A lookup table from {@link Index} to {@link ProjectId}
19021909
*/
1903-
interface ProjectLookup {
1904-
/**
1905-
* Return the {@link ProjectId} for the provided {@link Index}, if it exists
1906-
*/
1907-
Optional<ProjectMetadata> project(Index index);
1908-
}
1909-
1910-
/**
1911-
* An implementation of {@link ProjectLookup} that is optimized for the case where there is a single project.
1912-
*
1913-
*/
1914-
static class SingleProjectLookup implements ProjectLookup {
1915-
1916-
private final ProjectMetadata project;
1917-
1918-
SingleProjectLookup(ProjectMetadata project) {
1919-
this.project = project;
1920-
}
1921-
1922-
@Override
1923-
public Optional<ProjectMetadata> project(Index index) {
1924-
if (project.hasIndex(index)) {
1925-
return Optional.of(project);
1926-
} else {
1927-
return Optional.empty();
1928-
}
1929-
}
1930-
}
1931-
1932-
class MultiProjectLookup implements ProjectLookup {
1910+
class ProjectLookup {
19331911
private final Map<String, ProjectMetadata> lookup;
19341912

1935-
private MultiProjectLookup() {
1913+
private ProjectLookup() {
19361914
this.lookup = Maps.newMapWithExpectedSize(Metadata.this.getTotalNumberOfIndices());
19371915
for (var project : projectMetadata.values()) {
19381916
for (var indexMetadata : project) {
@@ -1947,7 +1925,6 @@ private MultiProjectLookup() {
19471925
}
19481926
}
19491927

1950-
@Override
19511928
public Optional<ProjectMetadata> project(Index index) {
19521929
final ProjectMetadata project = lookup.get(index.getUUID());
19531930
if (project != null && project.hasIndex(index)) {

server/src/test/java/org/elasticsearch/cluster/metadata/MetadataTests.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@
7676
import org.elasticsearch.xcontent.XContentParserConfiguration;
7777
import org.elasticsearch.xcontent.XContentType;
7878
import org.elasticsearch.xcontent.json.JsonXContent;
79-
import org.hamcrest.Matchers;
8079

8180
import java.io.IOException;
8281
import java.lang.reflect.Field;
@@ -3037,17 +3036,16 @@ public void testProjectLookupWithSingleProject() {
30373036
projectBuilder.put(indexMetadata, false);
30383037
}
30393038

3040-
final Metadata.ProjectLookup lookup = Metadata.builder().put(projectBuilder).build().getProjectLookup();
3041-
assertThat(lookup, Matchers.instanceOf(Metadata.SingleProjectLookup.class));
3039+
final Metadata lookup = Metadata.builder().put(projectBuilder).build();
30423040
indices.forEach(im -> {
30433041
final Index index = im.getIndex();
3044-
assertThat(lookup.project(index).map(ProjectMetadata::id), isPresentWith(projectId));
3042+
assertThat(lookup.lookupProject(index).map(ProjectMetadata::id), isPresentWith(projectId));
30453043

30463044
Index alt1 = new Index(index.getName(), randomValueOtherThan(im.getIndexUUID(), ESTestCase::randomUUID));
3047-
assertThat(lookup.project(alt1), isEmpty());
3045+
assertThat(lookup.lookupProject(alt1), isEmpty());
30483046

30493047
Index alt2 = new Index(randomAlphaOfLength(8), im.getIndexUUID());
3050-
assertThat(lookup.project(alt2), isEmpty());
3048+
assertThat(lookup.lookupProject(alt2), isEmpty());
30513049
});
30523050
}
30533051

@@ -3076,7 +3074,6 @@ public void testProjectLookupWithMultipleProjects() {
30763074
}
30773075

30783076
final Metadata.ProjectLookup lookup = metadataBuilder.build().getProjectLookup();
3079-
assertThat(lookup, Matchers.instanceOf(Metadata.MultiProjectLookup.class));
30803077

30813078
indices.forEach((project, ix) -> ix.forEach(im -> {
30823079
final Index index = im.getIndex();

0 commit comments

Comments
 (0)