fix access denied for shard deletion with WindowsFS

We randomly use the WindowsFS mock file system to simulate that
windows does not delete files if they are opened by some other
process and instead gives you java.io.IOException: access denied.
In the tests we also check if the shard was deleted while it is
being deleted. This check loads the mata data of the index
and therefore might hold on to a file while the node
is trying to delete it and deletion will fail then.

Instead we should just check if the directory was removed.

closes #13758
This commit is contained in:
Britta Weber 2015-10-13 18:02:44 +02:00
parent 077a401c28
commit f7693b694b
1 changed files with 41 additions and 35 deletions

View File

@ -19,7 +19,6 @@
package org.elasticsearch.gateway; package org.elasticsearch.gateway;
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse; import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse; import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.IndexMetaData;
@ -27,13 +26,16 @@ import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.routing.allocation.decider.FilterAllocationDecider; import org.elasticsearch.cluster.routing.allocation.decider.FilterAllocationDecider;
import org.elasticsearch.common.collect.ImmutableOpenMap; import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.NodeEnvironment;
import org.elasticsearch.index.Index;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.InternalTestCluster; import org.elasticsearch.test.InternalTestCluster;
import org.junit.Test; import org.junit.Test;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.concurrent.Future;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.test.ESIntegTestCase.Scope; import static org.elasticsearch.test.ESIntegTestCase.Scope;
@ -70,14 +72,14 @@ public class MetaDataWriteDataNodesIT extends ESIntegTestCase {
index(index, "doc", "1", jsonBuilder().startObject().field("text", "some text").endObject()); index(index, "doc", "1", jsonBuilder().startObject().field("text", "some text").endObject());
ensureGreen(); ensureGreen();
assertIndexInMetaState(node1, index); assertIndexInMetaState(node1, index);
assertIndexNotInMetaState(node2, index); assertIndexDirectoryDeleted(node2, index);
assertIndexInMetaState(masterNode, index); assertIndexInMetaState(masterNode, index);
logger.debug("relocating index..."); logger.debug("relocating index...");
client().admin().indices().prepareUpdateSettings(index).setSettings(Settings.builder().put(FilterAllocationDecider.INDEX_ROUTING_INCLUDE_GROUP + "_name", node2)).get(); client().admin().indices().prepareUpdateSettings(index).setSettings(Settings.builder().put(FilterAllocationDecider.INDEX_ROUTING_INCLUDE_GROUP + "_name", node2)).get();
client().admin().cluster().prepareHealth().setWaitForRelocatingShards(0).get(); client().admin().cluster().prepareHealth().setWaitForRelocatingShards(0).get();
ensureGreen(); ensureGreen();
assertIndexNotInMetaState(node1, index); assertIndexDirectoryDeleted(node1, index);
assertIndexInMetaState(node2, index); assertIndexInMetaState(node2, index);
assertIndexInMetaState(masterNode, index); assertIndexInMetaState(masterNode, index);
} }
@ -149,48 +151,52 @@ public class MetaDataWriteDataNodesIT extends ESIntegTestCase {
assertThat(indicesMetaData.get(index).state(), equalTo(IndexMetaData.State.OPEN)); assertThat(indicesMetaData.get(index).state(), equalTo(IndexMetaData.State.OPEN));
} }
protected void assertIndexNotInMetaState(String nodeName, String indexName) throws Exception { protected void assertIndexDirectoryDeleted(final String nodeName, final String indexName) throws Exception {
assertMetaState(nodeName, indexName, false); assertBusy(new Runnable() {
} @Override
public void run() {
protected void assertIndexInMetaState(String nodeName, String indexName) throws Exception {
assertMetaState(nodeName, indexName, true);
}
private void assertMetaState(final String nodeName, final String indexName, final boolean shouldBe) throws Exception {
awaitBusy(() -> {
logger.info("checking if meta state exists..."); logger.info("checking if meta state exists...");
try { try {
return shouldBe == metaStateExists(nodeName, indexName); assertFalse("Expecting index directory of " + indexName + " to be deleted from node " + nodeName, indexDirectoryExists(nodeName, indexName));
} catch (Throwable t) { } catch (Exception e) {
logger.info("failed to load meta state", t); logger.info("failed to check for data director of index {} on node {}", indexName, nodeName);
// TODO: loading of meta state fails rarely if the state is deleted while we try to load it fail("could not check if data directory still exists");
// this here is a hack, would be much better to use for example a WatchService
return false;
} }
});
boolean inMetaSate = metaStateExists(nodeName, indexName);
if (shouldBe) {
assertTrue("expected " + indexName + " in meta state of node " + nodeName, inMetaSate);
} else {
assertFalse("expected " + indexName + " to not be in meta state of node " + nodeName, inMetaSate);
} }
} }
);
}
private boolean metaStateExists(String nodeName, String indexName) throws Exception { protected void assertIndexInMetaState(final String nodeName, final String indexName) throws Exception {
ImmutableOpenMap<String, IndexMetaData> indices = getIndicesMetaDataOnNode(nodeName); assertBusy(new Runnable() {
boolean inMetaSate = false; @Override
for (ObjectObjectCursor<String, IndexMetaData> index : indices) { public void run() {
inMetaSate = inMetaSate || index.key.equals(indexName); logger.info("checking if meta state exists...");
try {
assertTrue("Expecting meta state of index " + indexName + " to be on node " + nodeName, getIndicesMetaDataOnNode(nodeName).containsKey(indexName));
} catch (Throwable t) {
logger.info("failed to load meta state", t);
fail("could not load meta state");
} }
return inMetaSate; }
}
);
}
private boolean indexDirectoryExists(String nodeName, String indexName) throws Exception {
NodeEnvironment nodeEnv = ((InternalTestCluster) cluster()).getInstance(NodeEnvironment.class, nodeName);
for (Path path : nodeEnv.indexPaths(new Index(indexName))) {
if (Files.exists(path)) {
return true;
}
}
return false;
} }
private ImmutableOpenMap<String, IndexMetaData> getIndicesMetaDataOnNode(String nodeName) throws Exception { private ImmutableOpenMap<String, IndexMetaData> getIndicesMetaDataOnNode(String nodeName) throws Exception {
GatewayMetaState nodeMetaState = ((InternalTestCluster) cluster()).getInstance(GatewayMetaState.class, nodeName); GatewayMetaState nodeMetaState = ((InternalTestCluster) cluster()).getInstance(GatewayMetaState.class, nodeName);
MetaData nodeMetaData = null; MetaData nodeMetaData = nodeMetaState.loadMetaState();
nodeMetaData = nodeMetaState.loadMetaState();
return nodeMetaData.getIndices(); return nodeMetaData.getIndices();
} }
} }