Skip to content

Commit c77870e

Browse files
Update Text class to use native java ByteBuffer (#127666) (#127925)
This PR is a precursor to #126492. It does three things: - Move org.elasticsearch.common.text.Text from :server to org.elasticsearch.xcontent.Text in :libs:x-content. - Refactor the Text class to use a java-native ByteBuffer instead of the elasticsearch BytesReference. - Add the XContentString interface, with the Text class implementing that interface. (cherry picked from commit db0c3c7) # Conflicts: # server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/DefaultHighlighter.java # server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java # server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightFieldTests.java # test/framework/src/main/java/org/elasticsearch/search/SearchResponseUtils.java
1 parent bc5d219 commit c77870e

39 files changed

+133
-71
lines changed

server/src/main/java/org/elasticsearch/common/text/Text.java renamed to libs/x-content/src/main/java/org/elasticsearch/xcontent/Text.java

+39-23
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,17 @@
66
* your election, the "Elastic License 2.0", the "GNU Affero General Public
77
* License v3.0 only", or the "Server Side Public License, v 1".
88
*/
9-
package org.elasticsearch.common.text;
10-
11-
import org.apache.lucene.util.BytesRef;
12-
import org.elasticsearch.common.bytes.BytesArray;
13-
import org.elasticsearch.common.bytes.BytesReference;
14-
import org.elasticsearch.xcontent.ToXContentFragment;
15-
import org.elasticsearch.xcontent.XContentBuilder;
9+
package org.elasticsearch.xcontent;
1610

1711
import java.io.IOException;
12+
import java.nio.ByteBuffer;
1813
import java.nio.charset.StandardCharsets;
1914

2015
/**
21-
* Both {@link String} and {@link BytesReference} representation of the text. Starts with one of those, and if
16+
* Both {@link String} and {@link ByteBuffer} representation of the text. Starts with one of those, and if
2217
* the other is requests, caches the other one in a local reference so no additional conversion will be needed.
2318
*/
24-
public final class Text implements Comparable<Text>, ToXContentFragment {
19+
public final class Text implements XContentString, Comparable<Text>, ToXContentFragment {
2520

2621
public static final Text[] EMPTY_ARRAY = new Text[0];
2722

@@ -36,31 +31,43 @@ public static Text[] convertFromStringArray(String[] strings) {
3631
return texts;
3732
}
3833

39-
private BytesReference bytes;
34+
private ByteBuffer bytes;
4035
private String text;
4136
private int hash;
37+
private int stringLength = -1;
38+
39+
/**
40+
* Construct a Text from a UTF-8 encoded ByteBuffer. Since no string length is specified, {@link #stringLength()}
41+
* will perform a string conversion to measure the string length.
42+
*/
43+
public Text(ByteBuffer bytes) {
44+
this.bytes = bytes;
45+
}
4246

43-
public Text(BytesReference bytes) {
47+
/**
48+
* Construct a Text from a UTF-8 encoded ByteBuffer and an explicit string length. Used to avoid string conversion
49+
* in {@link #stringLength()}.
50+
*/
51+
public Text(ByteBuffer bytes, int stringLength) {
4452
this.bytes = bytes;
53+
this.stringLength = stringLength;
4554
}
4655

4756
public Text(String text) {
4857
this.text = text;
4958
}
5059

5160
/**
52-
* Whether a {@link BytesReference} view of the data is already materialized.
61+
* Whether a {@link ByteBuffer} view of the data is already materialized.
5362
*/
5463
public boolean hasBytes() {
5564
return bytes != null;
5665
}
5766

58-
/**
59-
* Returns a {@link BytesReference} view of the data.
60-
*/
61-
public BytesReference bytes() {
67+
@Override
68+
public ByteBuffer bytes() {
6269
if (bytes == null) {
63-
bytes = new BytesArray(text.getBytes(StandardCharsets.UTF_8));
70+
bytes = StandardCharsets.UTF_8.encode(text);
6471
}
6572
return bytes;
6673
}
@@ -72,11 +79,20 @@ public boolean hasString() {
7279
return text != null;
7380
}
7481

75-
/**
76-
* Returns a {@link String} view of the data.
77-
*/
82+
@Override
7883
public String string() {
79-
return text == null ? bytes.utf8ToString() : text;
84+
if (text == null) {
85+
text = StandardCharsets.UTF_8.decode(bytes).toString();
86+
}
87+
return text;
88+
}
89+
90+
@Override
91+
public int stringLength() {
92+
if (stringLength < 0) {
93+
stringLength = string().length();
94+
}
95+
return stringLength;
8096
}
8197

8298
@Override
@@ -115,8 +131,8 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
115131
} else {
116132
// TODO: TextBytesOptimization we can use a buffer here to convert it? maybe add a
117133
// request to jackson to support InputStream as well?
118-
BytesRef br = this.bytes().toBytesRef();
119-
return builder.utf8Value(br.bytes, br.offset, br.length);
134+
assert bytes.hasArray();
135+
return builder.utf8Value(bytes.array(), bytes.arrayOffset() + bytes.position(), bytes.remaining());
120136
}
121137
}
122138
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.xcontent;
11+
12+
import java.nio.ByteBuffer;
13+
14+
public interface XContentString {
15+
/**
16+
* Returns a {@link String} view of the data.
17+
*/
18+
String string();
19+
20+
/**
21+
* Returns a UTF8-encoded {@link ByteBuffer} view of the data.
22+
*/
23+
ByteBuffer bytes();
24+
25+
/**
26+
* Returns the number of characters in the represented string.
27+
*/
28+
int stringLength();
29+
}

server/src/main/java/org/elasticsearch/cluster/service/MasterService.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import org.elasticsearch.common.settings.ClusterSettings;
3636
import org.elasticsearch.common.settings.Setting;
3737
import org.elasticsearch.common.settings.Settings;
38-
import org.elasticsearch.common.text.Text;
3938
import org.elasticsearch.common.util.CollectionUtils;
4039
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
4140
import org.elasticsearch.common.util.concurrent.CountDown;
@@ -54,6 +53,7 @@
5453
import org.elasticsearch.tasks.TaskManager;
5554
import org.elasticsearch.threadpool.Scheduler;
5655
import org.elasticsearch.threadpool.ThreadPool;
56+
import org.elasticsearch.xcontent.Text;
5757

5858
import java.util.ArrayList;
5959
import java.util.Collections;

server/src/main/java/org/elasticsearch/cluster/service/PendingClusterTask.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
import org.elasticsearch.common.io.stream.StreamInput;
1414
import org.elasticsearch.common.io.stream.StreamOutput;
1515
import org.elasticsearch.common.io.stream.Writeable;
16-
import org.elasticsearch.common.text.Text;
1716
import org.elasticsearch.core.TimeValue;
17+
import org.elasticsearch.xcontent.Text;
1818

1919
import java.io.IOException;
2020

server/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java

+14-4
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@
2323
import org.elasticsearch.common.collect.ImmutableOpenMap;
2424
import org.elasticsearch.common.geo.GeoPoint;
2525
import org.elasticsearch.common.settings.SecureString;
26-
import org.elasticsearch.common.text.Text;
2726
import org.elasticsearch.common.util.Maps;
2827
import org.elasticsearch.common.util.set.Sets;
2928
import org.elasticsearch.core.CharArrays;
3029
import org.elasticsearch.core.Nullable;
3130
import org.elasticsearch.core.TimeValue;
31+
import org.elasticsearch.xcontent.Text;
3232

3333
import java.io.EOFException;
3434
import java.io.FilterInputStream;
@@ -379,13 +379,23 @@ public Text readOptionalText() throws IOException {
379379
if (length == -1) {
380380
return null;
381381
}
382-
return new Text(readBytesReference(length));
382+
byte[] bytes = new byte[length];
383+
if (length > 0) {
384+
readBytes(bytes, 0, length);
385+
}
386+
var byteBuff = ByteBuffer.wrap(bytes);
387+
return new Text(byteBuff);
383388
}
384389

385390
public Text readText() throws IOException {
386-
// use StringAndBytes so we can cache the string if it's ever converted to it
391+
// use Text so we can cache the string if it's ever converted to it
387392
int length = readInt();
388-
return new Text(readBytesReference(length));
393+
byte[] bytes = new byte[length];
394+
if (length > 0) {
395+
readBytes(bytes, 0, length);
396+
}
397+
var byteBuff = ByteBuffer.wrap(bytes);
398+
return new Text(byteBuff);
389399
}
390400

391401
@Nullable

server/src/main/java/org/elasticsearch/common/io/stream/StreamOutput.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@
2121
import org.elasticsearch.common.geo.GeoPoint;
2222
import org.elasticsearch.common.io.stream.Writeable.Writer;
2323
import org.elasticsearch.common.settings.SecureString;
24-
import org.elasticsearch.common.text.Text;
2524
import org.elasticsearch.common.util.ByteUtils;
2625
import org.elasticsearch.core.CharArrays;
2726
import org.elasticsearch.core.Nullable;
2827
import org.elasticsearch.core.TimeValue;
28+
import org.elasticsearch.xcontent.Text;
2929
import org.elasticsearch.xcontent.XContentType;
3030

3131
import java.io.IOException;
@@ -399,7 +399,7 @@ public void writeText(Text text) throws IOException {
399399
writeInt(spare.length());
400400
write(spare.bytes(), 0, spare.length());
401401
} else {
402-
BytesReference bytes = text.bytes();
402+
BytesReference bytes = BytesReference.fromByteBuffer(text.bytes());
403403
writeInt(bytes.length());
404404
bytes.writeTo(this);
405405
}

server/src/main/java/org/elasticsearch/search/SearchHit.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import org.elasticsearch.common.io.stream.StreamInput;
2121
import org.elasticsearch.common.io.stream.StreamOutput;
2222
import org.elasticsearch.common.io.stream.Writeable;
23-
import org.elasticsearch.common.text.Text;
2423
import org.elasticsearch.common.util.Maps;
2524
import org.elasticsearch.common.xcontent.ChunkedToXContent;
2625
import org.elasticsearch.common.xcontent.XContentHelper;
@@ -39,6 +38,7 @@
3938
import org.elasticsearch.search.lookup.Source;
4039
import org.elasticsearch.transport.LeakTracker;
4140
import org.elasticsearch.transport.RemoteClusterAware;
41+
import org.elasticsearch.xcontent.Text;
4242
import org.elasticsearch.xcontent.ToXContentFragment;
4343
import org.elasticsearch.xcontent.ToXContentObject;
4444
import org.elasticsearch.xcontent.XContentBuilder;

server/src/main/java/org/elasticsearch/search/SearchShardTarget.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
import org.elasticsearch.common.io.stream.StreamInput;
1313
import org.elasticsearch.common.io.stream.StreamOutput;
1414
import org.elasticsearch.common.io.stream.Writeable;
15-
import org.elasticsearch.common.text.Text;
1615
import org.elasticsearch.core.Nullable;
1716
import org.elasticsearch.index.shard.ShardId;
1817
import org.elasticsearch.transport.RemoteClusterAware;
18+
import org.elasticsearch.xcontent.Text;
1919

2020
import java.io.IOException;
2121
import java.util.Objects;

server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/DefaultHighlighter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import org.elasticsearch.common.CheckedSupplier;
2222
import org.elasticsearch.common.Strings;
2323
import org.elasticsearch.common.lucene.Lucene;
24-
import org.elasticsearch.common.text.Text;
2524
import org.elasticsearch.features.NodeFeature;
2625
import org.elasticsearch.index.IndexSettings;
2726
import org.elasticsearch.index.mapper.IdFieldMapper;
@@ -34,6 +33,7 @@
3433
import org.elasticsearch.lucene.search.uhighlight.Snippet;
3534
import org.elasticsearch.search.fetch.FetchContext;
3635
import org.elasticsearch.search.fetch.FetchSubPhase;
36+
import org.elasticsearch.xcontent.Text;
3737

3838
import java.io.IOException;
3939
import java.text.BreakIterator;

server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/FastVectorHighlighter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import org.apache.lucene.search.vectorhighlight.SingleFragListBuilder;
2424
import org.elasticsearch.common.settings.Setting;
2525
import org.elasticsearch.common.settings.Settings;
26-
import org.elasticsearch.common.text.Text;
2726
import org.elasticsearch.common.util.CollectionUtils;
2827
import org.elasticsearch.index.mapper.MappedFieldType;
2928
import org.elasticsearch.index.mapper.TextSearchInfo;
@@ -33,6 +32,7 @@
3332
import org.elasticsearch.search.fetch.subphase.highlight.SearchHighlightContext.Field;
3433
import org.elasticsearch.search.fetch.subphase.highlight.SearchHighlightContext.FieldOptions;
3534
import org.elasticsearch.search.lookup.Source;
35+
import org.elasticsearch.xcontent.Text;
3636

3737
import java.io.IOException;
3838
import java.text.BreakIterator;

server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightField.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import org.elasticsearch.common.io.stream.StreamInput;
1414
import org.elasticsearch.common.io.stream.StreamOutput;
1515
import org.elasticsearch.common.io.stream.Writeable;
16-
import org.elasticsearch.common.text.Text;
16+
import org.elasticsearch.xcontent.Text;
1717
import org.elasticsearch.xcontent.ToXContentFragment;
1818
import org.elasticsearch.xcontent.XContentBuilder;
1919
import org.elasticsearch.xcontent.XContentParser;

server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/PlainHighlighter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@
2424
import org.apache.lucene.search.highlight.TextFragment;
2525
import org.apache.lucene.util.BytesRefHash;
2626
import org.elasticsearch.common.lucene.Lucene;
27-
import org.elasticsearch.common.text.Text;
2827
import org.elasticsearch.index.IndexSettings;
2928
import org.elasticsearch.index.mapper.MappedFieldType;
3029
import org.elasticsearch.search.fetch.FetchContext;
3130
import org.elasticsearch.search.fetch.FetchSubPhase;
31+
import org.elasticsearch.xcontent.Text;
3232

3333
import java.io.IOException;
3434
import java.util.ArrayList;

server/src/main/java/org/elasticsearch/search/searchafter/SearchAfterBuilder.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
import org.elasticsearch.common.io.stream.StreamInput;
2020
import org.elasticsearch.common.io.stream.StreamOutput;
2121
import org.elasticsearch.common.io.stream.Writeable;
22-
import org.elasticsearch.common.text.Text;
2322
import org.elasticsearch.core.Nullable;
2423
import org.elasticsearch.index.fielddata.IndexFieldData;
2524
import org.elasticsearch.search.DocValueFormat;
2625
import org.elasticsearch.search.sort.SortAndFormats;
2726
import org.elasticsearch.xcontent.ParseField;
27+
import org.elasticsearch.xcontent.Text;
2828
import org.elasticsearch.xcontent.ToXContentObject;
2929
import org.elasticsearch.xcontent.XContentBuilder;
3030
import org.elasticsearch.xcontent.XContentParser;

server/src/main/java/org/elasticsearch/search/suggest/Suggest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414
import org.elasticsearch.common.io.stream.StreamInput;
1515
import org.elasticsearch.common.io.stream.StreamOutput;
1616
import org.elasticsearch.common.io.stream.Writeable;
17-
import org.elasticsearch.common.text.Text;
1817
import org.elasticsearch.rest.action.search.RestSearchAction;
1918
import org.elasticsearch.search.aggregations.Aggregation;
2019
import org.elasticsearch.search.suggest.Suggest.Suggestion.Entry;
2120
import org.elasticsearch.search.suggest.Suggest.Suggestion.Entry.Option;
2221
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
2322
import org.elasticsearch.xcontent.ParseField;
23+
import org.elasticsearch.xcontent.Text;
2424
import org.elasticsearch.xcontent.ToXContentFragment;
2525
import org.elasticsearch.xcontent.XContentBuilder;
2626

server/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggester.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818
import org.apache.lucene.search.suggest.document.TopSuggestDocs;
1919
import org.apache.lucene.search.suggest.document.TopSuggestDocsCollector;
2020
import org.apache.lucene.util.CharsRefBuilder;
21-
import org.elasticsearch.common.text.Text;
2221
import org.elasticsearch.index.mapper.CompletionFieldMapper;
2322
import org.elasticsearch.search.suggest.Suggest;
2423
import org.elasticsearch.search.suggest.Suggester;
24+
import org.elasticsearch.xcontent.Text;
2525

2626
import java.io.IOException;
2727
import java.util.Collections;

server/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestion.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414
import org.elasticsearch.common.io.stream.StreamInput;
1515
import org.elasticsearch.common.io.stream.StreamOutput;
1616
import org.elasticsearch.common.lucene.Lucene;
17-
import org.elasticsearch.common.text.Text;
1817
import org.elasticsearch.common.util.Maps;
1918
import org.elasticsearch.common.util.set.Sets;
2019
import org.elasticsearch.search.SearchHit;
2120
import org.elasticsearch.search.suggest.Suggest;
2221
import org.elasticsearch.xcontent.ParseField;
22+
import org.elasticsearch.xcontent.Text;
2323
import org.elasticsearch.xcontent.XContentBuilder;
2424

2525
import java.io.IOException;

server/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggester.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import org.apache.lucene.util.BytesRefBuilder;
2020
import org.apache.lucene.util.CharsRefBuilder;
2121
import org.elasticsearch.common.lucene.Lucene;
22-
import org.elasticsearch.common.text.Text;
2322
import org.elasticsearch.index.query.AbstractQueryBuilder;
2423
import org.elasticsearch.index.query.ParsedQuery;
2524
import org.elasticsearch.index.query.QueryBuilder;
@@ -31,6 +30,7 @@
3130
import org.elasticsearch.search.suggest.Suggester;
3231
import org.elasticsearch.search.suggest.SuggestionSearchContext.SuggestionContext;
3332
import org.elasticsearch.search.suggest.phrase.NoisyChannelSpellChecker.Result;
33+
import org.elasticsearch.xcontent.Text;
3434
import org.elasticsearch.xcontent.XContentFactory;
3535
import org.elasticsearch.xcontent.XContentParser;
3636

server/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestion.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111

1212
import org.elasticsearch.common.io.stream.StreamInput;
1313
import org.elasticsearch.common.io.stream.StreamOutput;
14-
import org.elasticsearch.common.text.Text;
1514
import org.elasticsearch.search.suggest.Suggest;
1615
import org.elasticsearch.search.suggest.Suggest.Suggestion;
16+
import org.elasticsearch.xcontent.Text;
1717

1818
import java.io.IOException;
1919
import java.util.Objects;

0 commit comments

Comments
 (0)