Skip to content

Commit a3611bc

Browse files
committed
Improve codec caching.
Codecs are now cached using their value type for simple value/null encoding. Additionally, for decoding we check whether the cached codec can decode the desired format/data type/value type and fall back to the cache supplier if there was a hash collision. [resolves #511] Signed-off-by: Mark Paluch <[email protected]>
1 parent 95d9eee commit a3611bc

File tree

1 file changed

+26
-24
lines changed

1 file changed

+26
-24
lines changed

src/main/java/io/r2dbc/postgresql/codec/CachedCodecLookup.java

+26-24
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ class CachedCodecLookup implements CodecLookup {
3939

4040
private final Map<Integer, Codec<?>> decodeCodecsCache = new ConcurrentHashMap<>();
4141

42-
private final Map<Integer, Codec<?>> encodeCodecsCache = new ConcurrentHashMap<>();
42+
private final Map<Class<?>, Codec<?>> encodeCodecsCache = new ConcurrentHashMap<>();
4343

44-
private final Map<Integer, Codec<?>> encodeNullCodecsCache = new ConcurrentHashMap<>();
44+
private final Map<Class<?>, Codec<?>> encodeNullCodecsCache = new ConcurrentHashMap<>();
4545

4646
private final CodecLookup delegate;
4747

@@ -93,7 +93,7 @@ public void afterCodecAdded() {
9393
@Override
9494
public <T> Codec<T> findDecodeCodec(int dataType, Format format, Class<? extends T> type) {
9595
Integer hash = generateCodecHash(dataType, format, type);
96-
return findCodec(hash, this.decodeCodecsCache, () -> {
96+
return findCodec(hash, dataType, format, type, this.decodeCodecsCache, () -> {
9797
LOG.trace("[codec-finder dataType={}, format={}, type={}] Decode codec not found in cache", dataType, format, type.getName());
9898
Codec<T> c = this.delegate.findDecodeCodec(dataType, format, type);
9999
if (c != null) {
@@ -105,25 +105,23 @@ public <T> Codec<T> findDecodeCodec(int dataType, Format format, Class<? extends
105105

106106
@Override
107107
public <T> Codec<T> findEncodeCodec(T value) {
108-
Integer hash = generateCodecHash(value.getClass());
109-
return findCodec(hash, this.encodeCodecsCache, () -> {
108+
return findCodec(value.getClass(), this.encodeCodecsCache, () -> {
110109
LOG.trace("[codec-finder type={}] Encode codec not found in cache", value.getClass().getName());
111110
Codec<T> c = this.delegate.findEncodeCodec(value);
112111
if (c != null) {
113-
this.encodeCodecsCache.putIfAbsent(hash, c);
112+
this.encodeCodecsCache.putIfAbsent(value.getClass(), c);
114113
}
115114
return c;
116115
});
117116
}
118117

119118
@Override
120119
public <T> Codec<T> findEncodeNullCodec(Class<T> type) {
121-
Integer hash = generateCodecHash(type);
122-
return findCodec(hash, this.encodeNullCodecsCache, () -> {
120+
return findCodec(type, this.encodeNullCodecsCache, () -> {
123121
LOG.trace("[codec-finder type={}] Encode null codec not found in cache", type.getName());
124122
Codec<T> c = this.delegate.findEncodeNullCodec(type);
125123
if (c != null) {
126-
this.encodeNullCodecsCache.putIfAbsent(hash, c);
124+
this.encodeNullCodecsCache.putIfAbsent(type, c);
127125
}
128126
return c;
129127
});
@@ -135,32 +133,36 @@ private void cacheDecode(Codec<?> c, Class<?> type, PostgresqlObjectId identifie
135133
}
136134

137135
private void cacheEncode(Codec<?> c, Class<?> type) {
138-
Integer encodeHash = generateCodecHash(type);
139-
this.encodeCodecsCache.putIfAbsent(encodeHash, c);
136+
this.encodeCodecsCache.putIfAbsent(type, c);
140137
if (c.canEncodeNull(type)) {
141-
this.encodeNullCodecsCache.putIfAbsent(encodeHash, c);
138+
this.encodeNullCodecsCache.putIfAbsent(type, c);
142139
}
143140
}
144141

145142
@SuppressWarnings("unchecked")
146-
private synchronized <T> Codec<T> findCodec(Integer codecHash, Map<Integer, Codec<?>> cache, Supplier<Codec<T>> fallback) {
147-
Codec<T> value = (Codec<T>) cache.get(codecHash);
143+
private synchronized <T> Codec<T> findCodec(Class<?> cacheKey, Map<Class<?>, Codec<?>> cache, Supplier<Codec<T>> fallback) {
144+
Codec<T> value = (Codec<T>) cache.get(cacheKey);
148145
return value != null ? value : fallback.get();
149146
}
150147

151-
private static Integer generateCodecHash(int dataType, Format format, Class<?> type) {
152-
int hash = (dataType << 5) - dataType;
153-
hash = (hash << 5) - hash + format.hashCode();
154-
hash = (hash << 5) - hash + generateCodecHash(type);
155-
return hash;
148+
@SuppressWarnings("unchecked")
149+
private synchronized <T> Codec<T> findCodec(Integer cacheKey, int dataType, Format format, Class<? extends T> type, Map<Integer, Codec<?>> cache, Supplier<Codec<T>> fallback) {
150+
Codec<T> value = (Codec<T>) cache.get(cacheKey);
151+
return (value != null && value.canDecode(dataType, format, type)) ? value : fallback.get();
156152
}
157153

158-
private static Integer generateCodecHash(Class<?> type) {
159-
int hash = type.hashCode();
160-
if (type.getComponentType() != null) {
161-
hash = (hash << 5) - hash + generateCodecHash(type.getComponentType());
154+
private static Integer generateCodecHash(int dataType, Format format, Class<?> type) {
155+
int result = 1;
156+
157+
result = 31 * result + dataType;
158+
result = 31 * result + format.hashCode();
159+
result = 31 * result + type.hashCode();
160+
161+
if (type.isArray()) {
162+
result = 31 * result + type.getComponentType().hashCode();
162163
}
163-
return hash;
164+
165+
return result;
164166
}
165167

166168
}

0 commit comments

Comments
 (0)