Skip to content

Commit

Permalink
Warn when searching a frozen index. (elastic#78184)
Browse files Browse the repository at this point in the history
The coordinating node should warn when a search request
is targeting a frozen index.

Relates to elastic#70192
  • Loading branch information
martijnvg authored Sep 27, 2021
1 parent b20939f commit 272c55e
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.block.ClusterBlockException;
import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.metadata.IndexMetadata;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodes;
Expand All @@ -33,6 +34,8 @@
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.logging.DeprecationCategory;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.util.concurrent.AtomicArray;
Expand Down Expand Up @@ -92,6 +95,10 @@

public class TransportSearchAction extends HandledTransportAction<SearchRequest, SearchResponse> {

private static final DeprecationLogger DEPRECATION_LOGGER = DeprecationLogger.getLogger(TransportSearchAction.class);
public static final String FROZEN_INDICES_DEPRECATION_MESSAGE = "Searching frozen indices [{}] is deprecated." +
" Consider cold or frozen tiers in place of frozen indices. The frozen feature will be removed in a feature release.";

/** The maximum number of shards for a single search request. */
public static final Setting<Long> SHARD_COUNT_LIMIT_SETTING = Setting.longSetting(
"action.search.shard_count.limit", Long.MAX_VALUE, 1L, Property.Dynamic, Property.NodeScope);
Expand Down Expand Up @@ -592,7 +599,23 @@ private Index[] resolveLocalIndices(OriginalIndices localIndices,
if (localIndices == null) {
return Index.EMPTY_ARRAY; //don't search on any local index (happens when only remote indices were specified)
}
return indexNameExpressionResolver.concreteIndices(clusterState, localIndices, timeProvider.getAbsoluteStartMillis());

List<String> frozenIndices = null;
Index[] indices = indexNameExpressionResolver.concreteIndices(clusterState, localIndices, timeProvider.getAbsoluteStartMillis());
for (Index index : indices) {
IndexMetadata indexMetadata = clusterState.metadata().index(index);
if (indexMetadata.getSettings().getAsBoolean("index.frozen", false)) {
if (frozenIndices == null) {
frozenIndices = new ArrayList<>();
}
frozenIndices.add(index.getName());
}
}
if (frozenIndices != null) {
DEPRECATION_LOGGER.critical(DeprecationCategory.INDICES, "search-frozen-indices", FROZEN_INDICES_DEPRECATION_MESSAGE,
String.join(",", frozenIndices));
}
return indices;
}

private void executeSearch(SearchTask task, SearchTimeProvider timeProvider, SearchRequest searchRequest,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.action.search.SearchShardTask;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.search.TransportSearchAction;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.action.support.WriteRequest;
Expand Down Expand Up @@ -917,16 +918,18 @@ public void testExpandSearchThrottled() {
}

public void testExpandSearchFrozen() {
createIndex("frozen_index");
String indexName = "frozen_index";
createIndex(indexName);
client().execute(
InternalOrPrivateSettingsPlugin.UpdateInternalOrPrivateAction.INSTANCE,
new InternalOrPrivateSettingsPlugin.UpdateInternalOrPrivateAction.Request("frozen_index",
new InternalOrPrivateSettingsPlugin.UpdateInternalOrPrivateAction.Request(indexName,
"index.frozen", "true"))
.actionGet();

client().prepareIndex("frozen_index").setId("1").setSource("field", "value").setRefreshPolicy(IMMEDIATE).get();
client().prepareIndex(indexName).setId("1").setSource("field", "value").setRefreshPolicy(IMMEDIATE).get();
assertHitCount(client().prepareSearch().get(), 0L);
assertHitCount(client().prepareSearch().setIndicesOptions(IndicesOptions.STRICT_EXPAND_OPEN_FORBID_CLOSED).get(), 1L);
assertWarnings(TransportSearchAction.FROZEN_INDICES_DEPRECATION_MESSAGE.replace("{}", indexName));
}

public void testCreateReduceContext() {
Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ tasks.named("yamlRestTestV7CompatTransform").configure({ task ->
})
tasks.named("yamlRestTestV7CompatTest").configure {
systemProperty 'tests.rest.blacklist', [
// UNMUTE after #78184 is backported to 7.x
'indices.freeze/10_basic/Basic',
'indices.freeze/10_basic/Test index options',
// to support it, it would require to almost revert back the #48725 and complicate the code
'vectors/10_dense_vector_basic/Deprecated function signature',
// not going to be supported
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.search.TransportSearchAction;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.cluster.block.ClusterBlockException;
Expand Down Expand Up @@ -92,17 +93,18 @@ String openReaders(TimeValue keepAlive, String... indices) {
}

public void testCloseFreezeAndOpen() throws Exception {
createIndex("index", Settings.builder().put("index.number_of_shards", 2).build());
client().prepareIndex("index").setId("1").setSource("field", "value").setRefreshPolicy(IMMEDIATE).get();
client().prepareIndex("index").setId("2").setSource("field", "value").setRefreshPolicy(IMMEDIATE).get();
client().prepareIndex("index").setId("3").setSource("field", "value").setRefreshPolicy(IMMEDIATE).get();
assertAcked(client().execute(FreezeIndexAction.INSTANCE, new FreezeRequest("index")).actionGet());
String indexName = "index";
createIndex(indexName, Settings.builder().put("index.number_of_shards", 2).build());
client().prepareIndex(indexName).setId("1").setSource("field", "value").setRefreshPolicy(IMMEDIATE).get();
client().prepareIndex(indexName).setId("2").setSource("field", "value").setRefreshPolicy(IMMEDIATE).get();
client().prepareIndex(indexName).setId("3").setSource("field", "value").setRefreshPolicy(IMMEDIATE).get();
assertAcked(client().execute(FreezeIndexAction.INSTANCE, new FreezeRequest(indexName)).actionGet());
expectThrows(
ClusterBlockException.class,
() -> client().prepareIndex("index").setId("4").setSource("field", "value").setRefreshPolicy(IMMEDIATE).get()
() -> client().prepareIndex(indexName).setId("4").setSource("field", "value").setRefreshPolicy(IMMEDIATE).get()
);
IndicesService indexServices = getInstanceFromNode(IndicesService.class);
Index index = resolveIndex("index");
Index index = resolveIndex(indexName);
IndexService indexService = indexServices.indexServiceSafe(index);
IndexShard shard = indexService.getShard(0);
Engine engine = IndexShardTestCase.getEngine(shard);
Expand Down Expand Up @@ -141,7 +143,7 @@ public void testCloseFreezeAndOpen() throws Exception {
} while (searchResponse.getHits().getHits().length > 0);
client().prepareClearScroll().addScrollId(searchResponse.getScrollId()).get();

String pitId = openReaders(TimeValue.timeValueMinutes(1), "index");
String pitId = openReaders(TimeValue.timeValueMinutes(1), indexName);
try {
for (int from = 0; from < 3; from++) {
searchResponse = client().prepareSearch()
Expand All @@ -160,6 +162,7 @@ public void testCloseFreezeAndOpen() throws Exception {
assertFalse(((FrozenEngine) engine).isReaderOpen());
}
}
assertWarnings(TransportSearchAction.FROZEN_INDICES_DEPRECATION_MESSAGE.replace("{}", indexName));
} finally {
client().execute(ClosePointInTimeAction.INSTANCE, new ClosePointInTimeRequest(pitId)).get();
}
Expand All @@ -177,11 +180,12 @@ public void testSearchAndGetAPIsAreThrottled() throws IOException {
.endObject()
.endObject()
.endObject();
createIndex("index", Settings.builder().put("index.number_of_shards", 2).build(), mapping);
String indexName = "index";
createIndex(indexName, Settings.builder().put("index.number_of_shards", 2).build(), mapping);
for (int i = 0; i < 10; i++) {
client().prepareIndex("index").setId("" + i).setSource("field", "foo bar baz").get();
client().prepareIndex(indexName).setId("" + i).setSource("field", "foo bar baz").get();
}
assertAcked(client().execute(FreezeIndexAction.INSTANCE, new FreezeRequest("index")).actionGet());
assertAcked(client().execute(FreezeIndexAction.INSTANCE, new FreezeRequest(indexName)).actionGet());
int numRequests = randomIntBetween(20, 50);
int numRefreshes = 0;
for (int i = 0; i < numRequests; i++) {
Expand All @@ -190,29 +194,30 @@ public void testSearchAndGetAPIsAreThrottled() throws IOException {
// searcher and rewrite the request outside of the search-throttle thread pool
switch (randomFrom(Arrays.asList(0, 1, 2))) {
case 0:
client().prepareGet("index", "" + randomIntBetween(0, 9)).get();
client().prepareGet(indexName, "" + randomIntBetween(0, 9)).get();
break;
case 1:
client().prepareSearch("index")
client().prepareSearch(indexName)
.setIndicesOptions(IndicesOptions.STRICT_EXPAND_OPEN_FORBID_CLOSED)
.setSearchType(SearchType.QUERY_THEN_FETCH)
.get();
// in total 4 refreshes 1x query & 1x fetch per shard (we have 2)
numRefreshes += 3;
break;
case 2:
client().prepareTermVectors("index", "" + randomIntBetween(0, 9)).get();
client().prepareTermVectors(indexName, "" + randomIntBetween(0, 9)).get();
break;
case 3:
client().prepareExplain("index", "" + randomIntBetween(0, 9)).setQuery(new MatchAllQueryBuilder()).get();
client().prepareExplain(indexName, "" + randomIntBetween(0, 9)).setQuery(new MatchAllQueryBuilder()).get();
break;

default:
assert false;
}
}
IndicesStatsResponse index = client().admin().indices().prepareStats("index").clear().setRefresh(true).get();
IndicesStatsResponse index = client().admin().indices().prepareStats(indexName).clear().setRefresh(true).get();
assertEquals(numRefreshes, index.getTotal().refresh.getTotal());
assertWarnings(TransportSearchAction.FROZEN_INDICES_DEPRECATION_MESSAGE.replace("{}", indexName));
}

public void testFreezeAndUnfreeze() {
Expand Down Expand Up @@ -298,26 +303,28 @@ public void testUnfreezeClosedIndices() {
}

public void testFreezePattern() {
createIndex("test-idx", Settings.builder().put("index.number_of_shards", 1).build());
client().prepareIndex("test-idx").setId("1").setSource("field", "value").setRefreshPolicy(IMMEDIATE).get();
String indexName = "test-idx";
createIndex(indexName, Settings.builder().put("index.number_of_shards", 1).build());
client().prepareIndex(indexName).setId("1").setSource("field", "value").setRefreshPolicy(IMMEDIATE).get();
createIndex("test-idx-1", Settings.builder().put("index.number_of_shards", 1).build());
client().prepareIndex("test-idx-1").setId("1").setSource("field", "value").setRefreshPolicy(IMMEDIATE).get();
assertAcked(client().execute(FreezeIndexAction.INSTANCE, new FreezeRequest("test-idx")).actionGet());
assertIndexFrozen("test-idx");
assertAcked(client().execute(FreezeIndexAction.INSTANCE, new FreezeRequest(indexName)).actionGet());
assertIndexFrozen(indexName);

IndicesStatsResponse index = client().admin().indices().prepareStats("test-idx").clear().setRefresh(true).get();
IndicesStatsResponse index = client().admin().indices().prepareStats(indexName).clear().setRefresh(true).get();
assertEquals(0, index.getTotal().refresh.getTotal());
assertHitCount(client().prepareSearch("test-idx").setIndicesOptions(IndicesOptions.STRICT_EXPAND_OPEN_FORBID_CLOSED).get(), 1);
index = client().admin().indices().prepareStats("test-idx").clear().setRefresh(true).get();
assertHitCount(client().prepareSearch(indexName).setIndicesOptions(IndicesOptions.STRICT_EXPAND_OPEN_FORBID_CLOSED).get(), 1);
index = client().admin().indices().prepareStats(indexName).clear().setRefresh(true).get();
assertEquals(1, index.getTotal().refresh.getTotal());

assertAcked(client().execute(FreezeIndexAction.INSTANCE, new FreezeRequest("test*")).actionGet());
assertIndexFrozen("test-idx");
assertIndexFrozen(indexName);
assertIndexFrozen("test-idx-1");
index = client().admin().indices().prepareStats("test-idx").clear().setRefresh(true).get();
index = client().admin().indices().prepareStats(indexName).clear().setRefresh(true).get();
assertEquals(1, index.getTotal().refresh.getTotal());
index = client().admin().indices().prepareStats("test-idx-1").clear().setRefresh(true).get();
assertEquals(0, index.getTotal().refresh.getTotal());
assertWarnings(TransportSearchAction.FROZEN_INDICES_DEPRECATION_MESSAGE.replace("{}", indexName));
}

public void testCanMatch() throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.elasticsearch.action.search.TransportSearchAction;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.Response;
Expand All @@ -29,6 +30,7 @@
import org.elasticsearch.test.rest.ESRestTestCase;

import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
Expand Down Expand Up @@ -470,19 +472,28 @@ protected static Number count(String index) throws IOException {
protected static Map<String, Object> search(String index, QueryBuilder query, Boolean ignoreThrottled) throws IOException {
final Request request = new Request(HttpPost.METHOD_NAME, '/' + index + "/_search");
request.setJsonEntity(new SearchSourceBuilder().trackTotalHits(true).query(query).toString());

// If warning are returned than these must exist in this set:
Set<String> expectedWarnings = new HashSet<>();
expectedWarnings.add(TransportSearchAction.FROZEN_INDICES_DEPRECATION_MESSAGE.replace("{}", index));
if (ignoreThrottled != null) {
request.addParameter("ignore_throttled", ignoreThrottled.toString());
RequestOptions requestOptions = RequestOptions.DEFAULT.toBuilder()
.setWarningsHandler(
warnings -> List.of(
"[ignore_throttled] parameter is deprecated because frozen indices have been deprecated. "
+ "Consider cold or frozen tiers in place of frozen indices."
).equals(warnings) == false
)
.build();
request.setOptions(requestOptions);
expectedWarnings.add(
"[ignore_throttled] parameter is deprecated because frozen indices have been deprecated. "
+ "Consider cold or frozen tiers in place of frozen indices."
);
}

RequestOptions requestOptions = RequestOptions.DEFAULT.toBuilder().setWarningsHandler(warnings -> {
for (String warning : warnings) {
if (expectedWarnings.contains(warning) == false) {
return true;
}
}
return false;
}).build();
request.setOptions(requestOptions);

final Response response = client().performRequest(request);
assertThat(
"Failed to execute search request on index [" + index + "]: " + response,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- do:
warnings:
- "[ignore_throttled] parameter is deprecated because frozen indices have been deprecated. Consider cold or frozen tiers in place of frozen indices."
- "Searching frozen indices [test] is deprecated. Consider cold or frozen tiers in place of frozen indices. The frozen feature will be removed in a feature release."
search:
rest_total_hits_as_int: true
index: test
Expand Down Expand Up @@ -68,6 +69,7 @@
- do:
warnings:
- "[ignore_throttled] parameter is deprecated because frozen indices have been deprecated. Consider cold or frozen tiers in place of frozen indices."
- "Searching frozen indices [test,test-01] is deprecated. Consider cold or frozen tiers in place of frozen indices. The frozen feature will be removed in a feature release."
search:
rest_total_hits_as_int: true
index: _all
Expand Down Expand Up @@ -134,6 +136,7 @@
- do:
warnings:
- "[ignore_throttled] parameter is deprecated because frozen indices have been deprecated. Consider cold or frozen tiers in place of frozen indices."
- "Searching frozen indices [test] is deprecated. Consider cold or frozen tiers in place of frozen indices. The frozen feature will be removed in a feature release."
search:
rest_total_hits_as_int: true
index: _all
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,9 @@ public void testFrozenIndexAfterRestarted() throws Exception {
assertNoFileBasedRecovery(index, n -> true);
final Request request = new Request("GET", "/" + index + "/_search");
request.setOptions(expectWarnings("[ignore_throttled] parameter is deprecated because frozen " +
"indices have been deprecated. Consider cold or frozen tiers in place of frozen indices."));
"indices have been deprecated. Consider cold or frozen tiers in place of frozen indices.",
"Searching frozen indices [" + index + "] is deprecated. " +
"Consider cold or frozen tiers in place of frozen indices. The frozen feature will be removed in a feature release."));
request.addParameter("ignore_throttled", "false");
assertThat(XContentMapValues.extractValue("hits.total.value", entityAsMap(client().performRequest(request))),
equalTo(totalHits));
Expand Down

0 comments on commit 272c55e

Please sign in to comment.