From a99bb2dcf2e5db765a551f280b9e3e5aa9ec51ab Mon Sep 17 00:00:00 2001 From: Kostas Krikellas <131142368+kkrik-es@users.noreply.github.com> Date: Thu, 31 Oct 2024 15:28:30 +0200 Subject: [PATCH] Check index setting for source mode in SourceOnlySnapshotRepository (#116002) * Check index setting for source mode in SourceOnlySnapshotRepository * update * Revert "update" This reverts commit 9bbf0490f7d21b8c08489e05da563e3a76815847. (cherry picked from commit 37a4ee3102a070c29c7d414bfaeb809a3a59e76b) --- .../index/mapper/SourceFieldMapper.java | 6 ++- .../SourceOnlySnapshotRepository.java | 6 ++- .../SourceOnlySnapshotShardTests.java | 50 +++++++++++++++++++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java index 372e0bbdfecf4..1162734c0dc81 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java @@ -242,7 +242,7 @@ public SourceFieldMapper build() { } private Mode resolveSourceMode() { - // If the `index.mapper.source.mode` exists it takes precedence to determine the source mode for `_source` + // If the `index.mapping.source.mode` exists it takes precedence to determine the source mode for `_source` // otherwise the mode is determined according to `_source.mode`. if (INDEX_MAPPER_SOURCE_MODE_SETTING.exists(settings)) { return INDEX_MAPPER_SOURCE_MODE_SETTING.get(settings); @@ -439,6 +439,10 @@ public static boolean isSynthetic(IndexSettings indexSettings) { return INDEX_MAPPER_SOURCE_MODE_SETTING.get(indexSettings.getSettings()) == SourceFieldMapper.Mode.SYNTHETIC; } + public static boolean isStored(IndexSettings indexSettings) { + return INDEX_MAPPER_SOURCE_MODE_SETTING.get(indexSettings.getSettings()) == Mode.STORED; + } + public boolean isDisabled() { return mode == Mode.DISABLED; } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/snapshots/sourceonly/SourceOnlySnapshotRepository.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/snapshots/sourceonly/SourceOnlySnapshotRepository.java index fd101e53cc90e..48c7b727c83fa 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/snapshots/sourceonly/SourceOnlySnapshotRepository.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/snapshots/sourceonly/SourceOnlySnapshotRepository.java @@ -33,6 +33,7 @@ import org.elasticsearch.index.engine.EngineFactory; import org.elasticsearch.index.engine.ReadOnlyEngine; import org.elasticsearch.index.mapper.MapperService; +import org.elasticsearch.index.mapper.SourceFieldMapper; import org.elasticsearch.index.store.Store; import org.elasticsearch.index.translog.TranslogStats; import org.elasticsearch.repositories.FilterRepository; @@ -139,8 +140,9 @@ private static Metadata metadataToSnapshot(Collection indices, Metadata @Override public void snapshotShard(SnapshotShardContext context) { final MapperService mapperService = context.mapperService(); - if (mapperService.documentMapper() != null // if there is no mapping this is null - && mapperService.documentMapper().sourceMapper().isComplete() == false) { + if ((mapperService.documentMapper() != null // if there is no mapping this is null + && mapperService.documentMapper().sourceMapper().isComplete() == false) + || (mapperService.documentMapper() == null && SourceFieldMapper.isStored(mapperService.getIndexSettings()) == false)) { context.onFailure( new IllegalStateException( "Can't snapshot _source only on an index that has incomplete source ie. has _source disabled or filters the source" diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/snapshots/sourceonly/SourceOnlySnapshotShardTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/snapshots/sourceonly/SourceOnlySnapshotShardTests.java index e39ddc170c0a9..7405b3e5348f3 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/snapshots/sourceonly/SourceOnlySnapshotShardTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/snapshots/sourceonly/SourceOnlySnapshotShardTests.java @@ -52,6 +52,7 @@ import org.elasticsearch.index.engine.InternalEngineFactory; import org.elasticsearch.index.fieldvisitor.FieldsVisitor; import org.elasticsearch.index.mapper.SeqNoFieldMapper; +import org.elasticsearch.index.mapper.SourceFieldMapper; import org.elasticsearch.index.mapper.SourceToParse; import org.elasticsearch.index.seqno.RetentionLeaseSyncer; import org.elasticsearch.index.seqno.SeqNoStats; @@ -149,6 +150,55 @@ public void testSourceIncomplete() throws IOException { closeShards(shard); } + public void testSourceIncompleteSyntheticSourceNoDoc() throws IOException { + ShardRouting shardRouting = shardRoutingBuilder( + new ShardId("index", "_na_", 0), + randomAlphaOfLength(10), + true, + ShardRoutingState.INITIALIZING + ).withRecoverySource(RecoverySource.EmptyStoreRecoverySource.INSTANCE).build(); + Settings settings = Settings.builder() + .put(IndexMetadata.SETTING_VERSION_CREATED, IndexVersion.current()) + .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0) + .put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1) + .put(SourceFieldMapper.INDEX_MAPPER_SOURCE_MODE_SETTING.getKey(), "synthetic") + .build(); + IndexMetadata metadata = IndexMetadata.builder(shardRouting.getIndexName()).settings(settings).primaryTerm(0, primaryTerm).build(); + IndexShard shard = newShard(shardRouting, metadata, null, new InternalEngineFactory()); + recoverShardFromStore(shard); + SnapshotId snapshotId = new SnapshotId("test", "test"); + IndexId indexId = new IndexId(shard.shardId().getIndexName(), shard.shardId().getIndex().getUUID()); + SourceOnlySnapshotRepository repository = new SourceOnlySnapshotRepository(createRepository()); + repository.start(); + try (Engine.IndexCommitRef snapshotRef = shard.acquireLastIndexCommit(true)) { + IndexShardSnapshotStatus indexShardSnapshotStatus = IndexShardSnapshotStatus.newInitializing(new ShardGeneration(-1L)); + final PlainActionFuture future = new PlainActionFuture<>(); + runAsSnapshot( + shard.getThreadPool(), + () -> repository.snapshotShard( + new SnapshotShardContext( + shard.store(), + shard.mapperService(), + snapshotId, + indexId, + new SnapshotIndexCommit(snapshotRef), + null, + indexShardSnapshotStatus, + IndexVersion.current(), + randomMillisUpToYear9999(), + future + ) + ) + ); + IllegalStateException illegalStateException = expectThrows(IllegalStateException.class, future::actionGet); + assertEquals( + "Can't snapshot _source only on an index that has incomplete source ie. has _source disabled or filters the source", + illegalStateException.getMessage() + ); + } + closeShards(shard); + } + public void testIncrementalSnapshot() throws IOException { IndexShard shard = newStartedShard(); for (int i = 0; i < 10; i++) {