in elastic-db-tools/src/main/java/com/microsoft/azure/elasticdb/shard/mapper/BaseShardMapper.java [194:286]
protected final <MappingT extends IShardProvider, KeyT> Connection openConnectionForKey(KeyT key,
ActionGeneric3Param<ShardMapManager, ShardMap, StoreMapping, MappingT> constructMapping,
ShardManagementErrorCategory errorCategory,
String connectionString,
ConnectionOptions options) {
ShardKey sk = new ShardKey(ShardKey.shardKeyTypeFromType(key.getClass()), key);
// Try to find the mapping within the cache.
ICacheStoreMapping csm = shardMapManager.getCache().lookupMappingByKey(shardMap.getStoreShardMap(), sk);
StoreMapping sm;
if (csm != null) {
sm = csm.getMapping();
}
else {
sm = this.lookupMappingForOpenConnectionForKey(sk, CacheStoreMappingUpdatePolicy.OverwriteExisting, errorCategory);
}
Connection result;
try {
// Initially attempt to connect based on lookup results from either cache or GSM.
result = shardMap.openConnection(constructMapping.invoke(this.getShardMapManager(), this.getShardMap(), sm), connectionString, options);
// Reset TTL on successful connection.
if (csm != null && csm.getTimeToLiveMilliseconds() > 0) {
csm.resetTimeToLive();
}
return result;
}
catch (ShardManagementException ex) {
// If we hit a validation failure due to stale version of mapping,
// we will perform one more attempt.
if (((options.getValue() & ConnectionOptions.Validate.getValue()) == ConnectionOptions.Validate.getValue())
&& ex.getErrorCategory() == ShardManagementErrorCategory.Validation
&& ex.getErrorCode() == ShardManagementErrorCode.MappingDoesNotExist) {
// Assumption here is that this time the attempt should succeed since the cache entry
// has already been either evicted, or updated based on latest data from the server.
sm = this.lookupMappingForOpenConnectionForKey(sk, CacheStoreMappingUpdatePolicy.OverwriteExisting, errorCategory);
result = shardMap.openConnection(constructMapping.invoke(this.getShardMapManager(), this.getShardMap(), sm), connectionString,
options);
return result;
}
else {
// The error was not due to validation but something else e.g.
// 1) Shard map does not exist
// 2) Mapping could not be found.
throw ex;
}
}
catch (Exception e) {
// We failed to connect.
// If we were trying to connect from an entry in cache and mapping expired in cache.
if (csm != null && (System.nanoTime() - csm.getCreationTime()) >= csm.getTimeToLiveMilliseconds()) {
try (IdLock _idLock = new IdLock(csm.getMapping().getStoreShard().getId())) {
// Similar to DCL pattern, we need to refresh the mapping again to see if we still need to
// go to the store to lookup the mapping after acquiring the shard lock. It might be the
// case that a fresh version has already been obtained by some other thread.
csm = shardMapManager.getCache().lookupMappingByKey(shardMap.getStoreShardMap(), sk);
// Only go to store if the mapping is stale even after refresh.
if (csm == null || (System.nanoTime() - csm.getCreationTime()) >= csm.getTimeToLiveMilliseconds()) {
// Refresh the mapping in cache. And try to open the connection after refresh.
sm = this.lookupMappingForOpenConnectionForKey(sk, CacheStoreMappingUpdatePolicy.UpdateTimeToLive, errorCategory);
}
else {
sm = csm.getMapping();
}
}
catch (IOException e1) {
e1.printStackTrace();
}
result = shardMap.openConnection(constructMapping.invoke(this.getShardMapManager(), this.getShardMap(), sm), connectionString,
options);
// Reset TTL on successful connection.
if (csm != null && csm.getTimeToLiveMilliseconds() > 0) {
csm.resetTimeToLive();
}
return result;
}
else {
// Either:
// 1) The mapping is still within the TTL. No refresh.
// 2) Mapping was not in cache, we originally did a lookup for mapping in GSM
// and even then could not connect.
throw e;
}
}
}