Skip to content

Commit 2c846e6

Browse files
committed
perf: add column name index map cache in the PostgresqlColumnMetadata.
[resolves pgjdbc#636]
1 parent bbe3abf commit 2c846e6

File tree

3 files changed

+38
-22
lines changed

3 files changed

+38
-22
lines changed

src/main/java/io/r2dbc/postgresql/PostgresqlRow.java

+10-12
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,21 @@ final class PostgresqlRow implements io.r2dbc.postgresql.api.PostgresqlRow {
5050

5151
private volatile boolean isReleased = false;
5252

53-
private Map<String, Integer> columnNameIndexCacheMap;
53+
private final Map<String, Integer> columnNameIndexCacheMap;
5454

5555
PostgresqlRow(ConnectionResources context, io.r2dbc.postgresql.api.PostgresqlRowMetadata metadata, List<RowDescription.Field> fields, ByteBuf[] data) {
5656
this.context = Assert.requireNonNull(context, "context must not be null");
5757
this.metadata = Assert.requireNonNull(metadata, "metadata must not be null");
5858
this.fields = Assert.requireNonNull(fields, "fields must not be null");
5959
this.data = Assert.requireNonNull(data, "data must not be null");
60+
61+
if (metadata instanceof PostgresqlRowMetadata) {
62+
this.columnNameIndexCacheMap = Assert.requireNonNull(
63+
((PostgresqlRowMetadata) metadata).getColumnNameIndexMap(),
64+
"columnNameIndexCacheMap must not be null");
65+
} else {
66+
this.columnNameIndexCacheMap = createColumnNameIndexMap(this.fields);
67+
}
6068
}
6169

6270
@Override
@@ -179,18 +187,8 @@ void release() {
179187
}
180188

181189
private int getColumn(String name) {
182-
if (this.columnNameIndexCacheMap == null) {
183-
this.columnNameIndexCacheMap = createColumnNameIndexMap(this.fields);
184-
}
185-
186-
Integer index = this.columnNameIndexCacheMap.get(name);
187-
if (index != null) {
188-
return index;
189-
}
190-
191-
index = this.columnNameIndexCacheMap.get(name.toLowerCase(Locale.ROOT));
190+
Integer index = this.columnNameIndexCacheMap.get(name.toLowerCase(Locale.ROOT));
192191
if (index != null) {
193-
this.columnNameIndexCacheMap.put(name, index);
194192
return index;
195193
}
196194

src/main/java/io/r2dbc/postgresql/PostgresqlRowMetadata.java

+11
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@
2626
import java.util.ArrayList;
2727
import java.util.Collection;
2828
import java.util.Collections;
29+
import java.util.HashMap;
2930
import java.util.Iterator;
3031
import java.util.LinkedHashMap;
3132
import java.util.List;
33+
import java.util.Locale;
3234
import java.util.Map;
3335
import java.util.NoSuchElementException;
3436
import java.util.Objects;
@@ -42,14 +44,19 @@ final class PostgresqlRowMetadata extends AbstractCollection<String> implements
4244

4345
private final Map<String, PostgresqlColumnMetadata> nameKeyedColumns;
4446

47+
private final Map<String, Integer> columnNameIndexMap;
48+
4549
PostgresqlRowMetadata(List<PostgresqlColumnMetadata> columnMetadatas) {
4650
this.columnMetadatas = Assert.requireNonNull(columnMetadatas, "columnMetadatas must not be null");
4751
this.nameKeyedColumns = new LinkedHashMap<>();
52+
this.columnNameIndexMap = new HashMap<>(columnMetadatas.size(), 1);
4853

54+
int i = 0;
4955
for (PostgresqlColumnMetadata columnMetadata : columnMetadatas) {
5056
if (!this.nameKeyedColumns.containsKey(columnMetadata.getName())) {
5157
this.nameKeyedColumns.put(columnMetadata.getName(), columnMetadata);
5258
}
59+
columnNameIndexMap.putIfAbsent(columnMetadata.getName().toLowerCase(Locale.ROOT), i++);
5360
}
5461
}
5562

@@ -183,6 +190,10 @@ PostgresqlColumnMetadata findColumn(String name) {
183190
return column;
184191
}
185192

193+
Map<String, Integer> getColumnNameIndexMap() {
194+
return this.columnNameIndexMap;
195+
}
196+
186197
static PostgresqlRowMetadata toRowMetadata(Codecs codecs, RowDescription rowDescription) {
187198
Assert.requireNonNull(codecs, "codecs must not be null");
188199
Assert.requireNonNull(rowDescription, "rowDescription must not be null");

src/test/java/io/r2dbc/postgresql/PostgresqlRowUnitTests.java

+17-10
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
package io.r2dbc.postgresql;
1818

1919
import io.netty.buffer.ByteBuf;
20+
import io.r2dbc.postgresql.codec.Codecs;
2021
import io.r2dbc.postgresql.codec.MockCodecs;
2122
import io.r2dbc.postgresql.message.backend.DataRow;
2223
import io.r2dbc.postgresql.message.backend.RowDescription;
2324
import io.r2dbc.postgresql.util.ReferenceCountedCleaner;
25+
import java.util.stream.Collectors;
2426
import org.junit.jupiter.api.AfterEach;
2527
import org.junit.jupiter.api.Test;
2628

@@ -51,6 +53,11 @@ final class PostgresqlRowUnitTests {
5153
new RowDescription.Field((short) 400, 400, 300, (short) 400, FORMAT_TEXT, "test-name-3", 500)
5254
);
5355

56+
private final PostgresqlRowMetadata metadata = new PostgresqlRowMetadata(columns
57+
.stream()
58+
.map(field -> PostgresqlColumnMetadata.toColumnMetadata(mock(Codecs.class), field))
59+
.collect(Collectors.toList()));
60+
5461
private final ByteBuf[] data = new ByteBuf[]{TEST.buffer(4).writeInt(100), TEST.buffer(4).writeInt(300), null};
5562

5663
@AfterEach
@@ -78,7 +85,7 @@ void getAfterRelease() {
7885
.decoding(TEST.buffer(4).writeInt(300), 400, FORMAT_TEXT, Object.class, value)
7986
.build();
8087

81-
PostgresqlRow row = new PostgresqlRow(MockContext.builder().codecs(codecs).build(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns, new ByteBuf[0]);
88+
PostgresqlRow row = new PostgresqlRow(MockContext.builder().codecs(codecs).build(), this.metadata, this.columns, new ByteBuf[0]);
8289
row.release();
8390

8491
assertThatIllegalStateException().isThrownBy(() -> row.get("test-name-2", Object.class))
@@ -93,7 +100,7 @@ void getDefaultType() {
93100
.decoding(TEST.buffer(4).writeInt(300), 400, FORMAT_TEXT, Object.class, value)
94101
.build();
95102

96-
assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns, this.data).get("test-name-2")).isSameAs(value);
103+
assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), this.metadata, this.columns, this.data).get("test-name-2")).isSameAs(value);
97104
}
98105

99106
@Test
@@ -104,20 +111,20 @@ void getIndex() {
104111
.decoding(TEST.buffer(4).writeInt(300), 400, FORMAT_TEXT, Object.class, value)
105112
.build();
106113

107-
assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns, this.data).get(1, Object.class)).isSameAs(value);
114+
assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), this.metadata, this.columns, this.data).get(1, Object.class)).isSameAs(value);
108115
}
109116

110117
@Test
111118
void getInvalidIndex() {
112-
assertThatExceptionOfType(IndexOutOfBoundsException.class).isThrownBy(() -> new PostgresqlRow(MockContext.empty(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns,
119+
assertThatExceptionOfType(IndexOutOfBoundsException.class).isThrownBy(() -> new PostgresqlRow(MockContext.empty(), this.metadata, this.columns,
113120
new ByteBuf[0]).get(3,
114121
Object.class))
115122
.withMessage("Column index 3 is larger than the number of columns 3");
116123
}
117124

118125
@Test
119126
void getInvalidName() {
120-
assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(() -> new PostgresqlRow(MockContext.empty(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns,
127+
assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(() -> new PostgresqlRow(MockContext.empty(), this.metadata, this.columns,
121128
new ByteBuf[0]).get("test-name" +
122129
"-4", Object.class))
123130
.withMessageMatching("Column name 'test-name-4' does not exist in column names \\[test-name-[\\d], test-name-[\\d], test-name-[\\d]\\]");
@@ -131,20 +138,20 @@ void getName() {
131138
.decoding(TEST.buffer(4).writeInt(300), 400, FORMAT_TEXT, Object.class, value)
132139
.build();
133140

134-
assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns, this.data).get("test-name-2", Object.class)).isSameAs(value);
135-
assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns, this.data).get("tEsT-nAme-2", Object.class)).isSameAs(value);
141+
assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), this.metadata, this.columns, this.data).get("test-name-2", Object.class)).isSameAs(value);
142+
assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), this.metadata, this.columns, this.data).get("tEsT-nAme-2", Object.class)).isSameAs(value);
136143
}
137144

138145
@Test
139146
void getNoIdentifier() {
140-
assertThatIllegalArgumentException().isThrownBy(() -> new PostgresqlRow(MockContext.empty(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns, new ByteBuf[0]).get(null,
147+
assertThatIllegalArgumentException().isThrownBy(() -> new PostgresqlRow(MockContext.empty(), this.metadata, this.columns, new ByteBuf[0]).get(null,
141148
Object.class))
142149
.withMessage("name must not be null");
143150
}
144151

145152
@Test
146153
void getNoType() {
147-
assertThatIllegalArgumentException().isThrownBy(() -> new PostgresqlRow(MockContext.empty(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns, new ByteBuf[0]).get("", null))
154+
assertThatIllegalArgumentException().isThrownBy(() -> new PostgresqlRow(MockContext.empty(), this.metadata, this.columns, new ByteBuf[0]).get("", null))
148155
.withMessage("type must not be null");
149156
}
150157

@@ -154,7 +161,7 @@ void getNull() {
154161
.decoding(null, 400, FORMAT_TEXT, Object.class, null)
155162
.build();
156163

157-
assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns, this.data).get("test-name-3", Object.class)).isNull();
164+
assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), this.metadata, this.columns, this.data).get("test-name-3", Object.class)).isNull();
158165
}
159166

160167
@Test

0 commit comments

Comments
 (0)