-
Notifications
You must be signed in to change notification settings - Fork 24.9k
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
Remove PROTO-serialization from IndexMetaData.Custom #32749
Remove PROTO-serialization from IndexMetaData.Custom #32749
Conversation
Switches IndexMetaData.Custom to standard named serialization. Supersedes elastic#32683
Pinging @elastic/es-core-infra |
retest this please |
if (entry.getValue() instanceof Map) { | ||
if (customsRegistry == null) { | ||
// Custom registry wasn't specified - we are in client mode let's try loading it from SPI | ||
customsRegistry = new NamedXContentRegistry(getProvidedNamedXContents()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure to understand what you want to achieve here (though I understand the proto based serialization removal).
I don't think we want a request object to create a NamedXContentRegistry
with only some provided names xcontents as it won't contain all named xcontent parsers but only the ones that provide and implement NamedXContentProvider
.
The NamedXContentRegistry is usually instantiated once on the server or client side and it must contain all required named xcontent parsers. This list is potentially enriched with named xcontent parsers provided by modules or plugins that implement NamedXContentProvider
. But in any case, the NamedXContentRegistry is instantiated once on server or client side with everything it needs.
On server side the registry is instantiated in the Node class and in the RestHighLevelClient class for an example of client side instanciation.
In your case, I guess you'll have to plumb the NamedXContentRegistry
down to where you want to parse this content. I think it's also possible to retrieve a ref on the current registry from a XContentParser instance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! As per our discussion, I have removed the automatic NamedXContentRegistry
discovery and replaced with passing it to source(...)
method as parameters.
retest this please |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This LGTM, thanks Igor, I left a couple tiny comments.
@jasontedor might want to take a look and make sure this will be workable for CCR though
*/ | ||
public <T> boolean supportsNamedObject(Class<T> categoryClass, String name) { | ||
Map<String, Entry> parsers = registry.get(categoryClass); | ||
if (parsers == null || registry.isEmpty()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the registry.isEmpty()
check is superfluous here
throw new IllegalArgumentException("No custom metadata prototype registered for type [" + type + "]"); | ||
public static Custom parseCustom(String name, Map<String, Object> map, DeprecationHandler deprecationHandler, | ||
NamedXContentRegistry customsRegistry) throws IOException { | ||
XContentBuilder customXContent = XContentFactory.jsonBuilder() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you put this in a try-with-resources block?
IndexMetaData.Custom custom = parser.namedObject(IndexMetaData.Custom.class, currentFieldName, null); | ||
builder.putCustom(custom.getWriteableName(), custom); | ||
} catch (UnknownNamedObjectException ex) { | ||
logger.warn("Skipping unknown custom index metadata object with type {}", currentFieldName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be lowercase (suuuuper minor)
@jasontedor will this work for CCR's needs? |
…ndexmetadata-custom-2
…ndexmetadata-custom-2
…ndexmetadata-custom-2
Okay I've made some changes to this PR: This PR nows removes the deprecated The Map<String, String> ccrMeta = indexMetaData.getCustom("ccr"); And then have complete control over the metadata. This also means any The reason I use a custom /ping @martijnvg @jasontedor @s1monw as I believe you were all interested in the implementation of this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dakrone This looks great! I left a couple of comments.
* This is a {@code Map<String, String>} that implements AbstractDiffable so it | ||
* can be used for cluster state purposes | ||
*/ | ||
public class DiffableStringMap extends AbstractDiffable<DiffableStringMap> implements Map<String, String> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we extend from AbstractMap
here instead of AbstractDiffable
and then implement Diffable
instead of Map
? I think that would simplify this class and the only method that AbstractDiffable
provides here is overwritten here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep that definitely works, will do that
@SuppressWarnings("unchecked") | ||
public <T extends Custom> T custom(String type) { | ||
return (T) customs.get(type); | ||
public Map<String, String> getCustomData(final String key) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we returning here a mutable map? I don't think we should do that here. We should at least wrap it in Collections#unmodifiableMap()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep good idea, I'll do that
assertThat(dsm3.get("newkey"), equalTo("yay")); | ||
assertThat(dsm3.get("baz"), equalTo("eggplant")); | ||
assertThat(dsm3.get("potato"), equalTo(null)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also add a test here with a few more maps and entries (maybe randomly generated) than in the existing test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and maybe also a test that verifies that the serialization works?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also wonder if we need a random test that adds randomly to one map and then passes it on as a diff to another and makes sure after we did that N times the maps are the same?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and maybe also a test that verifies that the serialization works?
The serialization was added as part of the IndexMetaDataTests
, but I'll add one here for targeted serialization
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also wonder if we need a random test that adds randomly to one map and then passes it on as a diff to another and makes sure after we did that N times the maps are the same?
I'll add a test for that as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good in general. I left some minors and once @martijnvg comments are resolved I am good to go with that. nice and simple!
* This is a {@code Map<String, String>} that implements AbstractDiffable so it | ||
* can be used for cluster state purposes | ||
*/ | ||
public class DiffableStringMap extends AbstractDiffable<DiffableStringMap> implements Map<String, String> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
if (in.getVersion().before(Version.V_7_0_0_alpha1)) { | ||
// This used to be the size of custom metadata classes | ||
int customSize = in.readVInt(); | ||
assert customSize == 0 : "unexpected custom metadata when none is supported"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm do we need to skip the size if we are in production? I mean that assert will not trip if we run without -ea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not following, do you want it to be a regular exception instead of an assert? We still need to do the readVInt
regardless of -ea
or without, it's just the 0 size comparison that is an assert for tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that we need to do a hard exception indeed, we won't be able to read the rest of the message at this point because we can't read the customs (no IndexMetaData#lookupPrototypeSafe anymore
) when there are unexpected ones. That is, customSize > 0
is fatal for us.
assertThat(dsm3.get("newkey"), equalTo("yay")); | ||
assertThat(dsm3.get("baz"), equalTo("eggplant")); | ||
assertThat(dsm3.get("potato"), equalTo(null)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also wonder if we need a random test that adds randomly to one map and then passes it on as a diff to another and makes sure after we did that N times the maps are the same?
org.elasticsearch.plugins.spi.NamedXContentProviderTests$TestNamedXContentProvider |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is an unrelated change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep sorry, this was part of reverting Igor's changes that missed a newline
m2.put("newkey", "yay"); | ||
m2.put("baz", "eggplant"); | ||
DiffableStringMap dsm2 = new DiffableStringMap(m2); | ||
logger.info("--> 1: {}", dsm); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we remove the logging in this unittest?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, will do this
extends AbstractMap<String, String> and implement Diffable<String>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left one comment.
if (in.getVersion().before(Version.V_7_0_0_alpha1)) { | ||
// This used to be the size of custom metadata classes | ||
int customSize = in.readVInt(); | ||
assert customSize == 0 : "unexpected custom metadata when none is supported"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that we need to do a hard exception indeed, we won't be able to read the rest of the message at this point because we can't read the customs (no IndexMetaData#lookupPrototypeSafe anymore
) when there are unexpected ones. That is, customSize > 0
is fatal for us.
if (in.getVersion().before(Version.V_7_0_0_alpha1)) { | ||
// Used to be used for custom index metadata | ||
int customSize = in.readVInt(); | ||
assert customSize == 0 : "expected not to have any custom metadata"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be fatal.
builder.putCustom(key, custom); | ||
} | ||
} else { | ||
assert customSize == 0 : "expected no custom index metadata"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be fatal.
if (in.getVersion().before(Version.V_7_0_0_alpha1)) { | ||
// Previously we allowed custom metadata | ||
int customSize = in.readVInt(); | ||
assert customSize == 0 : "expected no custom metadata"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be fatal.
Thanks @jasontedor, I've addressed your comments |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
…32749) This PR removes the deprecated `Custom` class in `IndexMetaData`, in favor of a `Map<String, DiffableStringMap>` that is used to store custom index metadata. As part of this, there is now no way to set this metadata in a template or create index request (since it's only set by plugins, or dedicated REST endpoints). The `Map<String, DiffableStringMap>` is intended to be a namespaced `Map<String, String>` (`DiffableStringMap` implements `Map<String, String>`, so the signature is more like `Map<String, Map<String, String>>`). This is so we can do things like: ``` java Map<String, String> ccrMeta = indexMetaData.getCustom("ccr"); ``` And then have complete control over the metadata. This also means any plugin/feature that uses this has to manage its own BWC, as the map is just serialized as a map. It also means that if metadata is put in the map that isn't used (for instance, if a plugin were removed), it causes no failures the way an unregistered `Setting` would. The reason I use a custom `DiffableStringMap` here rather than a plain `Map<String, String>` is so the map can be diffed with previous cluster state updates for serialization. Supersedes elastic#32683
} | ||
|
||
@Override | ||
public boolean equals(Object obj) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it is necessary to overwrite equals(), hashCode() and toString() here? AbstractMap
already implements these methods.
LGTM - left one minor comment. |
* 6.x: Mute test watcher usage stats output [Rollup] Fix FullClusterRestart test TEST: Disable soft-deletes in ParentChildTestCase TEST: Disable randomized soft-deletes settings Integrates soft-deletes into Elasticsearch (#33222) drop `index.shard.check_on_startup: fix` (#32279) Fix AwaitsFix issue number Mute SmokeTestWatcherWithSecurityIT testsi [DOCS] Moves ml folder from x-pack/docs to docs (#33248) TEST: mute more SmokeTestWatcherWithSecurityIT tests [DOCS] Move rollup APIs to docs (#31450) [DOCS] Rename X-Pack Commands section (#33005) Fixes SecurityIntegTestCase so it always adds at least one alias (#33296) TESTS: Fix Random Fail in MockTcpTransportTests (#33061) (#33307) MINOR: Remove Dead Code from PathTrie (#33280) (#33306) Fix pom for build-tools (#33300) Lazy evaluate java9home (#33301) SQL: test coverage for JdbcResultSet (#32813) Work around to be able to generate eclipse projects (#33295) Different handling for security specific errors in the CLI. Fix for #33230 (#33255) [ML] Refactor delimited file structure detection (#33233) SQL: Support multi-index format as table identifier (#33278) Enable forbiddenapis server java9 (#33245) [MUTE] SmokeTestWatcherWithSecurityIT flaky tests Add region ISO code to GeoIP Ingest plugin (#31669) (#33276) Don't be strict for 6.x Update serialization versions for custom IndexMetaData backport Replace IndexMetaData.Custom with Map-based custom metadata (#32749) Painless: Fix Bindings Bug (#33274) SQL: prevent duplicate generation for repeated aggs (#33252) TEST: Mute testMonitorClusterHealth Fix serialization of empty field capabilities response (#33263) Fix nested _source retrieval with includes/excludes (#33180) [DOCS] TLS file resources are reloadable (#33258) Watcher: Ensure TriggerEngine start replaces existing watches (#33157) Ignore module-info in jar hell checks (#33011) Fix docs build after #33241 [DOC] Repository GCS ADC not supported (#33238) Upgrade to latest Gradle 4.10 (#32801) Fix/30904 cluster formation part2 (#32877) Move file-based discovery to core (#33241) HLRC: add client side RefreshPolicy (#33209) [Kerberos] Add unsupported languages for tests (#33253) Watcher: Reload properly on remote shard change (#33167) Fix classpath security checks for external tests. (#33066) [Rollup] Only allow aggregating on multiples of configured interval (#32052) Added deprecation warning for rescore in scroll queries (#33070) Apply settings filter to get cluster settings API (#33247) [Rollup] Re-factor Rollup Indexer into a generic indexer for re-usability (#32743) HLRC: create base timed request class (#33216) HLRC: Use Optional in validation logic (#33104) Painless: Add Bindings (#33042)
Switches IndexMetaData.Custom to the standard named serialization.
Supersedes #32683
@jasontedor this is a version of #32683 without any breaking changes in terms of functionality and user interface. It will require small changes in existing plugins that use IndexMetaData.Custom, but otherwise, I think there is total parity with existing implementation minus PROTO-serialization.
@tlrx could you take a look at my (mis)use of SPI and XContent parsers in
CreateIndexRequest
andPutIndexTemplateRequest
? Did I miss anything there?