Skip to content

Commit

Permalink
perf: avoid BaseQueryKey.toString in CachedQuery.getSize (#1227)
Browse files Browse the repository at this point in the history
LruCache uses .getSize to limit the size of the cache, so this method
should refrain from doing memory allocations.

closes #1226
  • Loading branch information
benbenw authored and vlsi committed Jun 29, 2018
1 parent 191d84e commit 669fc31
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 5 deletions.
12 changes: 11 additions & 1 deletion pgjdbc/src/main/java/org/postgresql/core/BaseQueryKey.java
Expand Up @@ -5,13 +5,15 @@

package org.postgresql.core;

import org.postgresql.util.CanEstimateSize;

/**
* This class is used as a cache key for simple statements that have no "returning columns".
* Prepared statements that have no returning columns use just {@code String sql} as a key.
* Simple and Prepared statements that have returning columns use {@link QueryWithReturningColumnsKey}
* as a cache key.
*/
class BaseQueryKey {
class BaseQueryKey implements CanEstimateSize {
public final String sql;
public final boolean isParameterized;
public final boolean escapeProcessing;
Expand All @@ -31,6 +33,14 @@ public String toString() {
+ '}';
}

@Override
public long getSize() {
if (sql == null) { // just in case
return 16;
}
return 16 + sql.length() * 2L; // 2 bytes per char, revise with Java 9's compact strings
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
14 changes: 10 additions & 4 deletions pgjdbc/src/main/java/org/postgresql/core/CachedQuery.java
Expand Up @@ -13,9 +13,7 @@
*/
public class CachedQuery implements CanEstimateSize {
/**
* Cache key. {@link String} or {@code org.postgresql.jdbc.CallableQueryKey}. It is assumed that
* {@code String.valueOf(key)*2} would give reasonable estimate of the number of retained bytes by
* given key (see {@link #getSize}).
* Cache key. {@link String} or {@code org.postgresql.util.CanEstimateSize}.
*/
public final Object key;
public final Query query;
Expand All @@ -25,6 +23,9 @@ public class CachedQuery implements CanEstimateSize {
private int executeCount;

public CachedQuery(Object key, Query query, boolean isFunction, boolean outParmBeforeFunc) {
assert key instanceof String || key instanceof CanEstimateSize
: "CachedQuery.key should either be String or implement CanEstimateSize."
+ " Actual class is " + key.getClass();
this.key = key;
this.query = query;
this.isFunction = isFunction;
Expand Down Expand Up @@ -55,7 +56,12 @@ public int getExecuteCount() {

@Override
public long getSize() {
int queryLength = String.valueOf(key).length() * 2 /* 2 bytes per char */;
long queryLength;
if (key instanceof String) {
queryLength = ((String) key).length() * 2L; // 2 bytes per char, revise with Java 9's compact strings
} else {
queryLength = ((CanEstimateSize) key).getSize();
}
return queryLength * 2 /* original query and native sql */
+ 100L /* entry in hash map, CachedQuery wrapper, etc */;
}
Expand Down
Expand Up @@ -16,6 +16,7 @@
*/
class QueryWithReturningColumnsKey extends BaseQueryKey {
public final String[] columnNames;
private int size; // query length cannot exceed MAX_INT

QueryWithReturningColumnsKey(String sql, boolean isParameterized, boolean escapeProcessing,
String[] columnNames) {
Expand All @@ -27,6 +28,23 @@ class QueryWithReturningColumnsKey extends BaseQueryKey {
this.columnNames = columnNames;
}

@Override
public long getSize() {
int size = this.size;
if (size != 0) {
return size;
}
size = (int) super.getSize();
if (columnNames != null) {
size += 16L; // array itself
for (String columnName: columnNames) {
size += columnName.length() * 2L; // 2 bytes per char, revise with Java 9's compact strings
}
}
this.size = size;
return size;
}

@Override
public String toString() {
return "QueryWithReturningColumnsKey{"
Expand Down

0 comments on commit 669fc31

Please sign in to comment.