Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-introduce Retry logic for prepared statement caching #618

Merged
merged 13 commits into from
Feb 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 60 additions & 39 deletions src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,6 @@

// Note all the public functions in this class also need to be defined in SQLServerConnectionPoolProxy.
public class SQLServerConnection implements ISQLServerConnection {
boolean contextIsAlreadyChanged = false;
boolean contextChanged = false;

long timerExpire;
boolean attemptRefreshTokenLocked = false;
Expand Down Expand Up @@ -276,15 +274,20 @@ static ParsedSQLCacheItem parseAndCacheSQL(Sha1HashKey key, String sql) throws
return cacheItem;
}

/** Default size for prepared statement caches */
static final int DEFAULT_STATEMENT_POOLING_CACHE_SIZE = 0;

/** Size of the prepared statement handle cache */
private int statementPoolingCacheSize = 10;
private int statementPoolingCacheSize = DEFAULT_STATEMENT_POOLING_CACHE_SIZE;

/** Default size for prepared statement caches */
static final int DEFAULT_STATEMENT_POOLING_CACHE_SIZE = 10;
/** Cache of prepared statement handles */
private ConcurrentLinkedHashMap<Sha1HashKey, PreparedStatementHandle> preparedStatementHandleCache;
/** Cache of prepared statement parameter metadata */
private ConcurrentLinkedHashMap<Sha1HashKey, SQLServerParameterMetaData> parameterMetadataCache;
/**
* Checks whether statement pooling is enabled or disabled. The default is set to true;
*/
private boolean disableStatementPooling = true;

/**
* Find statement parameters.
Expand Down Expand Up @@ -925,17 +928,10 @@ final boolean attachConnId() {
connectionlogger.severe(message);
throw new UnsupportedOperationException(message);
}

// Caching turned on?
if (0 < this.getStatementPoolingCacheSize()) {
preparedStatementHandleCache = new Builder<Sha1HashKey, PreparedStatementHandle>()
.maximumWeightedCapacity(getStatementPoolingCacheSize())
.listener(new PreparedStatementCacheEvictionListener())
.build();

parameterMetadataCache = new Builder<Sha1HashKey, SQLServerParameterMetaData>()
.maximumWeightedCapacity(getStatementPoolingCacheSize())
.build();
if (!this.getDisableStatementPooling() && 0 < this.getStatementPoolingCacheSize()) {
prepareCache();
}
}

Expand Down Expand Up @@ -1437,10 +1433,8 @@ Connection connectInternal(Properties propsIn,
sPropKey = SQLServerDriverBooleanProperty.DISABLE_STATEMENT_POOLING.toString();
sPropValue = activeConnectionProperties.getProperty(sPropKey);
if (null != sPropValue) {
// If disabled set cache size to 0 if disabled.
if(booleanPropertyOn(sPropKey, sPropValue))
this.setStatementPoolingCacheSize(0);
}
setDisableStatementPooling(booleanPropertyOn(sPropKey, sPropValue));
}

sPropKey = SQLServerDriverBooleanProperty.INTEGRATED_SECURITY.toString();
sPropValue = activeConnectionProperties.getProperty(sPropKey);
Expand Down Expand Up @@ -3080,8 +3074,6 @@ final void poolCloseEventNotify() throws SQLServerException {
checkClosed();
if (catalog != null) {
connectionCommand("use " + Util.escapeSQLId(catalog), "setCatalog");
contextIsAlreadyChanged = true;
contextChanged = true;
sCatalog = catalog;
}
loggerExternal.exiting(getClassNameLogging(), "setCatalog");
Expand Down Expand Up @@ -5692,14 +5684,34 @@ final void unprepareUnreferencedPreparedStatementHandles(boolean force) {
}
}

/**
* Returns true if statement pooling is disabled.
*
* @return
*/
public boolean getDisableStatementPooling() {
return this.disableStatementPooling;
}

/**
* Sets statement pooling to true or false;
*
* @param value
*/
public void setDisableStatementPooling(boolean value) {
this.disableStatementPooling = value;
if (!value && 0 < this.getStatementPoolingCacheSize()) {
prepareCache();
}
}

/**
* Returns the size of the prepared statement cache for this connection. A value less than 1 means no cache.
* @return Returns the current setting per the description.
*/
public int getStatementPoolingCacheSize() {
return statementPoolingCacheSize;
}
}

/**
* Returns the current number of pooled prepared statement handles.
Expand All @@ -5717,25 +5729,40 @@ public int getStatementHandleCacheEntryCount() {
* @return Returns the current setting per the description.
*/
public boolean isStatementPoolingEnabled() {
return null != preparedStatementHandleCache && 0 < this.getStatementPoolingCacheSize();
return null != preparedStatementHandleCache && 0 < this.getStatementPoolingCacheSize() && !this.getDisableStatementPooling();
}

/**
* Specifies the size of the prepared statement cache for this conection. A value less than 1 means no cache.
* @param value The new cache size.
* Specifies the size of the prepared statement cache for this connection. A value less than 1 means no cache.
*
* @param value
* The new cache size.
*
*/
public void setStatementPoolingCacheSize(int value) {
if (value != this.statementPoolingCacheSize) {
value = Math.max(0, value);
statementPoolingCacheSize = value;

if (null != preparedStatementHandleCache)
preparedStatementHandleCache.setCapacity(value);
value = Math.max(0, value);
statementPoolingCacheSize = value;

if (null != parameterMetadataCache)
parameterMetadataCache.setCapacity(value);
if (!this.disableStatementPooling && value > 0) {
prepareCache();
}
if (null != preparedStatementHandleCache)
preparedStatementHandleCache.setCapacity(value);

if (null != parameterMetadataCache)
parameterMetadataCache.setCapacity(value);
}

/**
* Internal method to prepare the cache handle
* @param value
*/
private void prepareCache() {
preparedStatementHandleCache = new Builder<Sha1HashKey, PreparedStatementHandle>().maximumWeightedCapacity(getStatementPoolingCacheSize())
.listener(new PreparedStatementCacheEvictionListener()).build();

parameterMetadataCache = new Builder<Sha1HashKey, SQLServerParameterMetaData>().maximumWeightedCapacity(getStatementPoolingCacheSize())
.build();
}

/** Get a parameter metadata cache entry if statement pooling is enabled */
Expand Down Expand Up @@ -5788,12 +5815,6 @@ final void evictCachedPreparedStatementHandle(PreparedStatementHandle handle) {
preparedStatementHandleCache.remove(handle.getKey());
}

final void clearCachedPreparedStatementHandle() {
if (null != preparedStatementHandleCache) {
preparedStatementHandleCache.clear();
}
}

// Handle closing handles when removed from cache.
final class PreparedStatementCacheEvictionListener implements EvictionListener<Sha1HashKey, PreparedStatementHandle> {
public void onEviction(Sha1HashKey key, PreparedStatementHandle handle) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,6 @@ public void run() {
if (wrappedConnection.getConnectionLogger().isLoggable(Level.FINER))
wrappedConnection.getConnectionLogger().finer(toString() + " Connection proxy closed ");

// clear cached prepared statement handle on this connection
wrappedConnection.clearCachedPreparedStatementHandle();
wrappedConnection.poolCloseEventNotify();
wrappedConnection = null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ public int getServerPreparedStatementDiscardThreshold() {
}

/**
* Specifies the size of the prepared statement cache for this conection. A value less than 1 means no cache.
* Specifies the size of the prepared statement cache for this connection. A value less than 1 means no cache.
*
* @param statementPoolingCacheSize
* Changes the setting per the description.
Expand All @@ -754,14 +754,32 @@ public void setStatementPoolingCacheSize(int statementPoolingCacheSize) {
}

/**
* Returns the size of the prepared statement cache for this conection. A value less than 1 means no cache.
* Returns the size of the prepared statement cache for this connection. A value less than 1 means no cache.
*
* @return Returns the current setting per the description.
*/
public int getStatementPoolingCacheSize() {
int defaultSize = SQLServerDriverIntProperty.STATEMENT_POOLING_CACHE_SIZE.getDefaultValue();
return getIntProperty(connectionProps, SQLServerDriverIntProperty.STATEMENT_POOLING_CACHE_SIZE.toString(), defaultSize);
}

/**
* Sets the statement pooling to true or false
* @param disableStatementPooling
*/
public void setDisableStatementPooling(boolean disableStatementPooling) {
setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.DISABLE_STATEMENT_POOLING.toString(), disableStatementPooling);
}

/**
* Returns true if statement pooling is disabled.
* @return
*/
public boolean getDisableStatementPooling() {
boolean defaultValue = SQLServerDriverBooleanProperty.DISABLE_STATEMENT_POOLING.getDefaultValue();
return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.DISABLE_STATEMENT_POOLING.toString(),
defaultValue);
}

/**
* Setting the socket timeout
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ public String toString() {

enum SQLServerDriverBooleanProperty
{
DISABLE_STATEMENT_POOLING ("disableStatementPooling", false),
DISABLE_STATEMENT_POOLING ("disableStatementPooling", true),
ENCRYPT ("encrypt", false),
INTEGRATED_SECURITY ("integratedSecurity", false),
LAST_UPDATE_COUNT ("lastUpdateCount", true),
Expand Down
Loading