Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -533,15 +533,19 @@ private static Map<String, Mapper> buildMergedMappers(
MergeReason reason,
MapperMergeContext objectMergeContext
) {
Map<String, Mapper> mergedMappers = null;
for (Mapper mergeWithMapper : mergeWith) {
Mapper mergeIntoMapper = (mergedMappers == null ? existing.mappers : mergedMappers).get(mergeWithMapper.simpleName());
Iterator<Mapper> iterator = mergeWith.iterator();
if (iterator.hasNext() == false) {
return Map.copyOf(existing.mappers);
}
Comment thread
felixbarny marked this conversation as resolved.
Map<String, Mapper> mergedMappers = new HashMap<>(existing.mappers);
while (iterator.hasNext()) {
Mapper mergeWithMapper = iterator.next();
Mapper mergeIntoMapper = mergedMappers.get(mergeWithMapper.simpleName());

Mapper merged;
if (mergeIntoMapper == null) {
merged = mergeWithMapper;
mergedMappers.put(mergeWithMapper.simpleName(), mergeWithMapper);
} else if (mergeIntoMapper instanceof ObjectMapper objectMapper) {
merged = objectMapper.merge(mergeWithMapper, reason, objectMergeContext);
mergedMappers.put(objectMapper.simpleName(), objectMapper.merge(mergeWithMapper, reason, objectMergeContext));
} else {
assert mergeIntoMapper instanceof FieldMapper || mergeIntoMapper instanceof FieldAliasMapper;
if (mergeWithMapper instanceof NestedObjectMapper) {
Expand All @@ -553,22 +557,13 @@ private static Map<String, Mapper> buildMergedMappers(
// If we're merging template mappings when creating an index, then a field definition always
// replaces an existing one.
if (reason == MergeReason.INDEX_TEMPLATE) {
merged = mergeWithMapper;
mergedMappers.put(mergeWithMapper.simpleName(), mergeWithMapper);
} else {
merged = mergeIntoMapper.merge(mergeWithMapper, objectMergeContext);
mergedMappers.put(mergeWithMapper.simpleName(), mergeIntoMapper.merge(mergeWithMapper, objectMergeContext));
}
}
if (mergedMappers == null) {
mergedMappers = new HashMap<>(existing.mappers);
}
mergedMappers.put(merged.simpleName(), merged);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the put stay where it is? in every loop iteration we only ever put a single field, so we should be ok leaving a single put call, that adds the current merged instance to the map? That put call needs to be wrapped with a check that ensures we do not go beyond the limit?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we can do that. See also #102936 (comment)

It's important to decrement the field budget before calling merge on the sub fields. I think we should have the put calls as close as possible to the place where we decrement the field budget.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the latest changes in #102936, that no longer touches these lines, I still don't follow :)

The put is still within the loop, even if after the conditional instead of within the conditional . The only merge call I see in this method is performed within the conditional, before the put (before and after your change). What am I missing that makes this part of the changes necessary?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've actually reverted this in #102936 now (see c1b4258). Now that I've removed the Consumer methods from MapperMergeContext and there's only decrementFieldBudgetIfPossible which doesn't directly add the merged mapper to the map it think it's viable to not have the put in the if/else.

What's still important though is that we decrement the budget for the shallow object mapper in org.elasticsearch.index.mapper.ObjectMapper.MergeResult#truncateObjectMapper before calling shallowObjectMapper.merge. Otherwise, if we merged the object before decrementing the budget, we wouldn't have capacity to add the object itself.

}
if (mergedMappers != null) {
mergedMappers = Map.copyOf(mergedMappers);
} else {
mergedMappers = Map.copyOf(existing.mappers);
}
return mergedMappers;
return Map.copyOf(mergedMappers);
}
}

Expand Down