Skip to content
Merged
Show file tree
Hide file tree
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 @@ -110,7 +110,7 @@ public enum MergeReason {
private volatile Map<String, DocumentMapper> mappers = emptyMap();

private volatile FieldTypeLookup fieldTypes;
private volatile Map<String, ObjectMapper> fullPathObjectMappers = new HashMap<>();
private volatile Map<String, ObjectMapper> fullPathObjectMappers = emptyMap();
private boolean hasNested = false; // updated dynamically to true when a nested object is added
private boolean allEnabled = false; // updated dynamically to true when _all is enabled

Expand Down Expand Up @@ -394,6 +394,7 @@ private synchronized Map<String, DocumentMapper> internalMerge(@Nullable Documen

for (ObjectMapper objectMapper : objectMappers) {
if (fullPathObjectMappers == this.fullPathObjectMappers) {
// first time through the loops
fullPathObjectMappers = new HashMap<>(this.fullPathObjectMappers);
}
fullPathObjectMappers.put(objectMapper.fullPath(), objectMapper);
Expand All @@ -414,6 +415,7 @@ private synchronized Map<String, DocumentMapper> internalMerge(@Nullable Documen

if (oldMapper == null && newMapper.parentFieldMapper().active()) {
if (parentTypes == this.parentTypes) {
// first time through the loop
parentTypes = new HashSet<>(this.parentTypes);
}
parentTypes.add(mapper.parentFieldMapper().type());
Expand Down Expand Up @@ -456,8 +458,15 @@ private synchronized Map<String, DocumentMapper> internalMerge(@Nullable Documen
// make structures immutable
mappers = Collections.unmodifiableMap(mappers);
results = Collections.unmodifiableMap(results);
parentTypes = Collections.unmodifiableSet(parentTypes);
fullPathObjectMappers = Collections.unmodifiableMap(fullPathObjectMappers);

// only need to immutably rewrap these if the previous reference was changed.
// if not then they are already implicitly immutable.
if (fullPathObjectMappers != this.fullPathObjectMappers) {
fullPathObjectMappers = Collections.unmodifiableMap(fullPathObjectMappers);
}
if (parentTypes != this.parentTypes) {
parentTypes = Collections.unmodifiableSet(parentTypes);
}

// commit the change
if (defaultMappingSource != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;

Expand Down Expand Up @@ -189,6 +190,22 @@ public void testMergeWithMap() throws Throwable {
assertThat(e.getMessage(), startsWith("Failed to parse mapping [type1]: "));
}

public void testMergeParentTypesSame() {
// Verifies that a merge (absent a DocumentMapper change)
// doesn't change the parentTypes reference.
// The collection was being rewrapped with each merge
// in v5.2 resulting in eventual StackOverflowErrors.
// https://github.com/elastic/elasticsearch/issues/23604

IndexService indexService1 = createIndex("index1");
MapperService mapperService = indexService1.mapperService();
Set<String> parentTypes = mapperService.getParentTypes();

Map<String, Map<String, Object>> mappings = new HashMap<>();
mapperService.merge(mappings, MergeReason.MAPPING_UPDATE, false);
assertSame(parentTypes, mapperService.getParentTypes());
}

public void testOtherDocumentMappersOnlyUpdatedWhenChangingFieldType() throws IOException {
IndexService indexService = createIndex("test");

Expand Down