protected final Connection openConnectionForKey()

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;
            }
        }
    }