public void TestShardConnectionOpenException()
        {
            try
            {
                Action executeOnOpen = () =>
                {
                    throw new InsufficientMemoryException();
                };
                var shardConnections = CreateConnections(10, executeOnOpen);
                var mockCmd          = new MockSqlCommand();
                mockCmd.CommandText = "Select 1";
                using (var conn = new MultiShardConnection(shardConnections))
                {
                    using (var cmd = MultiShardCommand.Create(conn, mockCmd, 100))
                    {
                        cmd.CommandText = "select 1";
                        cmd.ExecuteReader();
                    }
                }
            }
            catch (Exception ex)
            {
                if (ex is MultiShardAggregateException)
                {
                    var maex = (MultiShardAggregateException)ex;
                    Logger.Log("Exception message: {0}.\n Exception tostring: {1}",
                               ex.Message, ex.ToString());

                    throw (maex.InnerException).InnerException;
                }

                throw;
            }
        }
示例#2
0
        private async Task <MultiShardDataReader> ExecAsync(MultiShardConnection conn, MultiShardCommand cmd)
        {
            cmd.ExecutionPolicy  = MultiShardExecutionPolicy.PartialResults;
            cmd.ExecutionOptions = MultiShardExecutionOptions.IncludeShardNameColumn;

            return(await cmd.ExecuteReaderAsync(CommandBehavior.Default, CancellationToken.None));
        }
示例#3
0
        public void TestFailedCommandWithConnectionCloseCmdBehavior()
        {
            Parallel.For(0, 100, i =>
            {
                try
                {
                    using (MultiShardConnection conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
                    {
                        using (MultiShardCommand cmd = conn.CreateCommand())
                        {
                            cmd.CommandText = "select * from table_does_not_exist";
                            cmd.CommandType = CommandType.Text;

                            using (MultiShardDataReader sdr = cmd.ExecuteReader())
                            {
                                while (sdr.Read())
                                {
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Encountered exception: {0} in iteration: {1}",
                                      ex.ToString(), i);
                }
                finally
                {
                    Console.WriteLine("Completed execution of iteration: {0}", i);
                }
            });
        }
示例#4
0
 public void TestCreateConnectionWithNoShards()
 {
     using (MultiShardConnection conn = new MultiShardConnection(new Shard[] { }, String.Empty))
     {
         Assert.Fail("Should have failed in the MultiShardConnection c-tor.");
     }
 }
        public void TestShardCommandSucceedHandler()
        {
            var shardConnections = CreateConnections(10, () => { });
            ConcurrentDictionary <ShardLocation, bool> passedLocations = new ConcurrentDictionary <ShardLocation, bool>();

            using (var conn = new MultiShardConnection(shardConnections))
            {
                Func <CancellationToken, MockSqlCommand, DbDataReader> executeReaderFunc = (token, cmd) =>
                {
                    Thread.Sleep(TimeSpan.FromSeconds(2));
                    return(new MockSqlDataReader());
                };

                MockSqlCommand mockCmd = new MockSqlCommand();
                mockCmd.ExecuteReaderFunc = executeReaderFunc;
                mockCmd.CommandText       = "Select 1";
                using (MultiShardCommand cmd = MultiShardCommand.Create(conn, mockCmd, 10))
                {
                    cmd.ShardExecutionSucceeded += new EventHandler <ShardExecutionEventArgs>((obj, eventArgs) =>
                    {
                        Assert.IsTrue(shardConnections.Select(x => x.Item1).Contains(eventArgs.ShardLocation), "The ShardLocation passed to the event handler does not exist in the set of passed in ShardLocations");
                        passedLocations[eventArgs.ShardLocation] = true;
                    });
                    CommandBehavior behavior = CommandBehavior.Default;
                    cmd.ExecuteReader(behavior);
                }
            }

            Assert.AreEqual(shardConnections.Count, passedLocations.Count, "Not every ShardLocation had its corresponding event handler invoked.");
        }
示例#6
0
        public void TestSelectNoRows(string commandText, MultiShardExecutionPolicy policy)
        {
            using (MultiShardConnection conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
            {
                using (MultiShardCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText     = commandText;
                    cmd.ExecutionPolicy = policy;

                    // Read first
                    using (MultiShardDataReader sdr = cmd.ExecuteReader())
                    {
                        Assert.AreEqual(0, sdr.MultiShardExceptions.Count);
                        while (sdr.Read())
                        {
                            Assert.Fail("Should not have gotten any records.");
                        }
                        Assert.IsFalse(sdr.HasRows);
                    }

                    // HasRows first
                    using (MultiShardDataReader sdr = cmd.ExecuteReader())
                    {
                        Assert.AreEqual(0, sdr.MultiShardExceptions.Count);
                        Assert.IsFalse(sdr.HasRows);
                        while (sdr.Read())
                        {
                            Assert.Fail("Should not have gotten any records.");
                        }
                    }
                }
            }
        }
示例#7
0
        public void TestQueryShardsAsync()
        {
            // Create new sharded connection so we can test the OpenAsync call as well.
            //
            using (MultiShardConnection conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
            {
                using (MultiShardCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText = "SELECT dbNameField, Test_int_Field, Test_bigint_Field  FROM ConsistentShardedTable";
                    cmd.CommandType = CommandType.Text;

                    using (MultiShardDataReader sdr = ExecAsync(conn, cmd).Result)
                    {
                        int recordsRetrieved = 0;
                        while (sdr.Read())
                        {
                            recordsRetrieved++;
                            var dbNameField     = sdr.GetString(0);
                            var testIntField    = sdr.GetFieldValue <int>(1);
                            var testBigIntField = sdr.GetFieldValue <Int64>(2);
                            Logger.Log("RecordRetrieved: dbNameField: {0}, TestIntField: {1}, TestBigIntField: {2}, RecordCount: {3}",
                                       dbNameField, testIntField, testBigIntField, recordsRetrieved);
                        }

                        Assert.AreEqual(recordsRetrieved, 9);
                    }
                }
            }
        }
示例#8
0
        public void TestQueryShardsInvalidConnectionSync()
        {
            var badShard = new ShardLocation("badLocation", "badDatabase");
            var bldr     = new SqlConnectionStringBuilder();

            bldr.DataSource     = badShard.DataSource;
            bldr.InitialCatalog = badShard.Database;
            var badConn = new SqlConnection(bldr.ConnectionString);

            try
            {
                using (var conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
                {
                    conn.GetShardConnections().Add(new Tuple <ShardLocation, DbConnection>(badShard,
                                                                                           badConn));
                    using (var cmd = conn.CreateCommand())
                    {
                        cmd.CommandText = "select 1";
                        cmd.ExecuteReader();
                    }
                }
            }
            catch (Exception ex)
            {
                if (ex is MultiShardAggregateException)
                {
                    var maex = (MultiShardAggregateException)ex;
                    Logger.Log("Exception encountered: " + maex.ToString());
                    throw ((MultiShardException)(maex.InnerException)).InnerException;
                }
                throw;
            }
        }
示例#9
0
        public MultiShardAggregateException TestSelectFailure(string commandText, MultiShardExecutionPolicy policy)
        {
            using (MultiShardConnection conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
            {
                using (MultiShardCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText     = commandText;
                    cmd.ExecutionPolicy = policy;

                    // ExecuteReader should fail
                    MultiShardAggregateException aggregateException =
                        AssertExtensions.AssertThrows <MultiShardAggregateException>(() => cmd.ExecuteReader());

                    // Sanity check the exceptions are the correct type
                    foreach (Exception e in aggregateException.InnerExceptions)
                    {
                        Assert.IsInstanceOfType(e, typeof(MultiShardException));
                        Assert.IsInstanceOfType(e.InnerException, typeof(SqlException));
                    }

                    // Return the exception so that the caller can do additional validation
                    return(aggregateException);
                }
            }
        }
        public void TestShardCommandCancellationHandler()
        {
            // Create connections to a few shards
            var shardConnections = CreateConnections(10, () => { });

            var mockCmd       = new MockSqlCommand();
            var cmdStartEvent = new ManualResetEvent(false);

            mockCmd.ExecuteReaderFunc = (token, cmd) =>
            {
                while (true)
                {
                    if (token == null)
                    {
                        break;
                    }
                    token.ThrowIfCancellationRequested();
                    Thread.Sleep(500);
                    cmdStartEvent.Set();
                }

                return(new MockSqlDataReader());
            };

            mockCmd.CommandText = "select 1";
            ConcurrentDictionary <ShardLocation, bool> passedLocations = new ConcurrentDictionary <ShardLocation, bool>();

            using (var conn = new MultiShardConnection(shardConnections))
            {
                using (var cmd = MultiShardCommand.Create(conn, mockCmd, 300))
                {
                    cmd.ShardExecutionCanceled += new EventHandler <ShardExecutionEventArgs>((obj, eventArgs) =>
                    {
                        Assert.IsTrue(shardConnections.Select(x => x.Item1).Contains(eventArgs.ShardLocation),
                                      "The ShardLocation passed to the event handler does not exist in the set of passed in ShardLocations");
                        passedLocations[eventArgs.ShardLocation] = true;
                    });
                    try
                    {
                        // start the Cancel on a separate thread
                        Task executeTask = Task.Run(() =>
                        {
                            cmdStartEvent.WaitOne();
                            cmd.Cancel();
                        });

                        cmd.ExecuteReader();
                        executeTask.Wait();
                        Assert.Fail("We should always be throwing an exception.");
                    }
                    catch (Exception ex)
                    {
                        Assert.IsTrue(ex is OperationCanceledException, "OperationCanceledException expected. Found {0}!", ex.ToString());
                    }
                }
            }
            Assert.AreEqual(shardConnections.Count, passedLocations.Count, "Not every ShardLocation had its corresponding event handler invoked.");
        }
示例#11
0
        /// <summary>
        /// Executes the SQL command and returns the output in text format.
        /// </summary>
        private static string ExecuteCommand(MultiShardConnection conn, string commandText)
        {
            try
            {
                StringBuilder output = new StringBuilder();
                output.AppendLine();

                int rowsAffected = 0;

                using (MultiShardCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText            = commandText;
                    cmd.CommandTimeout         = s_commandLine.QueryTimeout;
                    cmd.CommandTimeoutPerShard = s_commandLine.QueryTimeout;

                    // Execute command and time with a stopwatch
                    Stopwatch stopwatch = Stopwatch.StartNew();
                    cmd.ExecutionPolicy  = s_commandLine.ExecutionPolicy;
                    cmd.ExecutionOptions = s_commandLine.ExecutionOptions;
                    using (MultiShardDataReader reader = cmd.ExecuteReader(CommandBehavior.Default))
                    {
                        stopwatch.Stop();

                        // Get column names
                        IEnumerable <string> columnNames = GetColumnNames(reader).ToArray();

                        // Create table formatter
                        TableFormatter tableFormatter = new TableFormatter(columnNames.ToArray());

                        // Read results from db
                        while (reader.Read())
                        {
                            rowsAffected++;

                            // Add the row to the table formatter
                            object[] values = new object[reader.FieldCount];
                            reader.GetValues(values);
                            tableFormatter.AddRow(values);
                        }

                        // Write formatter output
                        output.AppendLine(tableFormatter.ToString());
                    }

                    output.AppendLine();
                    output.AppendFormat("({0} rows affected - {1:hh}:{1:mm}:{1:ss} elapsed)", rowsAffected, stopwatch.Elapsed);
                    output.AppendLine();
                }

                return(output.ToString());
            }
            catch (MultiShardAggregateException e)
            {
                return(e.ToString());
            }
        }
示例#12
0
        public void TestSchemaMismatchErrorPropagation()
        {
            // First we need to alter the schema on one of the shards - we'll choose the last one.
            //
            string origColName = "Test_bigint_Field";
            string newColName  = "ModifiedName";

            MultiShardTestUtils.ChangeColumnNameOnShardedTable(2, origColName, newColName);

            // Then create new sharded connection so we can test the error handling logic.
            // We'll wrap this all in a try-catch-finally block so that we can change the schema back
            // to what the other tests will expect it to be in the finally.
            //
            try
            {
                using (MultiShardConnection conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
                {
                    using (MultiShardCommand cmd = conn.CreateCommand())
                    {
                        // Need to do a SELECT * in order to get the column name error as a schema mismatcherror.  If we name it explicitly
                        // we will get a command execution error instead.
                        //
                        cmd.CommandText = "SELECT * FROM ConsistentShardedTable";
                        cmd.CommandType = CommandType.Text;

                        using (MultiShardDataReader sdr = ExecAsync(conn, cmd).Result)
                        {
                            // The number of errors we have depends on which shard executed first.
                            // So, we know it should be 1 OR 2.
                            //
                            Assert.IsTrue(
                                ((sdr.MultiShardExceptions.Count == 1) || (sdr.MultiShardExceptions.Count == 2)),
                                string.Format("Expected 1 or 2 execution erros, but saw {0}", sdr.MultiShardExceptions.Count));

                            int recordsRetrieved = 0;
                            while (sdr.Read())
                            {
                                recordsRetrieved++;
                                var dbNameField = sdr.GetString(0);
                            }

                            // We should see 9 records less 3 for each one that had a schema error.
                            int expectedRecords = ((9 - (3 * sdr.MultiShardExceptions.Count)));

                            Assert.AreEqual(recordsRetrieved, expectedRecords);
                        }
                    }
                }
            }
            finally
            {
                MultiShardTestUtils.ChangeColumnNameOnShardedTable(2, newColName, origColName);
            }
        }
        // GET: Captain
        public ActionResult Index()
        {
            Dictionary <int, int> votes = new Dictionary <int, int>();

            //Perform a multi shard query to tally all the votes
            // Get the shards to connect to
            var shards = _shardMap.GetShards();

            // Create the multi-shard connection
            using (var conn = new MultiShardConnection(shards, Util.SqlHelper.GetCredentialsConnectionString()))
            {
                // Create a simple command
                using (MultiShardCommand cmd = conn.CreateCommand())
                {
                    // Because this query is grouped by CustomerID, which is sharded,
                    // we will not get duplicate rows.
                    cmd.CommandText = @"SELECT Captain, COUNT(*) AS Votes FROM [dbo].[Votes] GROUP BY [Captain]";

                    // Allow for partial results in case some shards do not respond in time
                    cmd.ExecutionPolicy = MultiShardExecutionPolicy.PartialResults;

                    // Allow the entire command to take up to 30 seconds
                    cmd.CommandTimeout = 30;

                    // Execute the command.
                    // We do not need to specify retry logic because MultiShardDataReader will internally retry until the CommandTimeout expires.
                    using (MultiShardDataReader reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            votes.Add(reader.GetInt32(0), reader.GetInt32(1));
                        }
                    }
                }
            }


            var vm = new ViewModels.Captain.IndexViewModel();

            foreach (var captain in _captainContext.Captains)
            {
                int voteCount = 0;
                votes.TryGetValue(captain.ID, out voteCount);

                vm.Captains.Add(new ViewModels.Captain.IndexViewModelCaptain()
                {
                    ID    = captain.ID,
                    Name  = captain.Name,
                    Votes = voteCount
                });
            }

            return(View(vm));
        }
        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);
        }
示例#15
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;
            }
        }
示例#16
0
        // POST api/CustomLogin
        public HttpResponseMessage Post(LoginRequest loginRequest)
        {
            Guid shardKey;

            // SEND A QUERY TO ALL SHARD TO DETECT OUR SHARD!!!!
            // SAVE companiesId to shardKey!
            using (MultiShardConnection conn = new MultiShardConnection(WebApiConfig.ShardingObj.ShardMap.GetShards(), WebApiConfig.ShardingObj.connstring))
            {
                using (MultiShardCommand cmd = conn.CreateCommand())
                {
                    // CHECK SCHEMA
                    // SQL INJECTION SECURITY ISSUE
                    cmd.CommandText      = "SELECT CompaniesID FROM [mpbdm].[Accounts] JOIN [mpbdm].[Users] ON [mpbdm].[Users].Id = [mpbdm].[Accounts].User_Id WHERE email='" + loginRequest.email + "'";
                    cmd.CommandType      = CommandType.Text;
                    cmd.ExecutionOptions = MultiShardExecutionOptions.IncludeShardNameColumn;
                    cmd.ExecutionPolicy  = MultiShardExecutionPolicy.PartialResults;
                    // Async
                    using (MultiShardDataReader sdr = cmd.ExecuteReader())
                    {
                        bool res = sdr.Read();
                        if (res != false)
                        {
                            shardKey = new Guid(sdr.GetString(0));
                        }
                        else
                        {
                            return(this.Request.CreateResponse(HttpStatusCode.Unauthorized, "Account doesn't exist!"));
                        }
                    }
                }
            }
            // Connect with entity framework to the specific shard
            mpbdmContext <Guid> context = new mpbdmContext <Guid>(WebApiConfig.ShardingObj.ShardMap, shardKey, WebApiConfig.ShardingObj.connstring);
            Account             account = context.Accounts.Include("User").Where(a => a.User.Email == loginRequest.email).SingleOrDefault();

            if (account != null)
            {
                byte[] incoming = CustomLoginProviderUtils.hash(loginRequest.password, account.Salt);

                if (CustomLoginProviderUtils.slowEquals(incoming, account.SaltedAndHashedPassword))
                {
                    ClaimsIdentity claimsIdentity = new ClaimsIdentity();
                    claimsIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, account.User.Email));
                    // Custom Claim must be added to CustomLoginProvider too !!
                    claimsIdentity.AddClaim(new Claim("shardKey", account.User.CompaniesID));
                    var               customLoginProvider = new CustomLoginProvider(handler);
                    LoginResult       loginResult         = customLoginProvider.CreateLoginResult(claimsIdentity, Services.Settings.MasterKey);
                    MobileLoginResult res = new MobileLoginResult(account, loginResult);
                    return(this.Request.CreateResponse(HttpStatusCode.OK, res));
                }
            }
            return(this.Request.CreateResponse(HttpStatusCode.Unauthorized, "Invalid username or password"));
        }
        public void TestShardCommandRetryExhaustion()
        {
            var retryPolicy      = new RetryPolicy(2, TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(10), TimeSpan.FromMilliseconds(100));
            var shardConnections = new List <Tuple <ShardLocation, DbConnection> >();

            // Create ten mocked connections, half of them will throw exceptions on Open
            for (int i = 0; i < 10; i++)
            {
                string database = string.Format("Shard{0}", i);

                int    j             = i;
                Action executeOnOpen = () =>
                {
                    if (j < 5)
                    {
                        throw new TimeoutException();
                    }
                };

                var mockCon = new MockSqlConnection(database, executeOnOpen);
                shardConnections.Add(new Tuple <ShardLocation, DbConnection>(new ShardLocation("test", database), mockCon));
            }

            var mockCmd = new MockSqlCommand();

            mockCmd.ExecuteReaderFunc = (t, c) => new MockSqlDataReader();
            mockCmd.CommandText       = "select 1";
            using (var conn = new MultiShardConnection(shardConnections))
            {
                using (var cmd = MultiShardCommand.Create(conn, mockCmd, 300))
                {
                    cmd.ExecutionOptions = MultiShardExecutionOptions.None;
                    cmd.RetryPolicy      = retryPolicy;
                    cmd.ExecutionPolicy  = MultiShardExecutionPolicy.PartialResults;
                    MultiShardDataReader rdr = cmd.ExecuteReader(CommandBehavior.Default);

                    // Validate the right exception is re-thrown
                    Assert.IsTrue(rdr.MultiShardExceptions.Count == 5, "Expected MultiShardExceptions!");
                    foreach (MultiShardException ex in rdr.MultiShardExceptions)
                    {
                        Assert.IsTrue(ex.InnerException is TimeoutException, "Expected TimeoutException!");
                    }

                    // Validate that the connections for the faulted readers are closed
                    for (int i = 0; i < 5; i++)
                    {
                        Assert.IsTrue(shardConnections[i].Item2.State == ConnectionState.Closed,
                                      "Expected Connection to be Closed!");
                    }
                }
            }
        }
        public void TestMultiShardConnectionConstructorEvaluatesShardLocations()
        {
            List <ShardLocation> shardLocations = new List <ShardLocation>
            {
                new ShardLocation("server1", "db1"),
                new ShardLocation("server2", "db2"),
                new ShardLocation("server3", "db3")
            };

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

            AssertExtensions.AssertSequenceEqual(shardLocations, conn.ShardLocations);
        }
        public void TestShardCommandBehavior()
        {
            var shardConnections = CreateConnections(10, () => { });

            using (var conn = new MultiShardConnection(shardConnections))
            {
                using (var cmd = conn.CreateCommand())
                {
                    CommandBehavior behavior = CommandBehavior.SingleResult;
                    behavior &= CommandBehavior.SingleRow;
                    cmd.ExecuteReader(behavior);
                }
            }
        }
        public void TestShardCommandRetryBasic()
        {
            var retryPolicy      = new RetryPolicy(4, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(10), TimeSpan.FromMilliseconds(100));
            var openRetryCounts  = new int[10];
            var shardConnections = new List <Tuple <ShardLocation, DbConnection> >();

            // Create ten mocked connections, each will retry retryPolicy.RetryCount - 1 times,
            // and keep it's own actual retry count in one of the elements of openRetryCounts
            for (int i = 0; i < 10; i++)
            {
                string database = string.Format("Shard{0}", i);

                // We want to close on the value of i
                int    j             = i;
                Action executeOnOpen = () =>
                {
                    if (openRetryCounts[j] < (retryPolicy.RetryCount - 1))
                    {
                        Logger.Log("Current retry count for database: {0} is {1}", database, openRetryCounts[j]);
                        openRetryCounts[j]++;
                        throw new TimeoutException();
                    }
                };

                var mockCon = new MockSqlConnection(database, executeOnOpen);
                shardConnections.Add(new Tuple <ShardLocation, DbConnection>(new ShardLocation("test", database), mockCon));
            }

            var mockCmd = new MockSqlCommand();

            mockCmd.ExecuteReaderFunc = (t, c) => new MockSqlDataReader();
            mockCmd.CommandText       = "select 1";
            using (var conn = new MultiShardConnection(shardConnections))
            {
                using (var cmd = MultiShardCommand.Create(conn, mockCmd, 300))
                {
                    cmd.ExecutionOptions = MultiShardExecutionOptions.None;
                    cmd.RetryPolicy      = retryPolicy;
                    cmd.ExecutionPolicy  = MultiShardExecutionPolicy.PartialResults;
                    cmd.ExecuteReader(CommandBehavior.Default);
                }
            }

            for (int i = 0; i < openRetryCounts.Length; i++)
            {
                Assert.AreEqual(retryPolicy.RetryCount - 1, openRetryCounts[i]);
            }
        }
        public void TestShardCommandCancellation()
        {
            // Create connections to a few shards
            var shardConnections = CreateConnections(10, () => { });

            var mockCmd       = new MockSqlCommand();
            var cmdStartEvent = new ManualResetEvent(false);

            mockCmd.ExecuteReaderFunc = (token, cmd) =>
            {
                while (true)
                {
                    if (token == null)
                    {
                        break;
                    }
                    token.ThrowIfCancellationRequested();
                    Thread.Sleep(500);
                    cmdStartEvent.Set();
                }

                return(new MockSqlDataReader());
            };
            mockCmd.CommandText = "select 1";
            using (var conn = new MultiShardConnection(shardConnections))
            {
                using (var cmd = MultiShardCommand.Create(conn, mockCmd, 300))
                {
                    try
                    {
                        // start the Cancel on a separate thread
                        Task executeTask = Task.Run(() =>
                        {
                            cmdStartEvent.WaitOne();
                            cmd.Cancel();
                        });

                        cmd.ExecuteReader();
                        executeTask.Wait();
                        Assert.Fail("We should always be throwing an exception.");
                    }
                    catch (Exception ex)
                    {
                        Assert.IsTrue(ex is OperationCanceledException, "OperationCanceledException expected. Found {0}!", ex.ToString());
                    }
                }
            }
        }
        public DataSet MultiShardQuery(string commandText)
        {
            DataSet _ds = new DataSet();

            try
            {
                RetryPolicy.DefaultExponential.ExecuteAction(() =>
                {
                    using (MultiShardCommand cmd = new MultiShardConnection(lsm.GetShards(), shardConnectionString).CreateCommand())
                    {
                        cmd.CommandText      = commandText;
                        cmd.CommandType      = CommandType.Text;
                        cmd.ExecutionOptions = MultiShardExecutionOptions.None;
                        //04/23/2015 by Mark Berman - switched to Partial results versus CompleteResults as timeout exception was being thrown
                        cmd.ExecutionPolicy = MultiShardExecutionPolicy.PartialResults;
                        using (MultiShardDataReader sdr = cmd.ExecuteReader())
                        {
                            if (sdr.Read())
                            {
                                // the multi-shard query does not return a dataset or datarow.
                                // we have to manually re-create a table structure, then fill it with data.
                                object[] sqlValues = new object[sdr.FieldCount];
                                sdr.GetSqlValues(sqlValues);
                                DataTable dtValues = new DataTable();
                                foreach (var column in sqlValues)
                                {
                                    dtValues.Columns.Add(new DataColumn {
                                        DataType = column.GetType()
                                    });
                                }
                                _ds.Tables.Add(dtValues);
                                _ds.Tables[0].Rows.Add(sqlValues);
                                while (sdr.Read())
                                {
                                    sdr.GetSqlValues(sqlValues);
                                    _ds.Tables[0].Rows.Add(sqlValues);
                                }
                            }
                        }
                    }
                });
            }
            catch { _ds = null; }
            return(_ds);
        }
示例#23
0
        public void TestInvalidMultiShardConnectionString()
        {
            MultiShardConnection conn;

            try
            {
                conn = new MultiShardConnection(_shardMap.GetShards(), connectionString: null);
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is ArgumentNullException, "Expected ArgumentNullException!");
            }

            try
            {
                conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardMapManagerConnectionString);
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is ArgumentException, "Expected ArgumentException!");
            }

            // Validate that the ApplicationName is updated properly
            var applicationStringBldr = new StringBuilder();

            for (int i = 0; i < ApplicationNameHelper.MaxApplicationNameLength; i++)
            {
                applicationStringBldr.Append('x');
            }
            string applicationName = applicationStringBldr.ToString();
            SqlConnectionStringBuilder connStringBldr = new SqlConnectionStringBuilder(MultiShardTestUtils.ShardConnectionString);

            connStringBldr.ApplicationName = applicationName;
            conn = new MultiShardConnection(_shardMap.GetShards(), connStringBldr.ConnectionString);

            string updatedApplicationName = new SqlConnectionStringBuilder
                                                (conn.GetShardConnections()[0].Item2.ConnectionString).ApplicationName;

            Assert.IsTrue(updatedApplicationName.Length == ApplicationNameHelper.MaxApplicationNameLength &&
                          updatedApplicationName.EndsWith(MultiShardConnection.ApplicationNameSuffix), "ApplicationName not appended with {0}!",
                          MultiShardConnection.ApplicationNameSuffix);
        }
示例#24
0
        public void TestSimpleSelect(MultiShardExecutionPolicy policy)
        {
            // What we're doing:
            // Grab all rows from each test database.
            // Load them into a MultiShardDataReader.
            // Iterate through the rows and make sure that we have 9 total.
            //
            using (MultiShardConnection conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
            {
                using (MultiShardCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText      = "SELECT dbNameField, Test_int_Field, Test_bigint_Field FROM ConsistentShardedTable";
                    cmd.ExecutionOptions = MultiShardExecutionOptions.IncludeShardNameColumn;
                    cmd.ExecutionPolicy  = policy;

                    using (MultiShardDataReader sdr = cmd.ExecuteReader())
                    {
                        int recordsRetrieved = 0;
                        Logger.Log("Starting to get records");
                        while (sdr.Read())
                        {
                            recordsRetrieved++;
                            string dbNameField         = sdr.GetString(0);
                            int    testIntField        = sdr.GetFieldValue <int>(1);
                            Int64  testBigIntField     = sdr.GetFieldValue <Int64>(2);
                            string shardIdPseudoColumn = sdr.GetFieldValue <string>(3);
                            string logRecord           =
                                string.Format(
                                    "RecordRetrieved: dbNameField: {0}, TestIntField: {1}, TestBigIntField: {2}, shardIdPseudoColumnField: {3}, RecordCount: {4}",
                                    dbNameField, testIntField, testBigIntField, shardIdPseudoColumn, recordsRetrieved);
                            Logger.Log(logRecord);
                            Debug.WriteLine(logRecord);
                        }

                        sdr.Close();

                        Assert.AreEqual(recordsRetrieved, 9);
                    }
                }
            }
        }
示例#25
0
        public void TestSelectNonQuery(string commandText, MultiShardExecutionPolicy policy)
        {
            using (MultiShardConnection conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
            {
                using (MultiShardCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText     = commandText;
                    cmd.ExecutionPolicy = policy;

                    using (MultiShardDataReader sdr = cmd.ExecuteReader())
                    {
                        Assert.AreEqual(0, sdr.MultiShardExceptions.Count);

                        // TODO: This is a weird error message, but it's good enough for now
                        // Fixing this will require significant refactoring of MultiShardDataReader,
                        // we should fix it when we finish implementing async adding of child readers
                        AssertExtensions.AssertThrows <MultiShardDataReaderClosedException>(() => sdr.Read());
                    }
                }
            }
        }
示例#26
0
        private static List <dynamic> ExecuteMultiShardQuery(ref ShardingClient sharding, string connectionString)
        {
            dynamic result = new List <dynamic>();

            var multiShardConnection = new MultiShardConnection(sharding.ShardMap.GetShards(), connectionString);

            using (var cmd = multiShardConnection.CreateCommand()) {
                cmd.CommandText            = @"SELECT * FROM dbo.Blogs";
                cmd.CommandType            = System.Data.CommandType.Text;
                cmd.CommandTimeoutPerShard = 60;

                using (var reader = cmd.ExecuteReader()) {
                    if (reader.HasRows)
                    {
                        result = reader.ToExpandoList();
                    }
                }
            }

            return(result);
        }
        public void TestShardCommandTimeoutException()
        {
            var shardConnections = CreateConnections(10, () => { });

            Func <CancellationToken, MockSqlCommand, DbDataReader> executeReaderFunc = (token, cmd) =>
            {
                Thread.Sleep(TimeSpan.FromSeconds(2));
                return(new MockSqlDataReader());
            };
            var mockCmd = new MockSqlCommand();

            mockCmd.ExecuteReaderFunc = executeReaderFunc;
            mockCmd.CommandText       = "Select 1";
            using (var conn = new MultiShardConnection(shardConnections))
            {
                using (var cmd = MultiShardCommand.Create(conn, mockCmd, 1))
                {
                    cmd.ExecuteReader();
                }
            }
        }
示例#28
0
        public void TestSelect_PartialFailure_PartialResults()
        {
            using (MultiShardConnection conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
            {
                using (MultiShardCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText     = GetPartialFailureQuery();
                    cmd.ExecutionPolicy = MultiShardExecutionPolicy.PartialResults;

                    using (MultiShardDataReader sdr = cmd.ExecuteReader())
                    {
                        // Exactly one should have failed
                        Assert.AreEqual(1, sdr.MultiShardExceptions.Count);

                        // We should be able to read
                        while (sdr.Read())
                        {
                        }
                    }
                }
            }
        }
        public void TestShardCommandFaultHandler()
        {
            var shardConnections = CreateConnections(10, () => { });

            Func <CancellationToken, MockSqlCommand, DbDataReader> executeReaderFunc = (token, cmd) =>
            {
                throw new InsufficientMemoryException();
            };
            var mockCmd = new MockSqlCommand();

            mockCmd.ExecuteReaderFunc = executeReaderFunc;
            mockCmd.CommandText       = "Select 1";
            ConcurrentDictionary <ShardLocation, bool> passedLocations = new ConcurrentDictionary <ShardLocation, bool>();

            using (var conn = new MultiShardConnection(shardConnections))
            {
                using (var cmd = MultiShardCommand.Create(conn, mockCmd, 1))
                {
                    cmd.ExecutionPolicy        = MultiShardExecutionPolicy.PartialResults;
                    cmd.CommandTimeout         = 300;
                    cmd.ShardExecutionFaulted += new EventHandler <ShardExecutionEventArgs>((obj, eventArgs) =>
                    {
                        Assert.IsTrue(shardConnections.Select(x => x.Item1).Contains(eventArgs.ShardLocation), "The ShardLocation passed to the event handler does not exist in the set of passed in ShardLocations");
                        passedLocations[eventArgs.ShardLocation] = true;
                        Assert.IsInstanceOfType(eventArgs.Exception, typeof(InsufficientMemoryException), "An incorrect exception type was passed to the event handler.");
                    });
                    try
                    {
                        // We want to execute to completion so we get to the validation at the end of the function.
                        cmd.ExecuteReader();
                    }
                    catch { }
                }
            }

            Assert.AreEqual(shardConnections.Count, passedLocations.Count, "Not every ShardLocation had its corresponding event handler invoked.");
        }
        public void TestSelectNonQuery(string commandText, MultiShardExecutionPolicy policy)
        {
            using (MultiShardConnection conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
            {
                using (MultiShardCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText = commandText;
                    cmd.ExecutionPolicy = policy;

                    using (MultiShardDataReader sdr = cmd.ExecuteReader())
                    {
                        Assert.AreEqual(0, sdr.MultiShardExceptions.Count);

                        // TODO: This is a weird error message, but it's good enough for now
                        // Fixing this will require significant refactoring of MultiShardDataReader,
                        // we should fix it when we finish implementing async adding of child readers
                        AssertExtensions.AssertThrows<MultiShardDataReaderClosedException>(() => sdr.Read());
                    }
                }
            }
        }
        public MultiShardAggregateException TestSelectFailure(string commandText, MultiShardExecutionPolicy policy)
        {
            using (MultiShardConnection conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
            {
                using (MultiShardCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText = commandText;
                    cmd.ExecutionPolicy = policy;

                    // ExecuteReader should fail
                    MultiShardAggregateException aggregateException =
                        AssertExtensions.AssertThrows<MultiShardAggregateException>(() => cmd.ExecuteReader());

                    // Sanity check the exceptions are the correct type
                    foreach (Exception e in aggregateException.InnerExceptions)
                    {
                        Assert.IsInstanceOfType(e, typeof(MultiShardException));
                        Assert.IsInstanceOfType(e.InnerException, typeof(SqlException));
                    }

                    // Return the exception so that the caller can do additional validation
                    return aggregateException;
                }
            }
        }
        public void TestSelect_PartialFailure_PartialResults()
        {
            using (MultiShardConnection conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
            {
                using (MultiShardCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText = GetPartialFailureQuery();
                    cmd.ExecutionPolicy = MultiShardExecutionPolicy.PartialResults;

                    using (MultiShardDataReader sdr = cmd.ExecuteReader())
                    {
                        // Exactly one should have failed
                        Assert.AreEqual(1, sdr.MultiShardExceptions.Count);

                        // We should be able to read
                        while (sdr.Read())
                        {
                        }
                    }
                }
            }
        }
        public void TestQueryShardsAsync()
        {
            // Create new sharded connection so we can test the OpenAsync call as well.
            //
            using (MultiShardConnection conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
            {
                using (MultiShardCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText = "SELECT dbNameField, Test_int_Field, Test_bigint_Field  FROM ConsistentShardedTable";
                    cmd.CommandType = CommandType.Text;

                    using (MultiShardDataReader sdr = ExecAsync(conn, cmd).Result)
                    {
                        int recordsRetrieved = 0;
                        while (sdr.Read())
                        {
                            recordsRetrieved++;
                            var dbNameField = sdr.GetString(0);
                            var testIntField = sdr.GetFieldValue<int>(1);
                            var testBigIntField = sdr.GetFieldValue<Int64>(2);
                            Logger.Log("RecordRetrieved: dbNameField: {0}, TestIntField: {1}, TestBigIntField: {2}, RecordCount: {3}",
                                dbNameField, testIntField, testBigIntField, recordsRetrieved);
                        }

                        Assert.AreEqual(recordsRetrieved, 9);
                    }
                }
            }
        }
        public void TestShardResultFailures()
        {
            ProxyServer proxyServer = GetProxyServer();

            try
            {
                // Start up the proxy server.  Do it in a try so we can shut it down in the finally.
                // Also, we have to generate the proxyShardconnections *AFTER* we start up the server 
                // so that we know what port the proxy is listening on.  More on the placement
                // of the connection generation below.
                //
                proxyServer.Start();

                // PreKillReads is the number of successful reads to perform before killing
                // all the connections.  We start at 0 to test the no failure case as well.
                //
                for (int preKillReads = 0; preKillReads <= 10; preKillReads++)
                {
                    // Additionally, since we are running inside a loop, we need to regenerate the proxy shard connections each time
                    // so that we don't re-use dead connections.  If we do that we will end up hung in the read call.
                    //
                    List<Tuple<ShardLocation, DbConnection>> proxyShardConnections = GetProxyShardConnections(proxyServer);
                    using (MultiShardConnection conn = new MultiShardConnection(proxyShardConnections))
                    {
                        using (MultiShardCommand cmd = conn.CreateCommand())
                        {
                            cmd.CommandText = "SELECT db_name() as dbName1, REPLICATE(db_name(), 1000) as longExpr, db_name() as dbName2 FROM ConsistentShardedTable";
                            cmd.CommandType = CommandType.Text;

                            cmd.ExecutionPolicy = MultiShardExecutionPolicy.PartialResults;
                            cmd.ExecutionOptions = MultiShardExecutionOptions.IncludeShardNameColumn;

                            using (MultiShardDataReader sdr = cmd.ExecuteReader(CommandBehavior.Default))
                            {
                                int tuplesRead = 0;

                                while (sdr.Read())
                                {
                                    // Read part of the tuple first before killing the connections and
                                    // then attempting to read the rest of the tuple.
                                    //
                                    tuplesRead++;

                                    try
                                    {
                                        // The longExpr should contain the first dbName field multiple times.
                                        //
                                        string dbName1 = sdr.GetString(0);
                                        string longExpr = sdr.GetString(1);
                                        Assert.IsTrue(longExpr.Contains(dbName1));

                                        if (tuplesRead == preKillReads)
                                        {
                                            proxyServer.KillAllConnections();
                                        }

                                        // The second dbName field should be the same as the first dbName field.
                                        //
                                        string dbName2 = sdr.GetString(2);
                                        Assert.AreEqual(dbName1, dbName2);

                                        // The shardId should contain both the first and the second dbName fields.
                                        //
                                        string shardId = sdr.GetString(3);
                                        Assert.IsTrue(shardId.Contains(dbName1));
                                        Assert.IsTrue(shardId.Contains(dbName2));
                                    }
                                    catch (Exception ex)
                                    {
                                        // We've seen some failures here due to an attempt to access a socket after it has
                                        // been disposed.  The only place where we are attempting to access the socket
                                        // is in the call to proxyServer.KillAllConnections.  Unfortunately, it's not clear
                                        // what is causing that problem since it only appears to repro in the lab.
                                        // I (errobins) would rather not blindly start changing things in the code (either
                                        // our code above, our exception handling code here, or the proxyServer code) until
                                        // we know which socket we are trying to access when we hit this problem.
                                        // So, the first step I will take is to pull additional exception information
                                        // so that we can see some more information about what went wrong the next time it repros.
                                        //
                                        Assert.Fail("Unexpected exception, rethrowing.  Here is some info: \n Message: {0} \n Source: {1} \n StackTrace: {2}",
                                            ex.Message, ex.Source, ex.StackTrace);
                                        throw;
                                    }
                                }

                                Assert.IsTrue((tuplesRead <= preKillReads) || (0 == preKillReads),
                                    String.Format("Tuples read was {0}, Pre-kill reads was {1}", tuplesRead, preKillReads));
                            }
                        }
                    }
                }
            }
            finally
            {
                // Be sure to shut down the proxy server.    
                //
                string proxyLog = proxyServer.EventLog.ToString();
                Logger.Log(proxyLog);
                proxyServer.Stop();
            }
        }
        public void MyTestInitialize()
        {
            _shardMap = MultiShardTestUtils.CreateAndGetTestShardMap();

            _shardConnection = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString);
        }
        private async Task<MultiShardDataReader> ExecAsync(MultiShardConnection conn, MultiShardCommand cmd)
        {
            cmd.ExecutionPolicy = MultiShardExecutionPolicy.PartialResults;
            cmd.ExecutionOptions = MultiShardExecutionOptions.IncludeShardNameColumn;

            return await cmd.ExecuteReaderAsync(CommandBehavior.Default, CancellationToken.None);
        }
 public void TestQueryShardsInvalidConnectionSync()
 {
     var badShard = new ShardLocation("badLocation", "badDatabase");
     var bldr = new SqlConnectionStringBuilder();
     bldr.DataSource = badShard.DataSource;
     bldr.InitialCatalog = badShard.Database;
     var badConn = new SqlConnection(bldr.ConnectionString);
     try
     {
         using (var conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
         {
             conn.ShardConnections.Add(new Tuple<ShardLocation, System.Data.Common.DbConnection>(badShard,
                 badConn));
             using (var cmd = conn.CreateCommand())
             {
                 cmd.CommandText = "select 1";
                 cmd.ExecuteReader();
             }
         }
     }
     catch (Exception ex)
     {
         if (ex is MultiShardAggregateException)
         {
             var maex = (MultiShardAggregateException)ex;
             Logger.Log("Exception encountered: " + maex.ToString());
             throw ((MultiShardException)(maex.InnerException)).InnerException;
         }
         throw;
     }
 }
        public void TestInvalidMultiShardConnectionString()
        {
            MultiShardConnection conn;

            try
            {
                conn = new MultiShardConnection(_shardMap.GetShards(), connectionString: null);
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is ArgumentNullException, "Expected ArgumentNullException!");
            }

            try
            {
                conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardMapManagerConnectionString);
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is ArgumentException, "Expected ArgumentException!");
            }

            // Validate that the ApplicationName is updated properly
            var applicationStringBldr = new StringBuilder();
            for (int i = 0; i < ApplicationNameHelper.MaxApplicationNameLength; i++)
            {
                applicationStringBldr.Append('x');
            }
            string applicationName = applicationStringBldr.ToString();
            SqlConnectionStringBuilder connStringBldr = new SqlConnectionStringBuilder(MultiShardTestUtils.ShardConnectionString);
            connStringBldr.ApplicationName = applicationName;
            conn = new MultiShardConnection(_shardMap.GetShards(), connStringBldr.ConnectionString);

            string updatedApplicationName = new SqlConnectionStringBuilder
                (conn.ShardConnections[0].Item2.ConnectionString).ApplicationName;
            Assert.IsTrue(updatedApplicationName.Length == ApplicationNameHelper.MaxApplicationNameLength &&
                updatedApplicationName.EndsWith(MultiShardConnection.ApplicationNameSuffix), "ApplicationName not appended with {0}!",
                MultiShardConnection.ApplicationNameSuffix);
        }
 public void TestCreateConnectionWithNoShards()
 {
     using (MultiShardConnection conn = new MultiShardConnection(new Shard[] { }, String.Empty))
     {
         Assert.Fail("Should have failed in the MultiShardConnection c-tor.");
     }
 }
        public void TestFailedCommandWithConnectionCloseCmdBehavior()
        {
            Parallel.For(0, 100, i =>
            {
                try
                {
                    using (MultiShardConnection conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
                    {
                        using (MultiShardCommand cmd = conn.CreateCommand())
                        {
                            cmd.CommandText = "select * from table_does_not_exist";
                            cmd.CommandType = CommandType.Text;

                            using (MultiShardDataReader sdr = cmd.ExecuteReader())
                            {
                                while (sdr.Read())
                                {
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Encountered exception: {0} in iteration: {1}",
                        ex.ToString(), i);
                }
                finally
                {
                    Console.WriteLine("Completed execution of iteration: {0}", i);
                }
            });
        }
        public void TestSelectNoRows(string commandText, MultiShardExecutionPolicy policy)
        {
            using (MultiShardConnection conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
            {
                using (MultiShardCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText = commandText;
                    cmd.ExecutionPolicy = policy;

                    // Read first
                    using (MultiShardDataReader sdr = cmd.ExecuteReader())
                    {
                        Assert.AreEqual(0, sdr.MultiShardExceptions.Count);
                        while (sdr.Read())
                        {
                            Assert.Fail("Should not have gotten any records.");
                        }
                        Assert.IsFalse(sdr.HasRows);
                    }

                    // HasRows first
                    using (MultiShardDataReader sdr = cmd.ExecuteReader())
                    {
                        Assert.AreEqual(0, sdr.MultiShardExceptions.Count);
                        Assert.IsFalse(sdr.HasRows);
                        while (sdr.Read())
                        {
                            Assert.Fail("Should not have gotten any records.");
                        }
                    }
                }
            }
        }
        public void TestSimpleSelect(MultiShardExecutionPolicy policy)
        {
            // What we're doing:
            // Grab all rows from each test database.
            // Load them into a MultiShardDataReader.
            // Iterate through the rows and make sure that we have 9 total.
            //
            using (MultiShardConnection conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
            {
                using (MultiShardCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText = "SELECT dbNameField, Test_int_Field, Test_bigint_Field FROM ConsistentShardedTable";
                    cmd.ExecutionOptions = MultiShardExecutionOptions.IncludeShardNameColumn;
                    cmd.ExecutionPolicy = policy;

                    using (MultiShardDataReader sdr = cmd.ExecuteReader())
                    {
                        int recordsRetrieved = 0;
                        Logger.Log("Starting to get records");
                        while (sdr.Read())
                        {
                            recordsRetrieved++;
                            string dbNameField = sdr.GetString(0);
                            int testIntField = sdr.GetFieldValue<int>(1);
                            Int64 testBigIntField = sdr.GetFieldValue<Int64>(2);
                            string shardIdPseudoColumn = sdr.GetFieldValue<string>(3);
                            string logRecord =
                                string.Format(
                                    "RecordRetrieved: dbNameField: {0}, TestIntField: {1}, TestBigIntField: {2}, shardIdPseudoColumnField: {3}, RecordCount: {4}",
                                    dbNameField, testIntField, testBigIntField, shardIdPseudoColumn, recordsRetrieved);
                            Logger.Log(logRecord);
                            Debug.WriteLine(logRecord);
                        }

                        sdr.Close();

                        Assert.AreEqual(recordsRetrieved, 9);
                    }
                }
            }
        }
        public void TestSchemaMismatchErrorPropagation()
        {
            // First we need to alter the schema on one of the shards - we'll choose the last one.
            //
            string origColName = "Test_bigint_Field";
            string newColName = "ModifiedName";

            MultiShardTestUtils.ChangeColumnNameOnShardedTable(2, origColName, newColName);

            // Then create new sharded connection so we can test the error handling logic.
            // We'll wrap this all in a try-catch-finally block so that we can change the schema back
            // to what the other tests will expect it to be in the finally.
            //
            try
            {
                using (MultiShardConnection conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
                {
                    using (MultiShardCommand cmd = conn.CreateCommand())
                    {
                        // Need to do a SELECT * in order to get the column name error as a schema mismatcherror.  If we name it explicitly
                        // we will get a command execution error instead.
                        //
                        cmd.CommandText = "SELECT * FROM ConsistentShardedTable";
                        cmd.CommandType = CommandType.Text;

                        using (MultiShardDataReader sdr = ExecAsync(conn, cmd).Result)
                        {
                            // The number of errors we have depends on which shard executed first.
                            // So, we know it should be 1 OR 2.
                            //
                            Assert.IsTrue(
                                ((sdr.MultiShardExceptions.Count == 1) || (sdr.MultiShardExceptions.Count == 2)),
                                string.Format("Expected 1 or 2 execution erros, but saw {0}", sdr.MultiShardExceptions.Count));

                            int recordsRetrieved = 0;
                            while (sdr.Read())
                            {
                                recordsRetrieved++;
                                var dbNameField = sdr.GetString(0);
                            }

                            // We should see 9 records less 3 for each one that had a schema error.
                            int expectedRecords = ((9 - (3 * sdr.MultiShardExceptions.Count)));

                            Assert.AreEqual(recordsRetrieved, expectedRecords);
                        }
                    }
                }
            }
            finally
            {
                MultiShardTestUtils.ChangeColumnNameOnShardedTable(2, newColName, origColName);
            }
        }
示例#44
0
        public List <string[]> ExecuteMultiShardQuery(ListShardMap <int> shardMap, string credentialsConnectionString)
        {
            // Get the shards to connect to
            IEnumerable <Shard> shards = shardMap.GetShards();

            // Create the multi-shard connection
            using (MultiShardConnection conn = new MultiShardConnection(shards, credentialsConnectionString))
            {
                // Create a simple command
                using (MultiShardCommand cmd = conn.CreateCommand())
                {
                    // Because this query is grouped by CustomerID, which is sharded,
                    // we will not get duplicate rows.
                    cmd.CommandText = @"
                        SELECT 
                            c.CustomerId, 
                            c.Name AS CustomerName, 
                            o.OrderID AS OrderCount
                        FROM 
                            dbo.Customers AS c INNER JOIN 
                            dbo.Orders AS o
                            ON c.CustomerID = o.CustomerID
                        
                        ORDER BY 
                            1";

                    // Append a column with the shard name where the row came from
                    cmd.ExecutionOptions = MultiShardExecutionOptions.IncludeShardNameColumn;

                    // Allow for partial results in case some shards do not respond in time
                    cmd.ExecutionPolicy = MultiShardExecutionPolicy.PartialResults;

                    // Allow the entire command to take up to 30 seconds
                    cmd.CommandTimeout = 30;

                    // Execute the command.
                    // We do not need to specify retry logic because MultiShardDataReader will internally retry until the CommandTimeout expires.
                    using (MultiShardDataReader reader = cmd.ExecuteReader())
                    {
                        // Get the column names
                        TableFormatter formatter = new TableFormatter(GetColumnNames(reader).ToArray());

                        int rows = 0;
                        while (reader.Read())
                        {
                            // Read the values using standard DbDataReader methods
                            object[] values = new object[reader.FieldCount];
                            reader.GetValues(values);

                            // Extract just database name from the $ShardLocation pseudocolumn to make the output formater cleaner.
                            // Note that the $ShardLocation pseudocolumn is always the last column
                            int shardLocationOrdinal = values.Length - 1;
                            values[shardLocationOrdinal] = ExtractDatabaseName(values[shardLocationOrdinal].ToString());

                            // Add values to output formatter
                            formatter.AddRow(values);

                            rows++;
                        }

                        Console.WriteLine(formatter.ToString());
                        Console.WriteLine("({0} rows returned)", rows);

                        return(formatter._rows);
                    }
                }
            }
        }
        public void TestShardNamePseudoColumnOption()
        {
            bool[] pseudoColumnOptions = new bool[2];
            pseudoColumnOptions[0] = true;
            pseudoColumnOptions[1] = false;

            // do the loop over the options.
            // add the excpetion handling when referencing the pseudo column
            //
            foreach (bool pseudoColumnPresent in pseudoColumnOptions)
            {
                using (MultiShardConnection conn = new MultiShardConnection(_shardMap.GetShards(), MultiShardTestUtils.ShardConnectionString))
                {
                    using (MultiShardCommand cmd = conn.CreateCommand())
                    {
                        cmd.CommandText = "SELECT dbNameField, Test_int_Field, Test_bigint_Field  FROM ConsistentShardedTable";
                        cmd.CommandType = CommandType.Text;

                        cmd.ExecutionPolicy = MultiShardExecutionPolicy.CompleteResults;
                        cmd.ExecutionOptions = pseudoColumnPresent ? MultiShardExecutionOptions.IncludeShardNameColumn :
                            MultiShardExecutionOptions.None;
                        using (MultiShardDataReader sdr = cmd.ExecuteReader(CommandBehavior.Default))
                        {
                            Assert.AreEqual(0, sdr.MultiShardExceptions.Count);

                            int recordsRetrieved = 0;

                            int expectedFieldCount = pseudoColumnPresent ? 4 : 3;
                            int expectedVisibleFieldCount = pseudoColumnPresent ? 4 : 3;
                            Assert.AreEqual(expectedFieldCount, sdr.FieldCount);
                            Assert.AreEqual(expectedVisibleFieldCount, sdr.VisibleFieldCount);

                            while (sdr.Read())
                            {
                                recordsRetrieved++;
                                var dbNameField = sdr.GetString(0);
                                var testIntField = sdr.GetFieldValue<int>(1);
                                var testBigIntField = sdr.GetFieldValue<Int64>(2);

                                try
                                {
                                    string shardIdPseudoColumn = sdr.GetFieldValue<string>(3);
                                    if (!pseudoColumnPresent)
                                    {
                                        Assert.Fail("Should not have been able to pull the pseudo column.");
                                    }
                                }
                                catch (IndexOutOfRangeException)
                                {
                                    if (pseudoColumnPresent)
                                    {
                                        Assert.Fail("Should not have encountered an exception.");
                                    }
                                }
                            }

                            Assert.AreEqual(recordsRetrieved, 9);
                        }
                    }
                }
            }
        }