|
38 | 38 | import java.util.Collections;
|
39 | 39 | import java.util.Iterator;
|
40 | 40 | import java.util.List;
|
| 41 | +import java.util.Locale; |
41 | 42 | import java.util.Map;
|
42 | 43 | import java.util.concurrent.TimeUnit;
|
43 | 44 | import java.util.function.Consumer;
|
|
51 | 52 | import static org.elasticsearch.index.mapper.MapperService.INDEX_MAPPING_NESTED_DOCS_LIMIT_SETTING;
|
52 | 53 | import static org.elasticsearch.index.mapper.MapperService.INDEX_MAPPING_NESTED_FIELDS_LIMIT_SETTING;
|
53 | 54 | import static org.elasticsearch.index.mapper.MapperService.INDEX_MAPPING_TOTAL_FIELDS_LIMIT_SETTING;
|
| 55 | +import static org.elasticsearch.index.mapper.SourceFieldMapper.INDEX_MAPPER_SOURCE_MODE_SETTING; |
54 | 56 |
|
55 | 57 | /**
|
56 | 58 | * This class encapsulates all index level settings and handles settings updates.
|
@@ -653,6 +655,62 @@ public Iterator<Setting<?>> settings() {
|
653 | 655 | Property.Final
|
654 | 656 | );
|
655 | 657 |
|
| 658 | + public static final Setting<Boolean> RECOVERY_USE_SYNTHETIC_SOURCE_SETTING = Setting.boolSetting( |
| 659 | + "index.recovery.use_synthetic_source", |
| 660 | + false, |
| 661 | + new Setting.Validator<>() { |
| 662 | + @Override |
| 663 | + public void validate(Boolean value) {} |
| 664 | + |
| 665 | + @Override |
| 666 | + public void validate(Boolean enabled, Map<Setting<?>, Object> settings) { |
| 667 | + if (enabled == false) { |
| 668 | + return; |
| 669 | + } |
| 670 | + |
| 671 | + // Verify if synthetic source is enabled on the index; fail if it is not |
| 672 | + var indexMode = (IndexMode) settings.get(MODE); |
| 673 | + if (indexMode.defaultSourceMode() != SourceFieldMapper.Mode.SYNTHETIC) { |
| 674 | + var sourceMode = (SourceFieldMapper.Mode) settings.get(INDEX_MAPPER_SOURCE_MODE_SETTING); |
| 675 | + if (sourceMode != SourceFieldMapper.Mode.SYNTHETIC) { |
| 676 | + throw new IllegalArgumentException( |
| 677 | + String.format( |
| 678 | + Locale.ROOT, |
| 679 | + "The setting [%s] is only permitted when [%s] is set to [%s]. Current mode: [%s].", |
| 680 | + RECOVERY_USE_SYNTHETIC_SOURCE_SETTING.getKey(), |
| 681 | + INDEX_MAPPER_SOURCE_MODE_SETTING.getKey(), |
| 682 | + SourceFieldMapper.Mode.SYNTHETIC.name(), |
| 683 | + sourceMode.name() |
| 684 | + ) |
| 685 | + ); |
| 686 | + } |
| 687 | + } |
| 688 | + |
| 689 | + // Verify that all nodes can handle this setting |
| 690 | + var version = (IndexVersion) settings.get(SETTING_INDEX_VERSION_CREATED); |
| 691 | + if (version.before(IndexVersions.USE_SYNTHETIC_SOURCE_FOR_RECOVERY)) { |
| 692 | + throw new IllegalArgumentException( |
| 693 | + String.format( |
| 694 | + Locale.ROOT, |
| 695 | + "The setting [%s] is unavailable on this cluster because some nodes are running older " |
| 696 | + + "versions that do not support it. Please upgrade all nodes to the latest version " |
| 697 | + + "and try again.", |
| 698 | + RECOVERY_USE_SYNTHETIC_SOURCE_SETTING.getKey() |
| 699 | + ) |
| 700 | + ); |
| 701 | + } |
| 702 | + } |
| 703 | + |
| 704 | + @Override |
| 705 | + public Iterator<Setting<?>> settings() { |
| 706 | + List<Setting<?>> res = List.of(INDEX_MAPPER_SOURCE_MODE_SETTING, SETTING_INDEX_VERSION_CREATED, MODE); |
| 707 | + return res.iterator(); |
| 708 | + } |
| 709 | + }, |
| 710 | + Property.IndexScope, |
| 711 | + Property.Final |
| 712 | + ); |
| 713 | + |
656 | 714 | /**
|
657 | 715 | * Returns <code>true</code> if TSDB encoding is enabled. The default is <code>true</code>
|
658 | 716 | */
|
@@ -824,6 +882,7 @@ private void setRetentionLeaseMillis(final TimeValue retentionLease) {
|
824 | 882 | private volatile boolean skipIgnoredSourceRead;
|
825 | 883 | private final SourceFieldMapper.Mode indexMappingSourceMode;
|
826 | 884 | private final boolean recoverySourceEnabled;
|
| 885 | + private final boolean recoverySourceSyntheticEnabled; |
827 | 886 |
|
828 | 887 | /**
|
829 | 888 | * The maximum number of refresh listeners allows on this shard.
|
@@ -984,8 +1043,9 @@ public IndexSettings(final IndexMetadata indexMetadata, final Settings nodeSetti
|
984 | 1043 | es87TSDBCodecEnabled = scopedSettings.get(TIME_SERIES_ES87TSDB_CODEC_ENABLED_SETTING);
|
985 | 1044 | skipIgnoredSourceWrite = scopedSettings.get(IgnoredSourceFieldMapper.SKIP_IGNORED_SOURCE_WRITE_SETTING);
|
986 | 1045 | skipIgnoredSourceRead = scopedSettings.get(IgnoredSourceFieldMapper.SKIP_IGNORED_SOURCE_READ_SETTING);
|
987 |
| - indexMappingSourceMode = scopedSettings.get(SourceFieldMapper.INDEX_MAPPER_SOURCE_MODE_SETTING); |
| 1046 | + indexMappingSourceMode = scopedSettings.get(INDEX_MAPPER_SOURCE_MODE_SETTING); |
988 | 1047 | recoverySourceEnabled = RecoverySettings.INDICES_RECOVERY_SOURCE_ENABLED_SETTING.get(nodeSettings);
|
| 1048 | + recoverySourceSyntheticEnabled = scopedSettings.get(RECOVERY_USE_SYNTHETIC_SOURCE_SETTING); |
989 | 1049 |
|
990 | 1050 | scopedSettings.addSettingsUpdateConsumer(
|
991 | 1051 | MergePolicyConfig.INDEX_COMPOUND_FORMAT_SETTING,
|
@@ -1677,6 +1737,13 @@ public boolean isRecoverySourceEnabled() {
|
1677 | 1737 | return recoverySourceEnabled;
|
1678 | 1738 | }
|
1679 | 1739 |
|
| 1740 | + /** |
| 1741 | + * @return Whether recovery source should always be bypassed in favor of using synthetic source. |
| 1742 | + */ |
| 1743 | + public boolean isRecoverySourceSyntheticEnabled() { |
| 1744 | + return recoverySourceSyntheticEnabled; |
| 1745 | + } |
| 1746 | + |
1680 | 1747 | /**
|
1681 | 1748 | * The bounds for {@code @timestamp} on this index or
|
1682 | 1749 | * {@code null} if there are no bounds.
|
|
0 commit comments