Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow indices to be closed without executing sanity checks #38609

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
"options" : ["open","closed","none","all"],
"default" : "open",
"description" : "Whether to expand wildcard expression to concrete indices that are open, closed or both."
},
"force": {
"type" : "boolean",
"description" : "Whether closing the index should be forced"
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,28 @@

- match: { acknowledged: true }
- match: { shards_acknowledged: true }

---
"Close index with force flag":
- skip:
version: " - 7.99.99"
reason: force parameter was added in 8.0.0
features: "warnings"

- do:
indices.create:
index: test_index
body:
settings:
number_of_replicas: 0

- do:
cluster.health:
wait_for_status: green

- do:
indices.close:
index: test_index
force: true
warnings:
- "parameter [force] is deprecated but was [true]"
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,22 @@
public class CloseIndexClusterStateUpdateRequest extends IndicesClusterStateUpdateRequest<CloseIndexClusterStateUpdateRequest> {

private final long taskId;
private final boolean force;

public CloseIndexClusterStateUpdateRequest(final long taskId) {
this(taskId, false);
}

public CloseIndexClusterStateUpdateRequest(final long taskId, final boolean force) {
this.taskId = taskId;
this.force = force;
}

public long taskId() {
return taskId;
}

public boolean force() {
return force;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

package org.elasticsearch.action.admin.indices.close;

import org.elasticsearch.Version;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.support.IndicesOptions;
Expand All @@ -38,6 +39,7 @@ public class CloseIndexRequest extends AcknowledgedRequest<CloseIndexRequest> im

private String[] indices;
private IndicesOptions indicesOptions = IndicesOptions.strictExpandOpen();
private boolean force = false;

public CloseIndexRequest() {
}
Expand Down Expand Up @@ -101,17 +103,38 @@ public CloseIndexRequest indicesOptions(IndicesOptions indicesOptions) {
return this;
}

/**
* Force the closing of indices without executing the pre-close sanity checks
*/
public boolean force() {
return force;
}

/**
* Force the closing of indices without executing the pre-close sanity checks
*/
public CloseIndexRequest force(final boolean force) {
this.force = force;
return this;
}

@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
indices = in.readStringArray();
indicesOptions = IndicesOptions.readIndicesOptions(in);
if (in.getVersion().onOrAfter(Version.V_8_0_0)) {
force = in.readBoolean();
}
}

@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeStringArray(indices);
indicesOptions.writeIndicesOptions(out);
if (out.getVersion().onOrAfter(Version.V_8_0_0)) {
out.writeBoolean(force);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,9 @@ public CloseIndexRequestBuilder setIndicesOptions(IndicesOptions indicesOptions)
request.indicesOptions(indicesOptions);
return this;
}

public CloseIndexRequestBuilder setForce(final boolean force) {
request.force(force);
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ protected void masterOperation(final Task task, final CloseIndexRequest request,
return;
}

final CloseIndexClusterStateUpdateRequest closeRequest = new CloseIndexClusterStateUpdateRequest(task.getId())
final CloseIndexClusterStateUpdateRequest closeRequest = new CloseIndexClusterStateUpdateRequest(task.getId(), request.force())
.ackTimeout(request.timeout())
.masterNodeTimeout(request.masterNodeTimeout())
.indices(concreteIndices);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,15 @@ public void closeIndices(final CloseIndexClusterStateUpdateRequest request, fina
throw new IllegalArgumentException("Index name is required");
}

final boolean forced = request.force();
clusterService.submitStateUpdateTask("add-block-index-to-close " + Arrays.toString(concreteIndices),
new ClusterStateUpdateTask(Priority.URGENT) {

private final Map<Index, ClusterBlock> blockedIndices = new HashMap<>();

@Override
public ClusterState execute(final ClusterState currentState) {
return addIndexClosedBlocks(concreteIndices, blockedIndices, currentState);
return addIndexClosedBlocks(concreteIndices, blockedIndices, currentState, forced);
}

@Override
Expand Down Expand Up @@ -199,8 +200,10 @@ public TimeValue timeout() {
* block (or reuses an existing one) to every index to close in the cluster state. After the cluster state is published, the shards
* should start to reject writing operations and we can proceed with step 2.
*/
static ClusterState addIndexClosedBlocks(final Index[] indices, final Map<Index, ClusterBlock> blockedIndices,
final ClusterState currentState) {
static ClusterState addIndexClosedBlocks(final Index[] indices,
final Map<Index, ClusterBlock> blockedIndices,
final ClusterState currentState,
final boolean forced) {
final MetaData.Builder metadata = MetaData.builder(currentState.metaData());

final Set<IndexMetaData> indicesToClose = new HashSet<>();
Expand All @@ -223,9 +226,9 @@ static ClusterState addIndexClosedBlocks(final Index[] indices, final Map<Index,
// Check if index closing conflicts with any running snapshots
SnapshotsService.checkIndexClosing(currentState, indicesToClose);

// If the cluster is in a mixed version that does not support the shard close action,
// If the close is forced or if the cluster is in a mixed version that does not support the shard close action,
// we use the previous way to close indices and directly close them without sanity checks
final boolean useDirectClose = currentState.nodes().getMinNodeVersion().before(Version.V_6_7_0);
final boolean useDirectClose = forced || currentState.nodes().getMinNodeVersion().before(Version.V_6_7_0);

final ClusterBlocks.Builder blocks = ClusterBlocks.builder().blocks(currentState.blocks());
final RoutingTable.Builder routingTable = RoutingTable.builder(currentState.routingTable());
Expand Down Expand Up @@ -401,6 +404,7 @@ static ClusterState closeRoutingTable(final ClusterState currentState,
if (indexMetaData.getState() == IndexMetaData.State.CLOSE) {
logger.debug("verification of shards before closing {} succeeded but index is already closed", index);
assert currentState.blocks().hasIndexBlock(index.getName(), INDEX_CLOSED_BLOCK);
closedIndices.add(index.getName());
continue;
}
final ClusterBlock closingBlock = blockedIndices.get(index);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@

package org.elasticsearch.rest.action.admin.indices;

import org.apache.logging.log4j.LogManager;
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Booleans;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController;
Expand All @@ -32,6 +35,9 @@
import java.io.IOException;

public class RestCloseIndexAction extends BaseRestHandler {

private static final DeprecationLogger deprecationLogger = new DeprecationLogger(LogManager.getLogger(RestCloseIndexAction.class));

public RestCloseIndexAction(Settings settings, RestController controller) {
super(settings);
controller.registerHandler(RestRequest.Method.POST, "/_close", this);
Expand All @@ -49,6 +55,20 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC
closeIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", closeIndexRequest.masterNodeTimeout()));
closeIndexRequest.timeout(request.paramAsTime("timeout", closeIndexRequest.timeout()));
closeIndexRequest.indicesOptions(IndicesOptions.fromRequest(request, closeIndexRequest.indicesOptions()));

final String forceParameter = request.param("force");
final boolean forced;
if (forceParameter == null) {
forced = closeIndexRequest.force();
} else {
deprecationLogger.deprecated("parameter [force] is deprecated but was [" + forceParameter + "]");
if (forceParameter.length() == 0) {
forced = true;
} else {
forced = Booleans.parseBoolean(forceParameter);
}
}
closeIndexRequest.force(forced);
return channel -> client.admin().indices().close(closeIndexRequest, new RestToXContentListener<>(channel));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public void testCloseRoutingTable() {
assertIsClosed(blockedIndex.getName(), updatedState);
} else {
assertIsOpened(blockedIndex.getName(), updatedState);
assertHasBlock(blockedIndex.getName(), updatedState, blockedIndices.get(blockedIndex));
assertThat(updatedState.blocks().hasIndexBlockWithId(blockedIndex.getName(), INDEX_CLOSED_BLOCK_ID), is(true));
}
}
Expand All @@ -120,14 +121,15 @@ public void testAddIndexClosedBlocks() {
final Map<Index, ClusterBlock> blockedIndices = new HashMap<>();
Index[] indices = new Index[]{new Index("_name", "_uid")};
expectThrows(IndexNotFoundException.class, () ->
MetaDataIndexStateService.addIndexClosedBlocks(indices, blockedIndices, initialState));
MetaDataIndexStateService.addIndexClosedBlocks(indices, blockedIndices, initialState, randomBoolean()));
assertTrue(blockedIndices.isEmpty());
}
{
final Map<Index, ClusterBlock> blockedIndices = new HashMap<>();
Index[] indices = Index.EMPTY_ARRAY;

ClusterState updatedState = MetaDataIndexStateService.addIndexClosedBlocks(indices, blockedIndices, initialState);
ClusterState updatedState =
MetaDataIndexStateService.addIndexClosedBlocks(indices, blockedIndices, initialState, randomBoolean());
assertSame(initialState, updatedState);
assertTrue(blockedIndices.isEmpty());
}
Expand All @@ -136,7 +138,7 @@ public void testAddIndexClosedBlocks() {
ClusterState state = addClosedIndex("closed", randomIntBetween(1, 3), randomIntBetween(0, 3), initialState);
Index[] indices = new Index[]{state.metaData().index("closed").getIndex()};

ClusterState updatedState = MetaDataIndexStateService.addIndexClosedBlocks(indices, blockedIndices, state);
ClusterState updatedState = MetaDataIndexStateService.addIndexClosedBlocks(indices, blockedIndices, state, randomBoolean());
assertSame(state, updatedState);
assertTrue(blockedIndices.isEmpty());

Expand All @@ -147,7 +149,7 @@ public void testAddIndexClosedBlocks() {
state = addOpenedIndex("opened", randomIntBetween(1, 3), randomIntBetween(0, 3), state);
Index[] indices = new Index[]{state.metaData().index("opened").getIndex(), state.metaData().index("closed").getIndex()};

ClusterState updatedState = MetaDataIndexStateService.addIndexClosedBlocks(indices, blockedIndices, state);
ClusterState updatedState = MetaDataIndexStateService.addIndexClosedBlocks(indices, blockedIndices, state, false);
assertNotSame(state, updatedState);

Index opened = updatedState.metaData().index("opened").getIndex();
Expand All @@ -167,7 +169,7 @@ public void testAddIndexClosedBlocks() {
state = addOpenedIndex("closed", randomIntBetween(1, 3), randomIntBetween(0, 3), state);
}
Index[] indices = new Index[]{state.metaData().index("restored").getIndex()};
MetaDataIndexStateService.addIndexClosedBlocks(indices, unmodifiableMap(emptyMap()), state);
MetaDataIndexStateService.addIndexClosedBlocks(indices, unmodifiableMap(emptyMap()), state, randomBoolean());
});
assertThat(exception.getMessage(), containsString("Cannot close indices that are being restored: [[restored]]"));
}
Expand All @@ -181,7 +183,7 @@ public void testAddIndexClosedBlocks() {
state = addOpenedIndex("closed", randomIntBetween(1, 3), randomIntBetween(0, 3), state);
}
Index[] indices = new Index[]{state.metaData().index("snapshotted").getIndex()};
MetaDataIndexStateService.addIndexClosedBlocks(indices, unmodifiableMap(emptyMap()), state);
MetaDataIndexStateService.addIndexClosedBlocks(indices, unmodifiableMap(emptyMap()), state, randomBoolean());
});
assertThat(exception.getMessage(), containsString("Cannot close indices that are being snapshotted: [[snapshotted]]"));
}
Expand All @@ -204,7 +206,7 @@ public void testAddIndexClosedBlocks() {
Index index3 = state.metaData().index("index-3").getIndex();
Index[] indices = new Index[]{index1, index2, index3};

ClusterState updatedState = MetaDataIndexStateService.addIndexClosedBlocks(indices, blockedIndices, state);
ClusterState updatedState = MetaDataIndexStateService.addIndexClosedBlocks(indices, blockedIndices, state, randomBoolean());
assertNotSame(state, updatedState);

for (Index index : indices) {
Expand All @@ -218,6 +220,41 @@ public void testAddIndexClosedBlocks() {
}
}

public void testAddIndexClosedBlocksWhenForced() {
final ClusterState initialState = ClusterState.builder(new ClusterName("testAddIndexClosedBlocksWhenForced")).build();

final int nbOpenedIndices = randomIntBetween(1, 5);
final Index[] indices = new Index[nbOpenedIndices + 1];

ClusterState state = initialState;
for (int i = 0; i < nbOpenedIndices; i++) {
final String indexName = "opened-" + i;
state = addOpenedIndex(indexName, randomIntBetween(1, 3), randomIntBetween(0, 3), state);
indices[i] = state.metaData().index(indexName).getIndex();
}

state = addClosedIndex("closed", randomIntBetween(1, 3), randomIntBetween(0, 3), state);
indices[nbOpenedIndices] = state.metaData().index("closed").getIndex();
state = addOpenedIndex("other", randomIntBetween(1, 3), randomIntBetween(0, 3), state);

final Map<Index, ClusterBlock> blockedIndices = new HashMap<>();
final ClusterState updatedState = MetaDataIndexStateService.addIndexClosedBlocks(indices, blockedIndices, state, true);
assertNotSame(state, updatedState);

assertFalse(blockedIndices.containsKey(updatedState.metaData().index("closed").getIndex()));
assertIsClosed("closed", updatedState);

assertFalse(blockedIndices.containsKey(updatedState.metaData().index("other").getIndex()));
assertIsOpened("other", updatedState);
assertNoBlock("other", updatedState);

for (int i = 0; i < nbOpenedIndices; i++) {
final String indexName = "opened-" + i;
assertTrue(blockedIndices.containsKey(updatedState.metaData().index(indexName).getIndex()));
assertIsClosed(indexName, updatedState); // forced close directly closes indices
}
}

public void testAddIndexClosedBlocksReusesBlocks() {
ClusterState state = ClusterState.builder(new ClusterName("testAddIndexClosedBlocksReuseBlocks")).build();
state = addOpenedIndex("test", randomIntBetween(1, 3), randomIntBetween(0, 3), state);
Expand All @@ -226,13 +263,13 @@ public void testAddIndexClosedBlocksReusesBlocks() {
Index[] indices = new Index[]{test};

final Map<Index, ClusterBlock> blockedIndices = new HashMap<>();
state = MetaDataIndexStateService.addIndexClosedBlocks(indices, blockedIndices, state);
state = MetaDataIndexStateService.addIndexClosedBlocks(indices, blockedIndices, state, false);

assertTrue(blockedIndices.containsKey(test));
assertHasBlock(test.getName(), state, blockedIndices.get(test));

final Map<Index, ClusterBlock> blockedIndices2 = new HashMap<>();
state = MetaDataIndexStateService.addIndexClosedBlocks(indices, blockedIndices2, state);
state = MetaDataIndexStateService.addIndexClosedBlocks(indices, blockedIndices2, state, false);

assertTrue(blockedIndices2.containsKey(test));
assertHasBlock(test.getName(), state, blockedIndices2.get(test));
Expand Down Expand Up @@ -385,4 +422,11 @@ private static void assertHasBlock(final String indexName, final ClusterState cl
clusterState.blocks().indices().getOrDefault(indexName, emptySet()).stream()
.filter(clusterBlock -> clusterBlock.id() == MetaDataIndexStateService.INDEX_CLOSED_BLOCK_ID).count(), equalTo(1L));
}

private static void assertNoBlock(final String indexName, final ClusterState clusterState) {
assertThat(clusterState.blocks().hasIndexBlock(indexName, INDEX_CLOSED_BLOCK), is(false));
assertThat("Index " + indexName + " must not have a block with [id=" + MetaDataIndexStateService.INDEX_CLOSED_BLOCK_ID + "]",
clusterState.blocks().indices().getOrDefault(indexName, emptySet()).stream()
.filter(clusterBlock -> clusterBlock.id() == MetaDataIndexStateService.INDEX_CLOSED_BLOCK_ID).count(), equalTo(0L));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@ private MetaDataIndexStateServiceUtils(){
}

/**
* Allows to call {@link MetaDataIndexStateService#addIndexClosedBlocks(Index[], Map, ClusterState)} which is a protected method.
* Allows to call {@link MetaDataIndexStateService#addIndexClosedBlocks(Index[], Map, ClusterState, boolean)}
* which is a protected method.
*/
public static ClusterState addIndexClosedBlocks(final Index[] indices, final Map<Index, ClusterBlock> blockedIndices,
final ClusterState state) {
return MetaDataIndexStateService.addIndexClosedBlocks(indices, blockedIndices, state);
public static ClusterState addIndexClosedBlocks(final Index[] indices,
final Map<Index, ClusterBlock> blockedIndices,
final ClusterState state,
final boolean forced) {
return MetaDataIndexStateService.addIndexClosedBlocks(indices, blockedIndices, state, forced);
}

/**
Expand Down
Loading