Beispiel #1
0
 public static ShardMapManager CreateSqlShardMapManager(
     SqlConnectionInfo connectionInfo,
     ShardMapManagerCreateMode createMode,
     RetryBehavior retryBehavior)
 {
     return(CreateSqlShardMapManagerImpl(
                connectionInfo,
                createMode,
                retryBehavior,
                null,
                GlobalConstants.GsmVersionClient));
 }
Beispiel #2
0
 /// <summary>
 /// Given a key value, obtains a SqlConnection to the shard in the mapping
 /// that contains the key value.
 /// </summary>
 /// <param name="key">Input key value.</param>
 /// <param name="connectionInfo">
 /// Connection string with credential information, the DataSource and Database are
 /// obtained from the results of the lookup operation for key.
 /// </param>
 /// <param name="options">Options for validation operations to perform on opened connection.</param>
 /// <returns>An opened SqlConnection.</returns>
 public SqlConnection OpenConnectionForKey(
     TKey key,
     SqlConnectionInfo connectionInfo,
     ConnectionOptions options = ConnectionOptions.Validate)
 {
     return(this.OpenConnectionForKey <PointMapping <TKey>, TKey>(
                key,
                (smm, sm, ssm) => new PointMapping <TKey>(smm, sm, ssm),
                ShardManagementErrorCategory.ListShardMap,
                connectionInfo,
                options));
 }
Beispiel #3
0
 /// <summary>
 /// Given a key value, asynchronously obtains a SqlConnection to the shard in the mapping
 /// that contains the key value.
 /// </summary>
 /// <param name="key">Input key value.</param>
 /// <param name="connectionString">
 /// Connection string with credential information, the DataSource and Database are
 /// obtained from the results of the lookup operation for key.
 /// </param>
 /// <param name="secureCredential">Secure SQL Credential.</param>
 /// <param name="options">Options for validation operations to perform on opened connection.</param>
 /// <returns>A Task encapsulating an opened SqlConnection.</returns>
 public async Task <SqlConnection> OpenConnectionForKeyAsync(
     TKey key,
     SqlConnectionInfo connectionInfo,
     ConnectionOptions options = ConnectionOptions.Validate)
 {
     return(await this.OpenConnectionForKeyAsync <RangeMapping <TKey>, TKey>(
                key,
                (smm, sm, ssm) => new RangeMapping <TKey>(smm, sm, ssm),
                ShardManagementErrorCategory.RangeShardMap,
                connectionInfo,
                options).ConfigureAwait(false));
 }
Beispiel #4
0
        /// <summary>
        /// Given a shard, asynchronously obtains a SqlConnection to the shard. The shard must exist in the mapper.
        /// </summary>
        /// <param name="key">Input shard.</param>
        /// <param name="connectionInfo">
        /// Connection string with credential information, the DataSource and Database are
        /// obtained from the results of the lookup operation.
        /// </param>
        /// <param name="options">Options for validation operations to perform on opened connection.</param>
        /// <returns>An opened SqlConnection.</returns>
        public async Task <SqlConnection> OpenConnectionForKeyAsync(
            Shard key,
            SqlConnectionInfo connectionInfo,
            ConnectionOptions options = ConnectionOptions.Validate)
        {
            Debug.Assert(key != null);
            Debug.Assert(connectionInfo != null);

            return(await this.ShardMap.OpenConnectionAsync(
                       this.Lookup(key, LookupOptions.LookupInCache | LookupOptions.LookupInStore),
                       connectionInfo,
                       options).ConfigureAwait(false));
        }
Beispiel #5
0
        /// <summary>
        /// Given a shard, obtains a SqlConnection to the shard. The shard must exist in the mapper.
        /// </summary>
        /// <param name="key">Input shard.</param>
        /// <param name="connectionInfo">
        /// Connection info with credential information, the DataSource and Database are
        /// obtained from the results of the lookup operation.
        /// </param>
        /// <param name="options">Options for validation operations to perform on opened connection.</param>
        /// <returns>An opened SqlConnection.</returns>
        public SqlConnection OpenConnectionForKey(
            Shard key,
            SqlConnectionInfo connectionInfo,
            ConnectionOptions options = ConnectionOptions.Validate)
        {
            Debug.Assert(key != null);
            Debug.Assert(connectionInfo != null);

            return(this.ShardMap.OpenConnection(
                       this.Lookup(key, LookupOptions.LookupInCache | LookupOptions.LookupInStore),
                       connectionInfo,
                       options));
        }
        public Task <SqlConnection> OpenConnectionForKeyAsync(
            TKey key,
            SqlConnectionInfo connectionInfo,
            ConnectionOptions options)
        {
            ExceptionUtils.DisallowNullArgument(connectionInfo, "connectionInfo");

            using (ActivityIdScope activityIdScope = new ActivityIdScope(Guid.NewGuid()))
            {
                return(_lsm.OpenConnectionForKeyAsync(
                           key,
                           connectionInfo,
                           options));
            }
        }
        /// <summary>
        /// Establishes connection to the target shard.
        /// </summary>
        private void EstablishConnnection()
        {
            // Open connection.
            SqlConnectionStringBuilder localConnectionString =
                new SqlConnectionStringBuilder(_credentials.ConnectionInfoShard.ConnectionString)
            {
                DataSource     = this.Location.DataSource,
                InitialCatalog = this.Location.Database
            };

            SqlConnectionInfo localConnectionInfo =
                _credentials.ConnectionInfoShard.CloneWithUpdatedConnectionString(
                    localConnectionString.ConnectionString);

            _localConnection = new SqlStoreConnection(
                StoreConnectionKind.LocalSource,
                localConnectionInfo);

            _localConnection.Open();
        }
Beispiel #8
0
        private static ShardMapManager GetSqlShardMapManager(
            SqlConnectionInfo connectionInfo,
            ShardMapManagerLoadPolicy loadPolicy,
            RetryBehavior retryBehavior,
            EventHandler <RetryingEventArgs> retryEventHandler)
        {
            ExceptionUtils.DisallowNullArgument(connectionInfo, "connectionInfo");
            ExceptionUtils.DisallowNullArgument(retryBehavior, "retryBehavior");

            using (ActivityIdScope activityIdScope = new ActivityIdScope(Guid.NewGuid()))
            {
                Tracer.TraceInfo(
                    TraceSourceConstants.ComponentNames.ShardMapManagerFactory,
                    "GetSqlShardMapManager",
                    "Start; ");

                Stopwatch stopwatch = Stopwatch.StartNew();

                ShardMapManager shardMapManager = ShardMapManagerFactory.GetSqlShardMapManager(
                    connectionInfo,
                    loadPolicy,
                    retryBehavior,
                    retryEventHandler,
                    true);

                stopwatch.Stop();

                Debug.Assert(shardMapManager != null);

                Tracer.TraceInfo(
                    TraceSourceConstants.ComponentNames.ShardMapManagerFactory,
                    "GetSqlShardMapManager",
                    "Complete; Duration: {0}",
                    stopwatch.Elapsed);

                return(shardMapManager);
            }
        }
Beispiel #9
0
        public static bool TryGetSqlShardMapManager(
            SqlConnectionInfo connectionInfo,
            ShardMapManagerLoadPolicy loadPolicy,
            RetryBehavior retryBehavior,
            out ShardMapManager shardMapManager)
        {
            ExceptionUtils.DisallowNullArgument(connectionInfo, "connectionInfo");
            ExceptionUtils.DisallowNullArgument(retryBehavior, "retryBehavior");

            using (ActivityIdScope activityIdScope = new ActivityIdScope(Guid.NewGuid()))
            {
                Tracer.TraceInfo(
                    TraceSourceConstants.ComponentNames.ShardMapManagerFactory,
                    "TryGetSqlShardMapManager",
                    "Start; ");

                Stopwatch stopwatch = Stopwatch.StartNew();

                shardMapManager = ShardMapManagerFactory.GetSqlShardMapManager(
                    connectionInfo,
                    loadPolicy,
                    retryBehavior,
                    null,
                    false);

                stopwatch.Stop();

                Tracer.TraceInfo(
                    TraceSourceConstants.ComponentNames.ShardMapManagerFactory,
                    "TryGetSqlShardMapManager",
                    "Complete; Duration: {0}",
                    stopwatch.Elapsed);

                return(shardMapManager != null);
            }
        }
 /// <summary>
 /// Constructs a new instance of user connection.
 /// </summary>
 /// <param name="connectionInfo">Connection info.</param>
 /// <returns>An unopened instance of the user connection.</returns>
 public virtual IUserStoreConnection GetUserConnection(SqlConnectionInfo connectionInfo)
 {
     return(new SqlUserStoreConnection(connectionInfo));
 }
 /// <summary>
 /// Constructs a new instance of store connection.
 /// </summary>
 /// <param name="kind">Type of store connection.</param>
 /// <param name="connectionInfo">Connection info.</param>
 /// <returns>An unopened instance of the store connection.</returns>
 public virtual IStoreConnection GetConnection(
     StoreConnectionKind kind,
     SqlConnectionInfo connectionInfo)
 {
     return(new SqlStoreConnection(kind, connectionInfo));
 }
Beispiel #12
0
        private static ShardMapManager CreateSqlShardMapManagerImpl(
            SqlConnectionInfo connectionInfo,
            ShardMapManagerCreateMode createMode,
            RetryBehavior retryBehavior,
            EventHandler <RetryingEventArgs> retryEventHandler,
            Version targetVersion)
        {
            ExceptionUtils.DisallowNullArgument(connectionInfo, "connectionInfo");
            ExceptionUtils.DisallowNullArgument(retryBehavior, "retryBehavior");

            if (createMode != ShardMapManagerCreateMode.KeepExisting &&
                createMode != ShardMapManagerCreateMode.ReplaceExisting)
            {
                throw new ArgumentException(
                          StringUtils.FormatInvariant(
                              Errors._General_InvalidArgumentValue,
                              createMode,
                              "createMode"),
                          "createMode");
            }

            using (ActivityIdScope activityIdScope = new ActivityIdScope(Guid.NewGuid()))
            {
                Tracer.TraceInfo(
                    TraceSourceConstants.ComponentNames.ShardMapManagerFactory,
                    "CreateSqlShardMapManager",
                    "Start; ");

                Stopwatch stopwatch = Stopwatch.StartNew();

                SqlShardMapManagerCredentials credentials = new SqlShardMapManagerCredentials(connectionInfo);

                TransientFaultHandling.RetryPolicy retryPolicy = new TransientFaultHandling.RetryPolicy(
                    new ShardManagementTransientErrorDetectionStrategy(retryBehavior),
                    RetryPolicy.DefaultRetryPolicy.GetRetryStrategy());

                EventHandler <TransientFaultHandling.RetryingEventArgs> handler = (sender, args) =>
                {
                    if (retryEventHandler != null)
                    {
                        retryEventHandler(sender, new RetryingEventArgs(args));
                    }
                };

                try
                {
                    retryPolicy.Retrying += handler;

                    // specifying targetVersion as GlobalConstants.GsmVersionClient to deploy latest store by default.
                    using (IStoreOperationGlobal op = new StoreOperationFactory().CreateCreateShardMapManagerGlobalOperation(
                               credentials,
                               retryPolicy,
                               "CreateSqlShardMapManager",
                               createMode,
                               targetVersion))
                    {
                        op.Do();
                    }

                    stopwatch.Stop();

                    Tracer.TraceInfo(
                        TraceSourceConstants.ComponentNames.ShardMapManagerFactory,
                        "CreateSqlShardMapManager",
                        "Complete; Duration: {0}",
                        stopwatch.Elapsed);
                }
                finally
                {
                    retryPolicy.Retrying -= handler;
                }

                return(new ShardMapManager(
                           credentials,
                           new SqlStoreConnectionFactory(),
                           new StoreOperationFactory(),
                           new CacheStore(),
                           ShardMapManagerLoadPolicy.Lazy,
                           RetryPolicy.DefaultRetryPolicy,
                           retryBehavior,
                           retryEventHandler));
            }
        }
        /// <summary>
        /// Given a key value, asynchronously obtains a SqlConnection to the shard in the mapping
        /// that contains the key value.
        /// </summary>
        /// <typeparam name="TMapping">Mapping type.</typeparam>
        /// <typeparam name="TKey">Key type.</typeparam>
        /// <param name="key">Input key value.</param>
        /// <param name="constructMapping">Delegate to construct a mapping object.</param>
        /// <param name="errorCategory">Error category.</param>
        /// <param name="connectionInfo">
        /// Connection info with credential information, the DataSource and Database are
        /// obtained from the results of the lookup operation for key.
        /// </param>
        /// <param name="options">Options for validation operations to perform on opened connection.</param>
        /// <returns>A task encapsulating an opened SqlConnection as the result.</returns>
        protected async Task <SqlConnection> OpenConnectionForKeyAsync <TMapping, TKey>(
            TKey key,
            Func <ShardMapManager, ShardMap, IStoreMapping, TMapping> constructMapping,
            ShardManagementErrorCategory errorCategory,
            SqlConnectionInfo connectionInfo,
            ConnectionOptions options = ConnectionOptions.Validate) where TMapping : class, IShardProvider
        {
            ShardKey sk = new ShardKey(ShardKey.ShardKeyTypeFromType(typeof(TKey)), key);

            // Try to find the mapping within the cache.
            ICacheStoreMapping csm = this.Manager.Cache.LookupMappingByKey(this.ShardMap.StoreShardMap, sk);

            IStoreMapping sm;

            if (csm != null)
            {
                sm = csm.Mapping;
            }
            else
            {
                sm = await this.LookupMappingForOpenConnectionForKeyAsync(
                    sk,
                    CacheStoreMappingUpdatePolicy.OverwriteExisting,
                    errorCategory).ConfigureAwait(false);
            }

            SqlConnection result;
            bool          lookupMappingOnEx = false;
            CacheStoreMappingUpdatePolicy cacheUpdatePolicyOnEx = CacheStoreMappingUpdatePolicy.OverwriteExisting;

            try
            {
                // Initially attempt to connect based on lookup results from either cache or GSM.
                result = await this.ShardMap.OpenConnectionAsync(
                    constructMapping(this.Manager, this.ShardMap, sm),
                    connectionInfo,
                    options).ConfigureAwait(false);

                csm.ResetTimeToLiveIfNecessary();

                return(result);
            }
            catch (ShardManagementException smme)
            {
                // If we hit a validation failure due to stale version of mapping, we will perform one more attempt.
                if (((options & ConnectionOptions.Validate) == ConnectionOptions.Validate) &&
                    smme.ErrorCategory == ShardManagementErrorCategory.Validation &&
                    smme.ErrorCode == 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.
                    lookupMappingOnEx     = true;
                    cacheUpdatePolicyOnEx = CacheStoreMappingUpdatePolicy.OverwriteExisting;
                }
                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;
                }
            }
            catch (SqlException)
            {
                // We failed to connect. If we were trying to connect from an entry in cache and mapping expired in cache.
                if (csm != null && csm.HasTimeToLiveExpired())
                {
                    using (IdLock _idLock = new IdLock(csm.Mapping.StoreShard.Id))
                    {
                        // 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 = this.Manager.Cache.LookupMappingByKey(this.ShardMap.StoreShardMap, sk);

                        // Only go to store if the mapping is stale even after refresh.
                        if (csm == null || csm.HasTimeToLiveExpired())
                        {
                            // Refresh the mapping in cache. And try to open the connection after refresh.
                            lookupMappingOnEx     = true;
                            cacheUpdatePolicyOnEx = CacheStoreMappingUpdatePolicy.UpdateTimeToLive;
                        }
                        else
                        {
                            sm = csm.Mapping;
                        }
                    }
                }
                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;
                }
            }

            if (lookupMappingOnEx)
            {
                sm = await this.LookupMappingForOpenConnectionForKeyAsync(
                    sk,
                    cacheUpdatePolicyOnEx,
                    errorCategory).ConfigureAwait(false);
            }

            // One last attempt to open the connection after a cache refresh
            result = await this.ShardMap.OpenConnectionAsync(
                constructMapping(this.Manager, this.ShardMap, sm),
                connectionInfo,
                options).ConfigureAwait(false);

            // Reset TTL on successful connection.
            csm.ResetTimeToLiveIfNecessary();

            return(result);
        }
        /// <summary>
        /// Ensures that the provided connection string is valid and builds the connection string
        /// to be used for DDR connection to the given shard provider.
        /// </summary>
        /// <param name="shardProvider">Shard provider containing shard to be connected to.</param>
        /// <param name="connectionInfo">Input connection info.</param>
        /// <returns>Connection string for DDR connection.</returns>
        private SqlConnectionInfo ValidateAndPrepareConnectionString(
            IShardProvider shardProvider,
            SqlConnectionInfo connectionInfo)
        {
            Debug.Assert(shardProvider != null);
            Debug.Assert(connectionInfo != null);
            Debug.Assert(connectionInfo.ConnectionString != null);

            // Devnote: If connection string specifies Active Directory authentication and runtime is not
            // .NET 4.6 or higher, then below call will throw.
            SqlConnectionStringBuilder connectionStringBuilder = new SqlConnectionStringBuilder(connectionInfo.ConnectionString);

            // DataSource must not be set.
            if (!string.IsNullOrEmpty(connectionStringBuilder.DataSource))
            {
                throw new ArgumentException(
                          StringUtils.FormatInvariant(
                              Errors._ShardMap_OpenConnection_ConnectionStringPropertyDisallowed,
                              "DataSource"),
                          "connectionString");
            }

            // InitialCatalog must not be set.
            if (!string.IsNullOrEmpty(connectionStringBuilder.InitialCatalog))
            {
                throw new ArgumentException(
                          StringUtils.FormatInvariant(
                              Errors._ShardMap_OpenConnection_ConnectionStringPropertyDisallowed,
                              "Initial Catalog"),
                          "connectionString");
            }

            // ConnectRetryCount must not be set (default value is 1)
            if (ShardMapUtils.IsConnectionResiliencySupported && (int)connectionStringBuilder[ShardMapUtils.ConnectRetryCount] > 1)
            {
                throw new ArgumentException(
                          StringUtils.FormatInvariant(
                              Errors._ShardMap_OpenConnection_ConnectionStringPropertyDisallowed,
                              ShardMapUtils.ConnectRetryCount),
                          "connectionString");
            }

            // Verify that either UserID/Password or provided or integrated authentication is enabled.
            SqlShardMapManagerCredentials.EnsureCredentials(
                connectionStringBuilder,
                "connectionString",
                connectionInfo.Credential,
                connectionInfo.AccessTokenFactory);

            Shard s = shardProvider.ShardInfo;

            connectionStringBuilder.DataSource     = s.Location.DataSource;
            connectionStringBuilder.InitialCatalog = s.Location.Database;

            // Append the proper post-fix for ApplicationName
            connectionStringBuilder.ApplicationName = ApplicationNameHelper.AddApplicationNameSuffix(
                connectionStringBuilder.ApplicationName,
                this.ApplicationNameSuffix);

            // Disable connection resiliency if necessary
            if (ShardMapUtils.IsConnectionResiliencySupported)
            {
                connectionStringBuilder[ShardMapUtils.ConnectRetryCount] = 0;
            }

            return(connectionInfo.CloneWithUpdatedConnectionString(connectionStringBuilder.ConnectionString));
        }
Beispiel #15
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SqlStoreConnection"/> class.
 /// </summary>
 /// <param name="kind">
 /// Type of store connection.
 /// </param>
 /// <param name="connectionInfo">
 /// The connection info.
 /// </param>
 protected internal SqlStoreConnection(StoreConnectionKind kind, SqlConnectionInfo connectionInfo)
 {
     this.Kind  = kind;
     this._conn = connectionInfo.CreateConnection();
 }
 /// <summary>
 /// Creates a new instance of user store connection.
 /// </summary>
 /// <param name="connectionInfo">Connection info.</param>
 internal SqlUserStoreConnection(SqlConnectionInfo connectionInfo)
 {
     _conn = connectionInfo.CreateConnection();
 }
Beispiel #17
0
        /// <summary>
        /// Instantiates the object that holds the credentials for accessing SQL Servers
        /// containing the shard map manager data.
        /// </summary>
        /// <param name="connectionInfo">
        /// Connection info for shard map manager data source.
        /// </param>
        public SqlShardMapManagerCredentials(SqlConnectionInfo connectionInfo)
        {
            ExceptionUtils.DisallowNullArgument(connectionInfo, "connectionInfo");

            // Devnote: If connection string specifies Active Directory authentication and runtime is not
            // .NET 4.6 or higher, then below call will throw.
            SqlConnectionStringBuilder connectionStringBuilder = new SqlConnectionStringBuilder(connectionInfo.ConnectionString);

            #region GSM Validation

            // DataSource must be set.
            if (string.IsNullOrEmpty(connectionStringBuilder.DataSource))
            {
                throw new ArgumentException(
                          StringUtils.FormatInvariant(
                              Errors._SqlShardMapManagerCredentials_ConnectionStringPropertyRequired,
                              "DataSource"),
                          "connectionString");
            }

            // InitialCatalog must be set.
            if (string.IsNullOrEmpty(connectionStringBuilder.InitialCatalog))
            {
                throw new ArgumentException(
                          StringUtils.FormatInvariant(
                              Errors._SqlShardMapManagerCredentials_ConnectionStringPropertyRequired,
                              "Initial Catalog"),
                          "connectionString");
            }

            // Ensure credentials are specified for GSM connectivity.
            SqlShardMapManagerCredentials.EnsureCredentials(
                connectionStringBuilder,
                "connectionString",
                connectionInfo.Credential,
                connectionInfo.AccessTokenFactory);

            #endregion GSM Validation

            // Generate connectionInfoShardMapManager
            SqlConnectionStringBuilder connectionStringShardMapManager = new SqlConnectionStringBuilder(connectionStringBuilder.ConnectionString);

            connectionStringShardMapManager.ApplicationName = ApplicationNameHelper.AddApplicationNameSuffix(
                connectionStringShardMapManager.ApplicationName,
                GlobalConstants.ShardMapManagerInternalConnectionSuffixGlobal);

            _smmDataSource     = connectionStringShardMapManager.DataSource;
            _smmInitialCatalog = connectionStringShardMapManager.InitialCatalog;

            this.ConnectionInfoShardMapManager =
                connectionInfo.CloneWithUpdatedConnectionString(connectionStringShardMapManager.ConnectionString);

            // Generate connectionInfoShard
            SqlConnectionStringBuilder connectionStringShard = new SqlConnectionStringBuilder(connectionStringBuilder.ConnectionString);

            connectionStringShard.Remove("Data Source");
            connectionStringShard.Remove("Initial Catalog");

            connectionStringShard.ApplicationName = ApplicationNameHelper.AddApplicationNameSuffix(
                connectionStringShard.ApplicationName,
                GlobalConstants.ShardMapManagerInternalConnectionSuffixLocal);

            this.ConnectionInfoShard =
                connectionInfo.CloneWithUpdatedConnectionString(connectionStringShard.ConnectionString);
        }