Skip to content

Commit faa5d51

Browse files
committed
Adjust unpromotable shard refresh request validation to allow RefreshResult.NO_REFRESH
When a primary shard uses the read-only engine, it always returns a RefreshResult.NO_REFRESH for refreshes. Since elastic#93600 we added an extra roundtrip to hook unpromotable shard refresh logic. This hook is always executed, even if there are no unpromotable shards, but the UnpromotableShardRefreshRequest would fail if the primary shard returns a RefreshResult.NO_REFRESH result. Closes elastic#129036
1 parent a859f37 commit faa5d51

File tree

6 files changed

+71
-11
lines changed

6 files changed

+71
-11
lines changed

server/src/main/java/org/elasticsearch/action/admin/indices/refresh/TransportShardRefreshAction.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import org.elasticsearch.cluster.service.ClusterService;
2424
import org.elasticsearch.common.io.stream.StreamInput;
2525
import org.elasticsearch.common.settings.Settings;
26-
import org.elasticsearch.index.engine.Engine;
2726
import org.elasticsearch.index.shard.IndexShard;
2827
import org.elasticsearch.indices.IndicesService;
2928
import org.elasticsearch.injection.guice.Inject;
@@ -127,10 +126,7 @@ public void onPrimaryOperationComplete(
127126
ActionListener<Void> listener
128127
) {
129128
var primaryTerm = replicaRequest.primaryRefreshResult.primaryTerm();
130-
assert Engine.UNKNOWN_PRIMARY_TERM < primaryTerm : primaryTerm;
131-
132129
var generation = replicaRequest.primaryRefreshResult.generation();
133-
assert Engine.RefreshResult.UNKNOWN_GENERATION < generation : generation;
134130

135131
transportService.sendRequest(
136132
transportService.getLocalNode(),

server/src/main/java/org/elasticsearch/action/admin/indices/refresh/TransportUnpromotableShardRefreshAction.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.elasticsearch.cluster.service.ClusterService;
2323
import org.elasticsearch.common.io.stream.StreamInput;
2424
import org.elasticsearch.core.TimeValue;
25+
import org.elasticsearch.index.engine.Engine;
2526
import org.elasticsearch.indices.IndicesService;
2627
import org.elasticsearch.injection.guice.Inject;
2728
import org.elasticsearch.node.NodeClosedException;
@@ -154,12 +155,13 @@ protected void unpromotableShardOperation(
154155
return;
155156
}
156157

158+
var primaryTerm = request.getPrimaryTerm();
159+
assert Engine.UNKNOWN_PRIMARY_TERM < primaryTerm : primaryTerm;
160+
var segmentGeneration = request.getSegmentGeneration();
161+
assert Engine.RefreshResult.UNKNOWN_GENERATION < segmentGeneration : segmentGeneration;
162+
157163
ActionListener.run(responseListener, listener -> {
158-
shard.waitForPrimaryTermAndGeneration(
159-
request.getPrimaryTerm(),
160-
request.getSegmentGeneration(),
161-
listener.map(l -> ActionResponse.Empty.INSTANCE)
162-
);
164+
shard.waitForPrimaryTermAndGeneration(primaryTerm, segmentGeneration, listener.map(l -> ActionResponse.Empty.INSTANCE));
163165
});
164166
}
165167

server/src/main/java/org/elasticsearch/action/admin/indices/refresh/UnpromotableShardRefreshRequest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ public UnpromotableShardRefreshRequest(StreamInput in) throws IOException {
6363
@Override
6464
public ActionRequestValidationException validate() {
6565
ActionRequestValidationException validationException = super.validate();
66-
if (segmentGeneration == Engine.RefreshResult.UNKNOWN_GENERATION) {
66+
if (segmentGeneration == Engine.RefreshResult.UNKNOWN_GENERATION && primaryTerm == Engine.UNKNOWN_PRIMARY_TERM) {
67+
// read-only primary shards (like searchable snapshot shard) return Engine.RefreshResult.NO_REFRESH during refresh
68+
} else if (segmentGeneration == Engine.RefreshResult.UNKNOWN_GENERATION) {
6769
validationException = addValidationError("segment generation is unknown", validationException);
6870
}
6971
return validationException;

server/src/main/java/org/elasticsearch/index/engine/ReadOnlyEngine.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ public RefreshResult refresh(String source) {
446446

447447
@Override
448448
public void maybeRefresh(String source, ActionListener<RefreshResult> listener) throws EngineException {
449-
listener.onResponse(RefreshResult.NO_REFRESH);
449+
ActionListener.completeWith(listener, () -> refresh(source));
450450
}
451451

452452
@Override

x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/FrozenSearchableSnapshotsIntegTests.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
import static org.elasticsearch.search.aggregations.AggregationBuilders.dateHistogram;
6868
import static org.elasticsearch.snapshots.SearchableSnapshotsSettings.SEARCHABLE_SNAPSHOT_STORE_TYPE;
6969
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
70+
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
7071
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailuresAndResponse;
7172
import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_RECOVERY_STATE_FACTORY_KEY;
7273
import static org.hamcrest.Matchers.containsString;
@@ -521,6 +522,34 @@ public void testRequestCacheOnFrozen() throws Exception {
521522
}
522523
}
523524

525+
public void testRefreshPartiallyMountedIndex() throws Exception {
526+
final var index = "index";
527+
createIndex(index, 1, 0);
528+
populateIndex(index, 1_000);
529+
530+
final var repository = "repository";
531+
createRepository(repository, FsRepository.TYPE, Settings.builder().put("location", randomRepoPath()));
532+
533+
final var snapshot = "repository";
534+
createFullSnapshot(repository, snapshot);
535+
assertAcked(indicesAdmin().prepareDelete(index));
536+
537+
final var partialIndex = "partial-" + index;
538+
mountSnapshot(
539+
repository,
540+
snapshot,
541+
index,
542+
partialIndex,
543+
Settings.builder().put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, randomInt(1)).build(),
544+
MountSearchableSnapshotRequest.Storage.SHARED_CACHE
545+
);
546+
ensureGreen(partialIndex);
547+
548+
// before the fix this would have failed
549+
var refreshResult = indicesAdmin().prepareRefresh(partialIndex).execute().actionGet();
550+
assertNoFailures(refreshResult);
551+
}
552+
524553
public void testTierPreferenceCannotBeRemovedForFrozenIndex() throws Exception {
525554
final String fsRepoName = randomAlphaOfLength(10);
526555
final String indexName = randomAlphaOfLength(10).toLowerCase(Locale.ROOT);

x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsIntegTests.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import org.elasticsearch.index.shard.IndexLongFieldRange;
5252
import org.elasticsearch.indices.IndicesService;
5353
import org.elasticsearch.repositories.RepositoryData;
54+
import org.elasticsearch.repositories.fs.FsRepository;
5455
import org.elasticsearch.rest.RestStatus;
5556
import org.elasticsearch.search.SearchResponseUtils;
5657
import org.elasticsearch.snapshots.SnapshotId;
@@ -89,6 +90,7 @@
8990
import static org.elasticsearch.snapshots.SearchableSnapshotsSettings.SEARCHABLE_SNAPSHOT_STORE_TYPE;
9091
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
9192
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
93+
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
9294
import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_RECOVERY_STATE_FACTORY_KEY;
9395
import static org.hamcrest.Matchers.allOf;
9496
import static org.hamcrest.Matchers.containsString;
@@ -1280,6 +1282,35 @@ public void onFailure(Exception e) {
12801282
}
12811283
}
12821284

1285+
public void testRefreshFullyMountedIndex() throws Exception {
1286+
final var index = "index";
1287+
createIndex(index, 1, 0);
1288+
populateIndex(index, 1_000);
1289+
1290+
final var repository = "repository";
1291+
createRepository(repository, FsRepository.TYPE, Settings.builder().put("location", randomRepoPath()));
1292+
1293+
final var snapshot = "repository";
1294+
createFullSnapshot(repository, snapshot);
1295+
assertAcked(indicesAdmin().prepareDelete(index));
1296+
1297+
final var fullIndex = "full-" + index;
1298+
mountSnapshot(
1299+
repository,
1300+
snapshot,
1301+
index,
1302+
fullIndex,
1303+
Settings.builder().put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, randomInt(1)).build(),
1304+
MountSearchableSnapshotRequest.Storage.FULL_COPY
1305+
);
1306+
ensureGreen(fullIndex);
1307+
1308+
// before the fix this would have failed
1309+
var refreshResult = indicesAdmin().prepareRefresh(fullIndex).execute().actionGet();
1310+
assertNoFailures(refreshResult);
1311+
}
1312+
1313+
12831314
private TaskInfo getTaskForActionFromMaster(String action) {
12841315
ListTasksResponse response = client().execute(
12851316
TransportListTasksAction.TYPE,

0 commit comments

Comments
 (0)