/// <summary>
        /// Adds an order to the orders table for the customer.
        /// </summary>
        private static void AddOrder(
            ShardMap shardMap,
            string credentialsConnectionString,
            int customerId,
            int productId)
        {
            SqlDatabaseUtils.SqlRetryPolicy.ExecuteAction(() =>
            {
                // Looks up the key in the shard map and opens a connection to the shard
                using (SqlConnection conn = shardMap.OpenConnectionForKey(customerId, credentialsConnectionString))
                {
                    // Create a simple command that will insert a new order
                    SqlCommand cmd = conn.CreateCommand();

                    // Create a simple command
                    cmd.CommandText = @"INSERT INTO dbo.Orders (CustomerId, OrderDate, ProductId)
                                        VALUES (@customerId, @orderDate, @productId)";
                    cmd.Parameters.AddWithValue("@customerId", customerId);
                    cmd.Parameters.AddWithValue("@orderDate", DateTime.Now.Date);
                    cmd.Parameters.AddWithValue("@productId", productId);
                    cmd.CommandTimeout = 60;

                    // Execute the command
                    cmd.ExecuteNonQuery();
                }
            });

            ConsoleUtils.WriteInfo("Inserted order for customer ID: {0}", customerId);
        }
        /// <summary>
        /// Adds a customer to the customers table (or updates the customer if that id already exists).
        /// </summary>
        private static void AddCustomer(
            ShardMap shardMap,
            string credentialsConnectionString,
            int customerId,
            string name,
            int regionId)
        {
            // Open and execute the command with retry for transient faults. Note that if the command fails, the connection is closed, so
            // the entire block is wrapped in a retry. This means that only one command should be executed per block, since if we had multiple
            // commands then the first command may be executed multiple times if later commands fail.
            SqlDatabaseUtils.SqlRetryPolicy.ExecuteAction(() =>
            {
                // Looks up the key in the shard map and opens a connection to the shard
                using (SqlConnection conn = shardMap.OpenConnectionForKey(customerId, credentialsConnectionString))
                {
                    // Create a simple command that will insert or update the customer information
                    SqlCommand cmd = conn.CreateCommand();
                    cmd.CommandText = @"
                    IF EXISTS (SELECT 1 FROM Customers WHERE CustomerId = @customerId)
                        UPDATE Customers
                            SET Name = @name, RegionId = @regionId
                            WHERE CustomerId = @customerId
                    ELSE
                        INSERT INTO Customers (CustomerId, Name, RegionId)
                        VALUES (@customerId, @name, @regionId)";
                    cmd.Parameters.AddWithValue("@customerId", customerId);
                    cmd.Parameters.AddWithValue("@name", name);
                    cmd.Parameters.AddWithValue("@regionId", regionId);
                    cmd.CommandTimeout = 60;

                    // Execute the command
                    cmd.ExecuteNonQuery();
                }
            });
        }
예제 #3
0
        public Shard CreateOrGet(ShardMap shardMap, string server, string database)
        {
            var location    = new ShardLocation(server, database);
            var shardExists = shardMap.TryGetShard(location, out var shard);

            return(shardExists ? shard : shardMap.CreateShard(location));
        }
예제 #4
0
        public void CreateShardDefault()
        {
            ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager(
                Globals.ShardMapManagerConnectionString,
                ShardMapManagerLoadPolicy.Lazy);

            ShardMap sm = smm.GetShardMap(ShardMapTests.s_defaultShardMapName);

            Assert.IsNotNull(sm);

            ShardLocation sl = new ShardLocation(
                Globals.ShardMapManagerTestsDatasourceName,
                ShardMapTests.s_shardedDBs[0],
                SqlProtocol.Tcp,
                1433);

            Shard sNew = sm.CreateShard(sl);

            Assert.IsNotNull(sNew);

            // Validate that the shard location is round-tripped correctly
            Assert.AreEqual(sl, sNew.Location);
            Assert.AreEqual(sl, sm.GetShard(sl).Location);

            // Validate that we can connect to the shard
            using (SqlConnection conn = sNew.OpenConnection(
                       Globals.ShardUserConnectionString,
                       ConnectionOptions.Validate))
            {
            }
        }
예제 #5
0
        public void CreateRangeShardMapDefault()
        {
            CountingCacheStore cacheStore =
                new CountingCacheStore(
                    new CacheStore());

            ShardMapManager smm = new ShardMapManager(
                new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString),
                new SqlStoreConnectionFactory(),
                new StoreOperationFactory(),
                cacheStore,
                ShardMapManagerLoadPolicy.Lazy,
                RetryPolicy.DefaultRetryPolicy,
                RetryBehavior.DefaultRetryBehavior);

            RangeShardMap <int> rsm = smm.CreateRangeShardMap <int>(ShardMapManagerTests.s_shardMapName);

            Assert.IsNotNull(rsm);
            Assert.AreEqual(ShardMapManagerTests.s_shardMapName, rsm.Name);

            ShardMap smLookup = smm.LookupShardMapByName("LookupShardMapByName", ShardMapManagerTests.s_shardMapName, true);

            Assert.IsNotNull(smLookup);
            Assert.AreEqual(ShardMapManagerTests.s_shardMapName, smLookup.Name);
            Assert.AreEqual(1, cacheStore.LookupShardMapCount);
            Assert.AreEqual(1, cacheStore.LookupShardMapHitCount);
        }
        /// <summary>
        /// Adds a customer to the customers table (or updates the customer if that id already exists).
        /// </summary>
        private static void AddCustomer(
            ShardMap shardMap,
            string credentialsConnectionString,
            int customerId,
            string name,
            int regionId)
        {
            // Open and execute the command with retry for transient faults. Note that if the command fails, the connection is closed, so
            // the entire block is wrapped in a retry. This means that only one command should be executed per block, since if we had multiple
            // commands then the first command may be executed multiple times if later commands fail.
            SqlDatabaseUtils.SqlRetryPolicy.ExecuteAction(() =>
            {
                // Looks up the key in the shard map and opens a connection to the shard
                using (SqlConnection conn = shardMap.OpenConnectionForKey(customerId, credentialsConnectionString))
                {
                    // Create a simple command that will insert or update the customer information
                    SqlCommand cmd  = conn.CreateCommand();
                    cmd.CommandText = @"
                    IF EXISTS (SELECT 1 FROM Customers WHERE CustomerId = @customerId)
                        UPDATE Customers
                            SET Name = @name, RegionId = @regionId
                            WHERE CustomerId = @customerId
                    ELSE
                        INSERT INTO Customers (CustomerId, Name, RegionId)
                        VALUES (@customerId, @name, @regionId)";
                    cmd.Parameters.AddWithValue("@customerId", customerId);
                    cmd.Parameters.AddWithValue("@name", name);
                    cmd.Parameters.AddWithValue("@regionId", regionId);
                    cmd.CommandTimeout = 60;

                    // Execute the command
                    cmd.ExecuteNonQuery();
                }
            });
        }
        /// <summary>
        /// Wrapper function for ShardMap.OpenConnectionForKey() that automatically sets CONTEXT_INFO to the correct
        /// tenantId before returning a connection. As a best practice, you should only open connections using this
        /// method to ensure that CONTEXT_INFO is always set before executing a query.
        /// </summary>
        public static SqlConnection OpenDDRConnection(ShardMap shardMap, T shardingKey, string connectionStr)
        {
            // No initialization
            Database.SetInitializer <ElasticScaleContext <T> >(null);

            // Ask shard map to broker a validated connection for the given key
            SqlConnection conn = null;

            try
            {
                conn = shardMap.OpenConnectionForKey(shardingKey, connectionStr, ConnectionOptions.Validate);

                // Set CONTEXT_INFO to shardingKey to enable Row-Level Security filtering
                SqlCommand cmd = conn.CreateCommand();
                cmd.CommandText = @"SET CONTEXT_INFO @shardingKey";
                cmd.Parameters.AddWithValue("@shardingKey", shardingKey);
                cmd.ExecuteNonQuery();

                return(conn);
            }
            catch (Exception)
            {
                if (conn != null)
                {
                    conn.Dispose();
                }

                throw;
            }
        }
예제 #8
0
        public void GetShardMapsDefault()
        {
            ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager(
                Globals.ShardMapManagerConnectionString,
                ShardMapManagerLoadPolicy.Lazy);

            ShardMap sm = smm.CreateListShardMap <int>(ShardMapManagerTests.s_shardMapName);

            Assert.IsNotNull(sm);

            Assert.AreEqual(ShardMapManagerTests.s_shardMapName, sm.Name);

            IEnumerable <ShardMap> shardmaps = smm.GetShardMaps();

            int count = 0;

            using (IEnumerator <ShardMap> mEnum = shardmaps.GetEnumerator())
            {
                while (mEnum.MoveNext())
                {
                    count++;
                }
            }
            Assert.AreEqual(1, count);
        }
        /// <summary>
        /// Helper function to do validation,this will be called using TFH retry policy.
        /// </summary>
        /// <param name="sm">Shard map for a mapping to validate</param>
        /// <param name="key">Key to lookup and validate</param>
        private static void ValidateImpl(ShardMap sm, int key)
        {
            try
            {
                using (SqlConnection conn = sm.OpenConnectionForKey(key,
                                                                    Globals.ShardUserConnectionString,
                                                                    ConnectionOptions.Validate))
                {
                }
            }
            catch (SqlException e)
            {
                // Error Number 3980: The request failed to run because the batch is aborted, this can be caused by abort signal sent from client, or another request is running in the same session, which makes the session busy.
                // Error Number = 0, Class = 20, Message = The connection is broken and recovery is not possible.  The connection is marked by the server as unrecoverable.  No attempt was made to restore the connection.
                // Error Number = 0, Class = 11, Message = A severe error occurred on the current command.  The results, if any, should be discarded.
                switch (e.Number)
                {
                case 0:
                    if (e.Class != 20 && e.Class != 11)
                    {
                        throw;
                    }
                    break;

                case 3980:
                    break;

                default:
                    throw;
                }
            }
        }
        /// <summary>
        /// Adds a customer to the customers table (or updates the customer if that id already exists).
        /// </summary>
        private static void AddCustomer(
            ShardMap shardMap,
            string credentialsConnectionString,
            int customerId,
            string name,
            int regionId)
        {
            //失敗的話重試
            SqlDatabaseUtils.SqlRetryPolicy.ExecuteAction(() =>
            {
                // 依據 Key 判斷要取回哪個 Shard
                using (SqlConnection conn = shardMap.OpenConnectionForKey(customerId, credentialsConnectionString))
                {
                    // 產生 Command
                    SqlCommand cmd = conn.CreateCommand();
                    cmd.CommandText = @"
                    IF EXISTS (SELECT 1 FROM Customers WHERE CustomerId = @customerId)
                        UPDATE Customers
                            SET Name = @name, RegionId = @regionId
                            WHERE CustomerId = @customerId
                    ELSE
                        INSERT INTO Customers (CustomerId, Name, RegionId)
                        VALUES (@customerId, @name, @regionId)";
                    cmd.Parameters.AddWithValue("@customerId", customerId);
                    cmd.Parameters.AddWithValue("@name", name);
                    cmd.Parameters.AddWithValue("@regionId", regionId);
                    cmd.CommandTimeout = 60;

                    // Execute the command
                    cmd.ExecuteNonQuery();
                }
            });
        }
예제 #11
0
        public void CreateRangeShardMapDuplicate()
        {
            ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager(
                Globals.ShardMapManagerConnectionString,
                ShardMapManagerLoadPolicy.Lazy);

            ShardMap sm = smm.CreateRangeShardMap <int>(ShardMapManagerTests.s_shardMapName);

            Assert.IsNotNull(sm);

            Assert.AreEqual(ShardMapManagerTests.s_shardMapName, sm.Name);

            bool creationFailed = false;

            try
            {
                RangeShardMap <int> rsm = smm.CreateRangeShardMap <int>(ShardMapManagerTests.s_shardMapName);
            }
            catch (ShardManagementException sme)
            {
                Assert.AreEqual(ShardManagementErrorCategory.ShardMapManager, sme.ErrorCategory);
                Assert.AreEqual(ShardManagementErrorCode.ShardMapAlreadyExists, sme.ErrorCode);
                creationFailed = true;
            }

            Assert.IsTrue(creationFailed);
        }
예제 #12
0
        public void DeleteShardDuplicate()
        {
            ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager(
                Globals.ShardMapManagerConnectionString,
                ShardMapManagerLoadPolicy.Lazy);

            ShardMap sm = smm.GetShardMap(ShardMapTests.s_defaultShardMapName);

            Assert.IsNotNull(sm);

            ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapTests.s_shardedDBs[0]);

            Shard sNew = sm.CreateShard(sl);

            Assert.IsNotNull(sNew);

            sm.DeleteShard(sNew);

            Assert.IsNotNull(sNew);

            bool removeFailed = false;

            try
            {
                sm.DeleteShard(sNew);
            }
            catch (ShardManagementException sme)
            {
                Assert.AreEqual(ShardManagementErrorCategory.ShardMap, sme.ErrorCategory);
                Assert.AreEqual(ShardManagementErrorCode.ShardDoesNotExist, sme.ErrorCode);
                removeFailed = true;
            }

            Assert.IsTrue(removeFailed);
        }
예제 #13
0
        public void UpgradeGSM()
        {
            // Get shard map manager
            ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager(
                Globals.ShardMapManagerConnectionString,
                ShardMapManagerLoadPolicy.Lazy);

            try
            {
                ShardMap testsm = smm.CreateListShardMap <int>(ShardMapManagerUpgradeTests.s_shardMapNames[0]);
                Assert.IsNotNull(testsm);
            }
            catch (ShardManagementException sme)
            {
                Assert.AreEqual(ShardManagementErrorCode.GlobalStoreVersionMismatch, sme.ErrorCode);
            }

            // Upgrade to version 1.0: no-op
            smm.UpgradeGlobalStore(new Version(1, 0));

            // Upgrade to version 1.1
            smm.UpgradeGlobalStore(new Version(1, 1));

            // Below call should succeed as latest supported major version of library matches major version of deployed store.
            ShardMap sm = smm.CreateListShardMap <int>(ShardMapManagerUpgradeTests.s_shardMapNames[0]);

            Assert.IsNotNull(sm);

            // Upgrade to version 1.2
            smm.UpgradeGlobalStore(new Version(1, 2));

            // Upgrade to latest version (1.2): no-op
            smm.UpgradeGlobalStore();
        }
예제 #14
0
        public void AddListShardMapNoCacheUpdate()
        {
            // Create a cache store that always misses.
            CountingCacheStore cacheStore =
                new CountingCacheStore(
                    new StubCacheStore()
            {
                CallBase = true,
                LookupMappingByKeyIStoreShardMapShardKey = (ssm, sk) => null,
                LookupShardMapByNameString = (n) => null
            });

            ShardMapManager smm = new ShardMapManager(
                new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString),
                new SqlStoreConnectionFactory(),
                new StoreOperationFactory(),
                cacheStore,
                ShardMapManagerLoadPolicy.Lazy,
                RetryPolicy.DefaultRetryPolicy, RetryBehavior.DefaultRetryBehavior);

            ShardMap sm = smm.CreateListShardMap <int>(ShardMapManagerTests.s_shardMapName);

            Assert.IsNotNull(sm);
            Assert.AreEqual(ShardMapManagerTests.s_shardMapName, sm.Name);
            Assert.AreEqual(1, cacheStore.AddShardMapCount);
            cacheStore.ResetCounters();

            ShardMap smLookup = smm.LookupShardMapByName("LookupShardMapByName", ShardMapManagerTests.s_shardMapName, true);

            Assert.IsNotNull(smLookup);
            Assert.AreEqual(1, cacheStore.AddShardMapCount);
            Assert.AreEqual(1, cacheStore.LookupShardMapMissCount);
        }
예제 #15
0
        public void RemoveListShardMapNoCacheUpdate()
        {
            // Counting store that does not perform deletions of shard maps.
            CountingCacheStore cacheStore =
                new CountingCacheStore(
                    new StubCacheStore()
            {
                CallBase = true,
                DeleteShardMapIStoreShardMap = (csm) => { }
            }
                    );

            ShardMapManager smm = new ShardMapManager(
                new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString),
                new SqlStoreConnectionFactory(),
                new StoreOperationFactory(),
                cacheStore,
                ShardMapManagerLoadPolicy.Lazy,
                RetryPolicy.DefaultRetryPolicy, RetryBehavior.DefaultRetryBehavior);

            ShardMap sm = smm.CreateListShardMap <int>(ShardMapManagerTests.s_shardMapName);

            Assert.IsNotNull(sm);

            Assert.AreEqual(ShardMapManagerTests.s_shardMapName, sm.Name);

            smm.DeleteShardMap(sm);

            Assert.AreEqual(1, cacheStore.DeleteShardMapCount);

            ShardMap smLookup = smm.LookupShardMapByName("LookupShardMapByName", ShardMapManagerTests.s_shardMapName, true);

            Assert.IsNotNull(smLookup);
            Assert.AreEqual(1, cacheStore.LookupShardMapHitCount);
        }
예제 #16
0
        public void ValidateShard()
        {
            ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager(
                Globals.ShardMapManagerConnectionString,
                ShardMapManagerLoadPolicy.Lazy);

            ShardMap sm = smm.GetShardMap(ShardMapTests.s_defaultShardMapName);

            Assert.IsNotNull(sm);

            ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapTests.s_shardedDBs[0]);

            Shard sNew = sm.CreateShard(new ShardCreationInfo(sl, ShardStatus.Online));

            ShardUpdate su = new ShardUpdate();

            su.Status = ShardStatus.Offline;

            Shard sUpdated = sm.UpdateShard(sNew, su);

            Assert.IsNotNull(sUpdated);

            bool validationFailed = false;

            try
            {
                using (SqlConnection conn = sNew.OpenConnection(
                           Globals.ShardUserConnectionString,
                           ConnectionOptions.Validate))
                {
                }
            }
            catch (ShardManagementException sme)
            {
                validationFailed = true;
                Assert.AreEqual(ShardManagementErrorCategory.Validation, sme.ErrorCategory);
                Assert.AreEqual(ShardManagementErrorCode.ShardVersionMismatch, sme.ErrorCode);
            }

            Assert.IsTrue(validationFailed);

            validationFailed = false;

            try
            {
                using (SqlConnection conn = sUpdated.OpenConnection(
                           Globals.ShardUserConnectionString,
                           ConnectionOptions.Validate))
                {
                }
            }
            catch (ShardManagementException)
            {
                validationFailed = true;
            }

            Assert.IsFalse(validationFailed);
        }
예제 #17
0
        // Only static methods are allowed in calls into base class c'tors
        private static DbConnection CreateDDRConnection(ShardMap shardMap, T shardingKey, string connectionStr)
        {
            // No initialization
            Database.SetInitializer <ElasticScaleContext <T> >(null);

            // Ask shard map to broker a validated connection for the given key
            SqlConnection conn = shardMap.OpenConnectionForKey <T>(shardingKey, connectionStr, ConnectionOptions.Validate);

            return(conn);
        }
예제 #18
0
        private static DbConnection CreateDdrConnection(ShardMap shardMap, int shardingKey, string connectionStr)
        {
            // No initialization
            Database.SetInitializer <TenantContext>(null);

            // Ask shard map to broker a validated connection for the given key
            SqlConnection sqlConn = shardMap.OpenConnectionForKey(shardingKey, connectionStr);

            return(sqlConn);
        }
예제 #19
0
        /// <summary>
        /// Creates the DDR (Data Dependent Routing) connection.
        /// </summary>
        /// <param name="shardMap">The shard map.</param>
        /// <param name="shardingKey">The sharding key.</param>
        /// <param name="connectionStr">The connection string.</param>
        /// <returns></returns>
        private static DbContextOptions CreateDdrConnection(ShardMap shardMap, int shardingKey, string connectionStr)
        {
            // Ask shard map to broker a validated connection for the given key
            SqlConnection sqlConn = shardMap.OpenConnectionForKey(shardingKey, connectionStr);

            var optionsBuilder = new DbContextOptionsBuilder <TenantDbContext>();
            var options        = optionsBuilder.UseSqlServer(sqlConn).Options;

            return(options);
        }
        private ShardMap CreateSampleShardMap()
        {
            var map = new ShardMap
            {
                ShardMapID = 1
            };

            var shard =
                new RangeShard
            {
                LowDistributionKey  = -9223372036854775808,
                HighDistributionKey = -5534023222112865486
            };

            map.Shards.Add(shard);

            shard =
                new RangeShard
            {
                LowDistributionKey  = -5534023222112865485,
                HighDistributionKey = -1844674407370955164
            };

            map.Shards.Add(shard);

            shard =
                new RangeShard
            {
                LowDistributionKey  = -1844674407370955163,
                HighDistributionKey = 1844674407370955158
            };

            map.Shards.Add(shard);

            shard =
                new RangeShard
            {
                LowDistributionKey  = 1844674407370955159,
                HighDistributionKey = 5534023222112865480
            };

            map.Shards.Add(shard);

            shard =
                new RangeShard
            {
                LowDistributionKey  = 5534023222112865481,
                HighDistributionKey = 9223372036854775807
            };

            map.Shards.Add(shard);

            return(map);
        }
예제 #21
0
        public static void Main(string[] args)
        {
            try
            {
                // Parse command line arguments
                s_commandLine = new CommandLine(args);
                if (!s_commandLine.IsValid)
                {
                    s_commandLine.WriteUsage();
                    return;
                }

                // Get Shard Map Manager
                ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager(
                    GetConnectionString(), ShardMapManagerLoadPolicy.Eager);
                Console.WriteLine("Connected to Shard Map Manager");

                // Get Shard Map
                ShardMap map = smm.GetShardMap(s_commandLine.ShardMap);
                Console.WriteLine("Found {0} shards", map.GetShards().Count());

                // Create connection string for MultiShardConnection
                string connectionString = GetCredentialsConnectionString();

                // REPL
                Console.WriteLine();
                while (true)
                {
                    // Read command from console
                    string commandText = GetCommand();
                    if (commandText == null)
                    {
                        // Exit requested
                        break;
                    }

                    // Evaluate command
                    string output;
                    using (MultiShardConnection conn = new MultiShardConnection(map.GetShards(), connectionString))
                    {
                        output = ExecuteCommand(conn, commandText);
                    }

                    // Print output
                    Console.WriteLine(output);
                }
            }
            catch (Exception e)
            {
                // Print exception and exit
                Console.WriteLine(e);
                return;
            }
        }
        public void TestMultiShardConnectionConstructorEvaluatesShards()
        {
            MultiShardTestUtils.DropAndCreateDatabases();
            ShardMap shardMap = MultiShardTestUtils.CreateAndGetTestShardMap();

            List <Shard> shards = shardMap.GetShards().ToList();

            MultiShardConnection conn = new MultiShardConnection(shards.ToConsumable(), dummyConnectionString);

            AssertExtensions.AssertSequenceEqual(shards, conn.Shards);
        }
예제 #23
0
        /// <summary>
        ///   Adds Shards to the Shard Map, or returns them if they have already been added.
        /// </summary>
        public Shard CreateOrGetShard(ShardMap shardMap, ShardLocation shardLocation)
        {
            Shard shard;
            var   shardExists = shardMap.TryGetShard(shardLocation, out shard);

            if (!shardExists)
            {
                shard = shardMap.CreateShard(shardLocation);
            }
            return(shard);
        }
예제 #24
0
        /// <summary>
        /// Adds Shards to the Shard Map, or returns them if they have already been added.
        /// </summary>
        public static Shard CreateOrGetShard(ShardMap shardMap, ShardLocation shardLocation)
        {
            // Try to get a reference to the Shard
            Shard shard;
            bool  shardExists = shardMap.TryGetShard(shardLocation, out shard);

            if (!shardExists)
            {
                shard = shardMap.CreateShard(shardLocation);
            }
            return(shard);
        }
예제 #25
0
        public static void ShardMapTestsInitialize(TestContext testContext)
        {
            // Clear all connection pools.
            SqlConnection.ClearAllPools();

            using (SqlConnection conn = new SqlConnection(Globals.ShardMapManagerTestConnectionString))
            {
                conn.Open();

                // Create ShardMapManager database
                using (SqlCommand cmd = new SqlCommand(
                           string.Format(Globals.CreateDatabaseQuery, Globals.ShardMapManagerDatabaseName),
                           conn))
                {
                    cmd.ExecuteNonQuery();
                }

                // Create shard databases
                for (int i = 0; i < ShardMapTests.s_shardedDBs.Length; i++)
                {
                    using (SqlCommand cmd = new SqlCommand(
                               string.Format(Globals.DropDatabaseQuery, ShardMapTests.s_shardedDBs[i]),
                               conn))
                    {
                        cmd.ExecuteNonQuery();
                    }

                    using (SqlCommand cmd = new SqlCommand(
                               string.Format(Globals.CreateDatabaseQuery, ShardMapTests.s_shardedDBs[i]),
                               conn))
                    {
                        cmd.ExecuteNonQuery();
                    }
                }
            }

            // Create shard map manager.
            ShardMapManagerFactory.CreateSqlShardMapManager(
                Globals.ShardMapManagerConnectionString,
                ShardMapManagerCreateMode.ReplaceExisting);

            // Create default shard map.
            ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager(
                Globals.ShardMapManagerConnectionString,
                ShardMapManagerLoadPolicy.Lazy);

            ShardMap sm = smm.CreateListShardMap <int>(ShardMapTests.s_defaultShardMapName);

            Assert.IsNotNull(sm);

            Assert.AreEqual(ShardMapTests.s_defaultShardMapName, sm.Name);
        }
        /// <summary>
        /// Helper function to select a random shard for specified shard map.
        /// </summary>
        /// <param name="sm">Shard map to get shard.</param>
        /// <returns>Shard from specified shard map.</returns>
        private Shard GetRandomOnlineShardFromShardMap(ShardMap sm)
        {
            List <Shard> shardList = sm.GetShards().Where(s => s.Status == ShardStatus.Online).ToList();

            if (shardList.Count > 0)
            {
                return(shardList[_r.Next(shardList.Count)]);
            }
            else
            {
                return(null);
            }
        }
예제 #27
0
        public void UpdateShardAbortGSM()
        {
            ShardMapManager smm = new ShardMapManager(
                new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString),
                new SqlStoreConnectionFactory(),
                new StubStoreOperationFactory()
            {
                CallBase = true,
                CreateUpdateShardOperationShardMapManagerIStoreShardMapIStoreShardIStoreShard =
                    (_smm, _sm, _so, _sn) => new NTimeFailingUpdateShardOperation(10, _smm, _sm, _so, _sn)
            },
                new CacheStore(),
                ShardMapManagerLoadPolicy.Lazy,
                new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero),
                RetryBehavior.DefaultRetryBehavior);
            ShardMap sm = smm.GetShardMap(ShardMapTests.s_defaultShardMapName);

            Assert.IsNotNull(sm);

            ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapTests.s_shardedDBs[0]);

            Shard sNew = sm.CreateShard(new ShardCreationInfo(sl, ShardStatus.Online));

            ShardUpdate su = new ShardUpdate();

            su.Status = ShardStatus.Offline;

            bool storeOperationFailed = false;

            try
            {
                Shard sUpdated = sm.UpdateShard(sNew, su);
                Assert.IsNotNull(sNew);
            }
            catch (ShardManagementException sme)
            {
                Assert.AreEqual(ShardManagementErrorCategory.ShardMap, sme.ErrorCategory);
                Assert.AreEqual(ShardManagementErrorCode.StorageOperationFailure, sme.ErrorCode);
                storeOperationFailed = true;
            }

            Assert.IsTrue(storeOperationFailed);

            // verify that shard status is not changed.
            Shard sValidate = sm.GetShard(sl);

            Assert.AreEqual(sNew.Status, sValidate.Status);
        }
예제 #28
0
        public void ShardMapManagerTestInitialize()
        {
            ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager(
                Globals.ShardMapManagerConnectionString,
                ShardMapManagerLoadPolicy.Lazy);

            try
            {
                ShardMap sm = smm.GetShardMap(ShardMapManagerTests.s_shardMapName);
                smm.DeleteShardMap(sm);
            }
            catch (ShardManagementException smme)
            {
                Assert.IsTrue(smme.ErrorCode == ShardManagementErrorCode.ShardMapLookupFailure);
            }
        }
예제 #29
0
        public void DeleteShardMapNonExisting()
        {
            ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager(
                Globals.ShardMapManagerConnectionString,
                ShardMapManagerLoadPolicy.Lazy);

            ShardMap sm = smm.CreateListShardMap <int>(ShardMapManagerTests.s_shardMapName);

            Assert.IsNotNull(sm);

            Assert.AreEqual(ShardMapManagerTests.s_shardMapName, sm.Name);

            smm.DeleteShardMap(sm);

            smm.DeleteShardMap(sm);
        }
        /// <summary>
        /// Creates the DDR (Data Dependent Routing) connection.
        /// </summary>
        /// <param name="shardMap">The shard map.</param>
        /// <param name="shardingKey">The sharding key.</param>
        /// <param name="connectionStr">The connection string.</param>
        /// <returns></returns>
        private static DbContextOptions CreateDdrConnection(ShardMap shardMap, int shardingKey, string connectionStr)
        {
            // Ask shard map to broker a validated connection for the given key
            SqlConnection sqlConn = shardMap.OpenConnectionForKey(shardingKey, connectionStr);

            // Set TenantId in SESSION_CONTEXT to shardingKey to enable Row-Level Security filtering
            SqlCommand cmd = sqlConn.CreateCommand();
            cmd.CommandText = @"exec sp_set_session_context @key=N'TenantId', @value=@shardingKey";
            cmd.Parameters.AddWithValue("@shardingKey", shardingKey);
            cmd.ExecuteNonQuery();

            var optionsBuilder = new DbContextOptionsBuilder<TenantDbContext>();
            var options = optionsBuilder.UseSqlServer(sqlConn).Options;

            return options;
        }
        private static DbConnection CreateDdrConnection(ShardMap shardMap, int shardingKey, string connectionStr)
        {
            // No initialization
            Database.SetInitializer <TenantContext>(null);

            // Ask shard map to broker a validated connection for the given key
            SqlConnection sqlConn = shardMap.OpenConnectionForKey(shardingKey, connectionStr);

            // Set TenantId in SESSION_CONTEXT to shardingKey to enable Row-Level Security filtering
            SqlCommand cmd = sqlConn.CreateCommand();

            cmd.CommandText = @"exec sp_set_session_context @key=N'TenantId', @value=@shardingKey";
            cmd.Parameters.AddWithValue("@shardingKey", shardingKey);
            cmd.ExecuteNonQuery();

            return(sqlConn);
        }
예제 #32
0
        public void GetDistinctLocations()
        {
            // Get shard map manager and 2 shard maps.
            ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager(
                Globals.ShardMapManagerConnectionString,
                ShardMapManagerLoadPolicy.Lazy);

            // Upgrade GSM to latest version
            smm.UpgradeGlobalStore();

            // create shard maps
            foreach (string name in ShardMapManagerUpgradeTests.s_shardMapNames)
            {
                ShardMap sm = smm.CreateListShardMap <int>(name);
                Assert.IsNotNull(sm);
            }

            ShardMap sm1 = smm.GetShardMap(ShardMapManagerUpgradeTests.s_shardMapNames[0]);

            Assert.IsNotNull(sm1);

            ShardMap sm2 = smm.GetShardMap(ShardMapManagerUpgradeTests.s_shardMapNames[1]);

            Assert.IsNotNull(sm2);

            // Add shards to the shard maps.

            ShardLocation sl1 = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapManagerUpgradeTests.s_shardedDBs[0]);
            ShardLocation sl2 = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapManagerUpgradeTests.s_shardedDBs[1]);
            ShardLocation sl3 = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapManagerUpgradeTests.s_shardedDBs[2]);

            Shard s1 = sm1.CreateShard(sl1);
            Shard s2 = sm1.CreateShard(sl2);
            Shard s3 = sm1.CreateShard(sl3);
            Shard s4 = sm2.CreateShard(sl2);
            Shard s5 = sm2.CreateShard(sl3);

            int count = 0;

            foreach (ShardLocation sl in smm.GetDistinctShardLocations())
            {
                count++;
            }

            Assert.AreEqual(3, count);
        }
        /// <summary>
        /// Helper function to do validation,this will be called using TFH retry policy.
        /// </summary>
        /// <param name="sm">Shard map for a mapping to validate</param>
        /// <param name="key">Key to lookup and validate</param>
        private static void ValidateImpl(ShardMap sm, int key)
        {
            try
            {
                using (SqlConnection conn = sm.OpenConnectionForKey(key,
                    Globals.ShardUserConnectionString,
                    ConnectionOptions.Validate))
                {
                }
            }
            catch (SqlException e)
            {
                // Error Number 3980: The request failed to run because the batch is aborted, this can be caused by abort signal sent from client, or another request is running in the same session, which makes the session busy.
                // Error Number = 0, Class = 20, Message = The connection is broken and recovery is not possible.  The connection is marked by the server as unrecoverable.  No attempt was made to restore the connection.
                // Error Number = 0, Class = 11, Message = A severe error occurred on the current command.  The results, if any, should be discarded.
                switch (e.Number)
                {
                    case 0:
                        if (e.Class != 20 && e.Class != 11)
                            throw;
                        break;

                    case 3980:
                        break;

                    default:
                        throw;
                }
            }
        }
        /// <summary>
        /// Helper function to select a random shard for specified shard map.
        /// </summary>
        /// <param name="sm">Shard map to get shard.</param>
        /// <returns>Shard from specified shard map.</returns>
        private Shard GetRandomOnlineShardFromShardMap(ShardMap sm)
        {
            List<Shard> shardList = sm.GetShards().Where(s => s.Status == ShardStatus.Online).ToList();

            if (shardList.Count > 0)
                return shardList[_r.Next(shardList.Count)];
            else
                return null;
        }
        /// <summary>
        /// Helper function to add a new shard to given shard map.
        /// </summary>
        /// <param name="sm"></param>
        private void AddShardToShardMap(ShardMap sm)
        {
            IEnumerable<Shard> existingShards = sm.GetShards();

            // get list of shard locations that are not already added to this shard map.
            List<string> availableLocationList = (from dbName in ShardMapManagerLoadTests.s_shardedDBs
                                                  where !existingShards.Select(s => s.Location.Database).ToList().Contains(dbName)
                                                  select dbName).ToList();

            if (availableLocationList.Count > 0)
            {
                ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, availableLocationList[_r.Next(availableLocationList.Count)]);

                Debug.WriteLine("Trying to add shard at location {0} to shard map {1}", sl, sm);

                ShardCreationInfo si = new ShardCreationInfo(sl, ShardStatus.Online);

                Shard newShard = sm.CreateShard(si);
            }
        }
        public void MyTestInitialize()
        {
            _shardMap = MultiShardTestUtils.CreateAndGetTestShardMap();

            _shardConnection = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString);
        }
        /// <summary>
        /// Adds an order to the orders table for the customer.
        /// </summary>
        private static void AddOrder(
            ShardMap shardMap,
            string credentialsConnectionString,
            int customerId,
            int productId)
        {
            SqlDatabaseUtils.SqlRetryPolicy.ExecuteAction(() =>
            {
                // Looks up the key in the shard map and opens a connection to the shard
                using (SqlConnection conn = shardMap.OpenConnectionForKey(customerId, credentialsConnectionString))
                {
                    // Create a simple command that will insert a new order
                    SqlCommand cmd = conn.CreateCommand();

                    // Create a simple command
                    cmd.CommandText = @"INSERT INTO dbo.Orders (CustomerId, OrderDate, ProductId)
                                        VALUES (@customerId, @orderDate, @productId)";
                    cmd.Parameters.AddWithValue("@customerId", customerId);
                    cmd.Parameters.AddWithValue("@orderDate", DateTime.Now.Date);
                    cmd.Parameters.AddWithValue("@productId", productId);
                    cmd.CommandTimeout = 60;

                    // Execute the command
                    cmd.ExecuteNonQuery();
                }
            });

            ConsoleUtils.WriteInfo("Inserted order for customer ID: {0}", customerId);
        }