This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-mime4j.git
commit a7a860d3eab7539c53a7d0ed0ea8ddd9e894e532 Author: Benoit Tellier <[email protected]> AuthorDate: Thu Jun 17 15:13:20 2021 +0700 MIME4J-302 Parser should avoid multiple calls to "toLowerCase" I was surprised MIME4J parsing spends 18% of its time calling toLowerCase on header names. This represents 12% of allocated memory. By holding the lowerCased name as part of the field name, and doing lazy initialization on it we can get this down to 6%. --- .../james/mime4j/stream/FallbackBodyDescriptorBuilder.java | 2 +- core/src/main/java/org/apache/james/mime4j/stream/Field.java | 9 +++++++++ .../main/java/org/apache/james/mime4j/stream/RawField.java | 11 +++++++++++ .../java/org/apache/james/mime4j/field/AbstractField.java | 12 ++++++++++++ .../org/apache/james/mime4j/field/DelegatingFieldParser.java | 10 +++++++++- .../apache/james/mime4j/internal/AbstractEntityBuilder.java | 4 ++-- .../java/org/apache/james/mime4j/message/AbstractHeader.java | 4 ++-- .../james/mime4j/message/DefaultBodyDescriptorBuilder.java | 2 +- 8 files changed, 47 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/apache/james/mime4j/stream/FallbackBodyDescriptorBuilder.java b/core/src/main/java/org/apache/james/mime4j/stream/FallbackBodyDescriptorBuilder.java index 2f0863a..4872654 100644 --- a/core/src/main/java/org/apache/james/mime4j/stream/FallbackBodyDescriptorBuilder.java +++ b/core/src/main/java/org/apache/james/mime4j/stream/FallbackBodyDescriptorBuilder.java @@ -117,7 +117,7 @@ class FallbackBodyDescriptorBuilder implements BodyDescriptorBuilder { * @param field the MIME field. */ public Field addField(RawField field) throws MimeException { - String name = field.getName().toLowerCase(Locale.US); + String name = field.getNameLowerCase(); if (name.equals("content-transfer-encoding") && transferEncoding == null) { String value = field.getBody(); diff --git a/core/src/main/java/org/apache/james/mime4j/stream/Field.java b/core/src/main/java/org/apache/james/mime4j/stream/Field.java index 6c58dec..bde3c79 100644 --- a/core/src/main/java/org/apache/james/mime4j/stream/Field.java +++ b/core/src/main/java/org/apache/james/mime4j/stream/Field.java @@ -19,6 +19,8 @@ package org.apache.james.mime4j.stream; +import java.util.Locale; + import org.apache.james.mime4j.util.ByteSequence; /** @@ -40,6 +42,13 @@ public interface Field { String getName(); /** + * Returns the name of the field in lower case. + */ + default String getNameLowerCase() { + return getName().toLowerCase(Locale.US); + } + + /** * Gets the unparsed and possibly encoded (see RFC 2047) field body string. * * @return the unparsed field body string. diff --git a/core/src/main/java/org/apache/james/mime4j/stream/RawField.java b/core/src/main/java/org/apache/james/mime4j/stream/RawField.java index f263b99..8bcaa77 100644 --- a/core/src/main/java/org/apache/james/mime4j/stream/RawField.java +++ b/core/src/main/java/org/apache/james/mime4j/stream/RawField.java @@ -19,6 +19,8 @@ package org.apache.james.mime4j.stream; +import java.util.Locale; + import org.apache.james.mime4j.util.ByteSequence; import org.apache.james.mime4j.util.CharsetUtil; import org.apache.james.mime4j.util.ContentUtil; @@ -39,6 +41,7 @@ public final class RawField implements Field { private final int delimiterIdx; private final String name; private final String body; + private String nameLowerCase; RawField(ByteSequence raw, int delimiterIdx, String name, String body) { if (name == null) { @@ -62,6 +65,14 @@ public final class RawField implements Field { return name; } + @Override + public String getNameLowerCase() { + if (nameLowerCase == null) { + nameLowerCase = name.toLowerCase(Locale.US); + } + return nameLowerCase; + } + public String getBody() { if (body != null) { return body; diff --git a/dom/src/main/java/org/apache/james/mime4j/field/AbstractField.java b/dom/src/main/java/org/apache/james/mime4j/field/AbstractField.java index d4330d9..f0580a3 100644 --- a/dom/src/main/java/org/apache/james/mime4j/field/AbstractField.java +++ b/dom/src/main/java/org/apache/james/mime4j/field/AbstractField.java @@ -49,6 +49,18 @@ public abstract class AbstractField implements ParsedField { return rawField.getName(); } + + /** + * Gets the name of the field in lower case (<code>subject</code>, + * <code>from</code>, etc). + * + * @return the field name. + */ + @Override + public String getNameLowerCase() { + return rawField.getNameLowerCase(); + } + /** * Gets the unfolded, unparsed and possibly encoded (see RFC 2047) field * body string. diff --git a/dom/src/main/java/org/apache/james/mime4j/field/DelegatingFieldParser.java b/dom/src/main/java/org/apache/james/mime4j/field/DelegatingFieldParser.java index 008918f..727958b 100644 --- a/dom/src/main/java/org/apache/james/mime4j/field/DelegatingFieldParser.java +++ b/dom/src/main/java/org/apache/james/mime4j/field/DelegatingFieldParser.java @@ -55,8 +55,16 @@ public class DelegatingFieldParser implements FieldParser<ParsedField> { return field; } + private FieldParser<? extends ParsedField> getParser(final Field rawField) { + final FieldParser<? extends ParsedField> field = parsers.get(rawField.getNameLowerCase()); + if (field == null) { + return defaultParser; + } + return field; + } + public ParsedField parse(final Field rawField, final DecodeMonitor monitor) { - final FieldParser<? extends ParsedField> parser = getParser(rawField.getName()); + final FieldParser<? extends ParsedField> parser = getParser(rawField); return parser.parse(rawField, monitor); } } diff --git a/dom/src/main/java/org/apache/james/mime4j/internal/AbstractEntityBuilder.java b/dom/src/main/java/org/apache/james/mime4j/internal/AbstractEntityBuilder.java index 5b83625..c8f0871 100644 --- a/dom/src/main/java/org/apache/james/mime4j/internal/AbstractEntityBuilder.java +++ b/dom/src/main/java/org/apache/james/mime4j/internal/AbstractEntityBuilder.java @@ -65,7 +65,7 @@ public abstract class AbstractEntityBuilder { * @param field the field to add. */ public AbstractEntityBuilder addField(Field field) { - String lowerCasedFieldName = field.getName().toLowerCase(Locale.US); + String lowerCasedFieldName = field.getNameLowerCase(); List<Field> values = fieldMap.get(lowerCasedFieldName); if (values == null) { values = new LinkedList<Field>(); @@ -210,7 +210,7 @@ public abstract class AbstractEntityBuilder { * @param field the field to set. */ public AbstractEntityBuilder setField(Field field) { - final String lowerCaseName = field.getName().toLowerCase(Locale.US); + final String lowerCaseName = field.getNameLowerCase(); List<Field> l = fieldMap.get(lowerCaseName); if (l == null || l.isEmpty()) { addField(field); diff --git a/dom/src/main/java/org/apache/james/mime4j/message/AbstractHeader.java b/dom/src/main/java/org/apache/james/mime4j/message/AbstractHeader.java index 63ac5af..c83de6f 100644 --- a/dom/src/main/java/org/apache/james/mime4j/message/AbstractHeader.java +++ b/dom/src/main/java/org/apache/james/mime4j/message/AbstractHeader.java @@ -67,7 +67,7 @@ public abstract class AbstractHeader implements Header { * @param field the field to add. */ public void addField(Field field) { - String lowerCaseFieldName = field.getName().toLowerCase(Locale.US); + String lowerCaseFieldName = field.getNameLowerCase(); List<Field> values = fieldMap.get(lowerCaseFieldName); if (values == null) { values = new LinkedList<Field>(); @@ -220,7 +220,7 @@ public abstract class AbstractHeader implements Header { * @param field the field to set. */ public void setField(Field field) { - final String lowerCaseName = field.getName().toLowerCase(Locale.US); + final String lowerCaseName = field.getNameLowerCase(); List<Field> l = fieldMap.get(lowerCaseName); if (l == null || l.isEmpty()) { addField(field); diff --git a/dom/src/main/java/org/apache/james/mime4j/message/DefaultBodyDescriptorBuilder.java b/dom/src/main/java/org/apache/james/mime4j/message/DefaultBodyDescriptorBuilder.java index e3d5e7e..de8d5a2 100644 --- a/dom/src/main/java/org/apache/james/mime4j/message/DefaultBodyDescriptorBuilder.java +++ b/dom/src/main/java/org/apache/james/mime4j/message/DefaultBodyDescriptorBuilder.java @@ -88,7 +88,7 @@ public class DefaultBodyDescriptorBuilder implements BodyDescriptorBuilder { public Field addField(final RawField rawfield) throws MimeException { ParsedField field = fieldParser.parse(rawfield, monitor); - String name = field.getName().toLowerCase(Locale.US); + String name = field.getNameLowerCase(); if (!fields.containsKey(name)) { fields.put(name, field); } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
