Beispiel #1
0
        /// <summary>
        /// Create the contents of the RTable configuration, and upload it to the appropriate container and blob.
        /// </summary>
        private void UploadRTableConfigToBlob(int viewId, bool convertXStoreTableMode, int numberOfBlobs)
        {
            string blobName = this.configurationInfos.FirstOrDefault().BlobPath;
            int    index    = blobName.IndexOf("/");

            blobName = blobName.Substring(index + 1); // +1 to acording for "/"

            Console.WriteLine("Uploading RTable config ...");

            for (int blobIndex = 0; blobIndex < numberOfBlobs; blobIndex++)
            {
                string          connectionString;
                CloudBlobClient cloudBloblClient = this.GenerateCloudBlobClient(
                    this.rtableTestConfiguration.StorageInformation.AccountNames[blobIndex],
                    this.rtableTestConfiguration.StorageInformation.AccountKeys[blobIndex],
                    this.rtableTestConfiguration.StorageInformation.DomainName,
                    out connectionString);

                CloudBlobContainer container = cloudBloblClient.GetContainerReference(this.rtableTestConfiguration.RTableInformation.ContainerName);
                container.CreateIfNotExists();

                CloudBlockBlob blockBlob = container.GetBlockBlobReference(blobName);

                ReplicatedTableConfigurationStore configuration = this.GetRTableConfiguration(viewId, convertXStoreTableMode);

                string jsonConfigText = JsonStore <ReplicatedTableConfigurationStore> .Serialize(configuration);

                blockBlob.UploadText(jsonConfigText);
            }
        }
        public void TestReplicatedTableConfigurationStoreEquality()
        {
            var conf1 = new ReplicatedTableConfigurationStore
            {
                ViewId = 5,
            };

            Assert.IsFalse(conf1.Equals(null));

            // - vs. different viewId
            var conf2 = new ReplicatedTableConfigurationStore
            {
                ViewId = 6,
            };

            Assert.IsFalse(conf1.Equals(conf2));

            // vs. same viewId
            var conf3 = new ReplicatedTableConfigurationStore
            {
                ViewId = 5,
            };

            Assert.IsTrue(conf1.Equals(conf3));
        }
Beispiel #3
0
        /// <summary>
        /// Helper function to return the RTableConfig
        /// Note that even if 3 (say) accounts are specified in the xml,
        /// the test codes can specify that only accounts #0 and #2 are used to construct the RTable.
        /// </summary>
        /// <param name="viewId"></param>
        /// <param name="convertXStoreTableMode"></param>
        /// <param name="readViewHeadIndex"></param>
        /// <returns></returns>
        private ReplicatedTableConfiguration GetRTableConfiguration(long viewId, bool convertXStoreTableMode, int readViewHeadIndex = 0)
        {
            if (viewId <= 0)
            {
                throw new Exception(string.Format("GetRTableConfigText() was called with invalid viewId {0}", viewId));
            }

            // 1 - Create a default view
            var viewConfig = new ReplicatedTableConfigurationStore
            {
                ViewId            = viewId,
                ReadViewHeadIndex = readViewHeadIndex,
            };

            int numberOfStorageAccounts = this.rtableTestConfiguration.StorageInformation.AccountNames.Count();

            for (int i = 0; i < this.actualStorageAccountsUsed.Count; i++)
            {
                int index = this.actualStorageAccountsUsed[i];
                if (index < 0 || index > numberOfStorageAccounts)
                {
                    throw new Exception(string.Format("this.actualStorageAccountsUsed[{0}] = {1} is out of range.", i, index));
                }

                ReplicaInfo replica = new ReplicaInfo
                {
                    StorageAccountName = this.rtableTestConfiguration.StorageInformation.AccountNames[index],
                    Status             = ReplicaStatus.ReadWrite,
                };

                if (readViewHeadIndex != 0 && i < readViewHeadIndex)
                {
                    replica.Status = ReplicaStatus.WriteOnly;
                }

                viewConfig.ReplicaChain.Add(replica);
            }

            // 2 - Create a default table config. that references the "DefaultView"
            var tableConfig = new ReplicatedTableConfiguredTable
            {
                TableName       = DefaultTableConfigName,
                ViewName        = DefaultViewName,
                ConvertToRTable = convertXStoreTableMode,
                UseAsDefault    = true,
            };

            // 3 - Create the final RTable configuration
            ReplicatedTableConfiguration configuration = new ReplicatedTableConfiguration();

            configuration.SetView(DefaultViewName, viewConfig);
            configuration.SetTable(tableConfig);

            return(configuration);
        }
        private void SetReadViewTailIndex(int index)
        {
            View view = this.configurationWrapper.GetWriteView();

            ReplicatedTableConfiguration    config;
            ReplicatedTableQuorumReadResult readStatus = this.configurationService.RetrieveConfiguration(out config);

            Assert.IsTrue(readStatus.Code == ReplicatedTableQuorumReadCode.Success);

            ReplicatedTableConfigurationStore viewConfg = config.GetView(view.Name);

            viewConfg.ReadViewTailIndex = index;

            this.configurationService.UpdateConfiguration(config);
        }
        private void SetConfigViewIdAndIgnoreHigherViewIdRowsFlag(long viewId, bool ignoreHigherViewIdRowsFlag)
        {
            View view = this.configurationWrapper.GetWriteView();

            ReplicatedTableConfiguration    config;
            ReplicatedTableQuorumReadResult readStatus = this.configurationService.RetrieveConfiguration(out config);

            Assert.IsTrue(readStatus.Code == ReplicatedTableQuorumReadCode.Success);

            ReplicatedTableConfigurationStore viewConfg = config.GetView(view.Name);

            viewConfg.ViewId = viewId;

            config.SetIgnoreHigherViewIdRowsFlag(ignoreHigherViewIdRowsFlag);

            this.configurationService.UpdateConfiguration(config);
        }
Beispiel #6
0
        /// <summary>
        /// Modify the contents of the RTable configuration blob to use the updated viewId
        /// </summary>
        /// <param name="updatedViewId"></param>
        /// <param name="convertXStoreTableMode"></param>
        /// <param name="readViewHeadIndex"></param>
        private void ModifyConfigurationBlob(long updatedViewId, bool convertXStoreTableMode, int readViewHeadIndex, List <int> blobIndexes)
        {
            try
            {
                foreach (var blobIndex in blobIndexes)
                {
                    Console.WriteLine("ModifyConfigurationBlob#{0} ...", blobIndex);

                    string blobName = this.configurationInfos[blobIndex].BlobPath;
                    int    index    = blobName.IndexOf("/");
                    blobName = blobName.Substring(index + 1); // +1 to acording for "/"

                    Console.WriteLine("Configuration blobname = {0}", blobName);

                    string          connectionString;
                    CloudBlobClient cloudBloblClient = this.GenerateCloudBlobClient(
                        this.rtableTestConfiguration.StorageInformation.AccountNames[blobIndex],
                        this.rtableTestConfiguration.StorageInformation.AccountKeys[blobIndex],
                        this.rtableTestConfiguration.StorageInformation.DomainName,
                        out connectionString);

                    CloudBlobContainer container =
                        cloudBloblClient.GetContainerReference(
                            this.rtableTestConfiguration.RTableInformation.ContainerName);
                    CloudBlockBlob blockBlob = container.GetBlockBlobReference(blobName);

                    string currentConfigText = blockBlob.DownloadText();
                    Console.WriteLine("currentConfigText = {0}", currentConfigText);

                    ReplicatedTableConfigurationStore configuration = this.GetRTableConfiguration(updatedViewId,
                                                                                                  convertXStoreTableMode, readViewHeadIndex);

                    string updatedConfigText = JsonStore <ReplicatedTableConfigurationStore> .Serialize(configuration);

                    Console.WriteLine("updatedConfigText = {0}", updatedConfigText);

                    blockBlob.UploadText(updatedConfigText);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("ModifyConfigurationBlob() encountered exception {0}", ex.ToString());
                throw;
            }
        }
        private void InsertHeadInView(string viewName, int leaseDuration, ReplicatedTableConfigurationServiceV2 configService)
        {
            // Download config using provided instance
            ReplicatedTableConfiguration    config;
            ReplicatedTableQuorumReadResult readStatus = configurationService.RetrieveConfiguration(out config);

            Assert.IsTrue(readStatus.Code == ReplicatedTableQuorumReadCode.Success);

            // Add the Head
            ReplicatedTableConfigurationStore viewConfg = config.GetView(viewName);

            viewConfg.ReplicaChain[0].Status = ReplicaStatus.WriteOnly;
            viewConfg.ViewId++;

            config.LeaseDuration = leaseDuration;

            // Upload config using provided instance
            configService.UpdateConfiguration(config);
        }
        public void TestGetCurrentReplicaChain()
        {
            var conf = new ReplicatedTableConfigurationStore();

            conf.ReplicaChain.Add(new ReplicaInfo
            {
                Status = ReplicaStatus.None,
            });
            conf.ReplicaChain.Add(new ReplicaInfo
            {
                Status = ReplicaStatus.ReadOnly,
            });
            conf.ReplicaChain.Add(new ReplicaInfo
            {
                Status = ReplicaStatus.None,
            });
            conf.ReplicaChain.Add(new ReplicaInfo
            {
                Status = ReplicaStatus.ReadWrite,
            });
            conf.ReplicaChain.Add(new ReplicaInfo
            {
                Status = ReplicaStatus.WriteOnly,
            });
            conf.ReplicaChain.Add(new ReplicaInfo
            {
                Status = ReplicaStatus.None,
            });
            conf.ReplicaChain.Add(new ReplicaInfo
            {
                Status = ReplicaStatus.ReadWrite,
            });
            conf.ReplicaChain.Add(new ReplicaInfo
            {
                Status = ReplicaStatus.None,
            });

            // only Active replicas are returned i.e. RO, WO and RW
            var chain = conf.GetCurrentReplicaChain();

            Assert.IsFalse(chain.Any(r => r.Status == ReplicaStatus.None));
        }
Beispiel #9
0
        /// <summary>
        /// Helper function to return the RTableConfig
        /// Note that even if 3 (say) accounts are specified in the xml,
        /// the test codes can specify that only accounts #0 and #2 are used to construct the RTable.
        /// </summary>
        /// <param name="viewId"></param>
        /// <param name="convertXStoreTableMode"></param>
        /// <param name="readViewHeadIndex"></param>
        /// <returns></returns>
        private ReplicatedTableConfigurationStore GetRTableConfiguration(long viewId, bool convertXStoreTableMode, int readViewHeadIndex = 0)
        {
            if (viewId <= 0)
            {
                throw new Exception(string.Format("GetRTableConfigText() was called with invalid viewId {0}", viewId));
            }

            ReplicatedTableConfigurationStore configuration = new ReplicatedTableConfigurationStore();

            configuration.ViewId                 = viewId;
            configuration.ReadViewHeadIndex      = readViewHeadIndex;
            configuration.ConvertXStoreTableMode = convertXStoreTableMode;

            int numberOfStorageAccounts = this.rtableTestConfiguration.StorageInformation.AccountNames.Count();

            for (int i = 0; i < this.actualStorageAccountsUsed.Count; i++)
            {
                int index = this.actualStorageAccountsUsed[i];
                if (index < 0 || index > numberOfStorageAccounts)
                {
                    throw new Exception(string.Format("this.actualStorageAccountsUsed[{0}] = {1} is out of range.", i, index));
                }

                ReplicaInfo replica = new ReplicaInfo();
                replica.StorageAccountName = this.rtableTestConfiguration.StorageInformation.AccountNames[index];

                if (readViewHeadIndex != 0)
                {
                    //If the read view head index is not 0, this means we are introducing 1 or more replicas at the head. For
                    //each such replica, update the view id in which it was added to the write view of the chain
                    if (i < readViewHeadIndex)
                    {
                        replica.ViewInWhichAddedToChain = viewId;
                    }
                }

                configuration.ReplicaChain.Add(replica);
            }

            return(configuration);
        }
Beispiel #10
0
        private void EnableTailInView(string viewName, int leaseDuration, ReplicatedTableConfigurationServiceV2 configService)
        {
            // Download config using provided instance
            ReplicatedTableConfiguration    config;
            ReplicatedTableQuorumReadResult readStatus = configurationService.RetrieveConfiguration(out config);

            Assert.IsTrue(readStatus.Code == ReplicatedTableQuorumReadCode.Success);

            // Enable the Tail
            ReplicatedTableConfigurationStore viewConfg = config.GetView(viewName);

            Assert.IsTrue(viewConfg.ReplicaChain.Count == 2);
            Assert.IsTrue(viewConfg.ReadViewTailIndex == 0);

            viewConfg.ReplicaChain[1].Status = ReplicaStatus.ReadWrite;
            viewConfg.ViewId++;

            config.LeaseDuration = leaseDuration;

            // Upload config using provided instance
            configService.UpdateConfiguration(config);
        }
Beispiel #11
0
        private void UploadHeadTailView(string viewName, int leaseDuration, ReplicatedTableConfigurationServiceV2 configService)
        {
            // Download config using provided instance
            ReplicatedTableConfiguration    config;
            ReplicatedTableQuorumReadResult readStatus = configService.RetrieveConfiguration(out config);

            Assert.IsTrue(readStatus.Code == ReplicatedTableQuorumReadCode.Success);

            // [Head] -> [Tail]
            ReplicatedTableConfigurationStore viewConfg = config.GetView(viewName);

            Assert.IsTrue(viewConfg.GetCurrentReplicaChain().Count == 2);

            // Force Reads on Head replica
            viewConfg.ReadViewTailIndex = 0;
            viewConfg.ViewId++;

            config.LeaseDuration = leaseDuration;

            // Upload config using provided instance
            configService.UpdateConfiguration(config);
        }
Beispiel #12
0
        protected void UpdateConfiguration(List <ReplicaInfo> replicaChain, int readViewHeadIndex, bool convertXStoreTableMode = false, long viewId = 0)
        {
            for (int i = 0; i < replicaChain.Count; i++)
            {
                replicaChain[i].Status = ReplicaStatus.ReadWrite;

                if (readViewHeadIndex != 0 && i < readViewHeadIndex)
                {
                    replicaChain[i].Status = ReplicaStatus.WriteOnly;
                }
            }

            // - view config
            var viewConfig = new ReplicatedTableConfigurationStore
            {
                ViewId            = viewId,
                ReadViewHeadIndex = readViewHeadIndex,
                ReplicaChain      = replicaChain,
            };

            // - table config
            var tableConfig = new ReplicatedTableConfiguredTable
            {
                TableName       = DefaultTableConfigName,
                ViewName        = DefaultViewName,
                ConvertToRTable = convertXStoreTableMode,
                UseAsDefault    = true,
            };

            // - Update RTable configuration
            ReplicatedTableConfiguration configuration = new ReplicatedTableConfiguration();

            configuration.SetView(DefaultViewName, viewConfig);
            configuration.SetTable(tableConfig);

            this.configurationService.UpdateConfiguration(configuration, false);
        }
Beispiel #13
0
        public void RepairMidAnUpdate()
        {
            this.rtableWrapper = RTableWrapperForSampleRTableEntity.GetRTableWrapper(this.repTable);

            // Not-Stable chain
            // Reconfigure RTable so Head is WriteOnly.
            View view = this.configurationService.GetTableView(this.repTable.TableName);

            ReplicatedTableConfiguration    config;
            ReplicatedTableQuorumReadResult readStatus = this.configurationService.RetrieveConfiguration(out config);

            Assert.IsTrue(readStatus.Code == ReplicatedTableQuorumReadCode.Success);

            // Set Head as WriteOnly mode
            ReplicatedTableConfigurationStore viewConfg = config.GetView(view.Name);

            viewConfg.ReplicaChain[0].Status = ReplicaStatus.WriteOnly;
            config.SetView(view.Name, viewConfg);

            // Upload RTable config back
            this.configurationService.UpdateConfiguration(config);

            // Sanity: Replicated mode and chain Not-Stable
            view = this.configurationService.GetTableView(this.repTable.TableName);
            Assert.IsTrue(view != null && view.Chain.Count > 1, "Two replicas should be used.");
            Assert.IsFalse(view.IsStable);


            // Insert one entry
            Console.WriteLine("Inserting entry ...");
            string entityPartitionKey = "jobType-RepairMidAnUpdate-Replace";
            string entityRowKey       = "jobId-RepairMidAnUpdate-Replace";
            var    entry = new SampleRTableEntity(entityPartitionKey, entityRowKey, "message");

            this.rtableWrapper.InsertRow(entry);


            // 1 - Launch a RepairRow task in wait mode ...
            bool triggerRepair            = false;
            bool repaireDone              = false;
            bool headAfterRepairWasLocked = false;

            TableResult repairResult = null;

            Task.Run(() =>
            {
                ReplicatedTable repairTable = new ReplicatedTable(this.repTable.TableName, this.configurationService);

                while (!triggerRepair)
                {
                    Thread.Sleep(5);
                }

                Console.WriteLine("RepairRow started ...");
                repairResult = repairTable.RepairRow(entry.PartitionKey, entry.RowKey, null);
                Console.WriteLine("RepairRow completed with HttpStatus={0}", repairResult == null ? "NULL" : repairResult.HttpStatusCode.ToString());

                // Check the entry at the Head is still locked i.e. RepairRow was NOP
                headAfterRepairWasLocked = HeadIsLocked(entry);

                Console.WriteLine("Signal the commit to Head job");
                repaireDone = true;
            });


            // 2 - Configure Mangler ...
            string accountNameToTamper = this.rtableTestConfiguration.StorageInformation.AccountNames[0];

            Console.WriteLine("RunHttpManglerBehaviorHelper(): accountNameToTamper={0}", accountNameToTamper);

            ProxyBehavior[] behaviors = new[]
            {
                TamperBehaviors.TamperAllRequestsIf(
                    (session =>
                {
                    Console.WriteLine("Delaying commit to the Head ... => signal RepairRow job");

                    // Let RepairRow task go through
                    triggerRepair = true;

                    int iter = 0;
                    while (!repaireDone)
                    {
                        // TODO: break the loop after couple of iteration ...

                        Thread.Sleep(100);
                        Console.WriteLine("Waiting on RepairRow to finish ({0}) ...", ++iter);
                    }

                    Console.WriteLine("Request a commit to the head");
                }),
                    (session =>
                {
                    // Commit on head i.e. a PUT with RowLock == false
                    if (session.hostname.Contains(accountNameToTamper + ".") &&
                        session.HTTPMethodIs("PUT") &&
                        session.GetRequestBodyAsString().Contains("\"_rtable_RowLock\":false"))
                    {
                        return(true);
                    }

                    return(false);
                }))
            };

            using (new HttpMangler(false, behaviors))
            {
                Console.WriteLine("Updating entry ...");
                entry         = this.rtableWrapper.FindRow(entry.PartitionKey, entry.RowKey);
                entry.Message = "updated message";

                this.rtableWrapper.ReplaceRow(entry);
            }

            Assert.IsTrue(triggerRepair);
            Assert.IsTrue(repairResult != null && repairResult.HttpStatusCode == (int)HttpStatusCode.OK, "Repair failed.");
            Assert.IsTrue(repaireDone);
            Assert.IsTrue(headAfterRepairWasLocked);

            Console.WriteLine("DONE. Test passed.");
        }
        public void CaseNoRepair_ReadRowFromNewViewCutOffTailUpdateRow()
        {
            string firstName = "FirstName";
            string lastName  = "LastName";

            TableOperation operation;
            TableResult    result;
            CustomerEntity customer;

            // - View has 2 replicas ?
            View view = this.configurationWrapper.GetWriteView();

            Assert.IsTrue(view.Chain.Count == 2, "expects 2 replicas only!");


            // 1 - [None]->[RW]
            ReplicatedTableConfiguration config;

            this.configurationService.RetrieveConfiguration(out config);
            ReplicatedTableConfigurationStore viewConfg = config.GetView(view.Name);

            viewConfg.ReplicaChain[0].Status = ReplicaStatus.None;
            viewConfg.ViewId++;
            this.configurationService.UpdateConfiguration(config);

            // *** - Insert entries in old viewId
            var rtable = new ReplicatedTable(this.repTable.TableName, this.configurationService);

            for (int i = 0; i < 3; i++)
            {
                customer = new CustomerEntity(firstName + i, lastName + i);

                operation = TableOperation.Insert(customer);
                rtable.Execute(operation);
            }


            // 2 - Insert Head => [WO]->[RW]
            this.configurationService.RetrieveConfiguration(out config);
            viewConfg = config.GetView(view.Name);
            viewConfg.ReplicaChain[0].Status = ReplicaStatus.WriteOnly;
            viewConfg.ViewId++;
            this.configurationService.UpdateConfiguration(config);

            // *** - Insert entries in new viewId
            rtable = new ReplicatedTable(this.repTable.TableName, this.configurationService);
            for (int i = 10; i < 13; i++)
            {
                customer = new CustomerEntity(firstName + i, lastName + i);

                operation = TableOperation.Insert(customer);
                rtable.Execute(operation);
            }


            // => Read old entry - from Tail -
            int entryId = 10;

            operation = TableOperation.Retrieve <CustomerEntity>(firstName + entryId, lastName + entryId);
            result    = rtable.Execute(operation);


            // 3 - Cut-off Tail without repairing replicas
            configurationService.RetrieveConfiguration(out config);
            viewConfg = config.GetView(view.Name);
            viewConfg.ReplicaChain[0].Status = ReplicaStatus.ReadWrite;
            viewConfg.ReplicaChain[1].Status = ReplicaStatus.None;
            viewConfg.ViewId++;
            this.configurationService.UpdateConfiguration(config);

            // => Update the row
            customer       = (CustomerEntity)result.Result;
            customer.Email = "*****@*****.**";
            operation      = TableOperation.Replace(customer);
            result         = rtable.Execute(operation);
            Assert.IsTrue(result != null && result.HttpStatusCode == (int)HttpStatusCode.NoContent, "Update customer failed");
        }
        public void RepairTableWontRepairRowsWithHigherViewIdWhenIgnoreHigherViewIdRowsFlagIsSet()
        {
            TableOperation operation;
            TableResult    result;
            CustomerEntity customer;


            // - View has 2 replicas ?
            View view = this.configurationWrapper.GetWriteView();

            Assert.IsTrue(view.Chain.Count == 2, "expects 2 replicas only!");


            // - Remove the Head, [None]->[RW]
            RemoveHeadFromView(view.Name, 600, this.configurationService);


            // 1 - Insert entries in old viewId
            var rtable = new ReplicatedTable(this.repTable.TableName, this.configurationService);

            string firstName = "FirstName";
            string lastName  = "LastName";

            for (int i = 0; i < 10; i++)
            {
                customer = new CustomerEntity(firstName + i, lastName + i);

                operation = TableOperation.Insert(customer);
                rtable.Execute(operation);
            }


            // 2 - Increase viewId => so we can create rows with higher viewId
            //   - Update entry #5 and #8 in new viewId
            ReplicatedTableConfiguration    config;
            ReplicatedTableQuorumReadResult readStatus = this.configurationService.RetrieveConfiguration(out config);

            Assert.IsTrue(readStatus.Code == ReplicatedTableQuorumReadCode.Success);
            ReplicatedTableConfigurationStore viewConfg = config.GetView(view.Name);

            viewConfg.ViewId += 100;
            this.configurationService.UpdateConfiguration(config);

            foreach (int entryId in new int[] { 5, 8 })
            {
                operation = TableOperation.Retrieve <CustomerEntity>(firstName + entryId, lastName + entryId);
                result    = rtable.Execute(operation);

                Assert.IsTrue(result != null && result.HttpStatusCode == (int)HttpStatusCode.OK && (CustomerEntity)result.Result != null, "Retrieve customer failed");

                customer       = (CustomerEntity)result.Result;
                customer.Email = "*****@*****.**";

                operation = TableOperation.Replace(customer);
                result    = rtable.Execute(operation);

                Assert.IsTrue(result != null && result.HttpStatusCode == (int)HttpStatusCode.NoContent, "Update customer failed");
            }


            // 3 - Restore previous viewId, and,
            //   - Set 'IgnoreHigherViewIdRows' flag so we ignore rows with higher viewIds
            readStatus = this.configurationService.RetrieveConfiguration(out config);
            Assert.IsTrue(readStatus.Code == ReplicatedTableQuorumReadCode.Success);
            viewConfg         = config.GetView(view.Name);
            viewConfg.ViewId -= 100;
            config.SetIgnoreHigherViewIdRowsFlag(true);
            this.configurationService.UpdateConfiguration(config);

            try
            {
                // Check Retrieve of row #5 and #8 returns NotFound
                foreach (int entryId in new int[] { 5, 8 })
                {
                    operation = TableOperation.Retrieve <CustomerEntity>(firstName + entryId, lastName + entryId);
                    var retrievedResult = rtable.Execute(operation);

                    Assert.AreNotEqual(null, retrievedResult, "retrievedResult = null");
                    Assert.AreEqual((int)HttpStatusCode.NotFound, retrievedResult.HttpStatusCode, "retrievedResult.HttpStatusCode mismatch");
                }
            }
            catch (ReplicatedTableStaleViewException)
            {
                Assert.Fail("Retrieve() is expected to NotFound the row, but got RTableStaleViewException !");
            }


            // 4 - Now insert a Head [WO]->[RW]
            //   - Then, call RepairTable ...
            InsertHeadInView(view.Name, 600, this.configurationService);
            ReconfigurationStatus status = rtable.RepairTable(0, null);

            Assert.AreEqual(status, ReconfigurationStatus.PARTIAL_FAILURE, "rows with higher viewId should not be repaired");


            // 5 - Check rows with higher viewId still NotFound, even after repair ...
            try
            {
                // Check Retrieve of row #5 and #8 returns NotFound
                foreach (int entryId in new int[] { 5, 8 })
                {
                    operation = TableOperation.Retrieve <CustomerEntity>(firstName + entryId, lastName + entryId);
                    var retrievedResult = rtable.Execute(operation);

                    Assert.AreNotEqual(null, retrievedResult, "retrievedResult = null");
                    Assert.AreEqual((int)HttpStatusCode.NotFound, retrievedResult.HttpStatusCode, "retrievedResult.HttpStatusCode mismatch");
                }
            }
            catch (ReplicatedTableStaleViewException)
            {
                Assert.Fail("Retrieve() is expected to NotFound the row, but got RTableStaleViewException !");
            }
        }
Beispiel #16
0
        public void RowsWithHigherViewIdNotFoundWhenIgnoreHigherViewIdRowsFlagIsSet()
        {
            long higherViewId = 200;

            // Configure RTable with a higher ViewId
            this.UpdateConfiguration(replicas, 0, false, higherViewId);

            string firstName = "FirstName02";
            string lastName  = "LastName02";
            string email     = "*****@*****.**";
            string phone     = "1-800-123-0001";

            // Insert entity
            CustomerEntity newCustomer = new CustomerEntity(firstName, lastName);

            newCustomer.Email       = email;
            newCustomer.PhoneNumber = phone;

            TableOperation operation = TableOperation.Insert(newCustomer);
            TableResult    result    = this.repTable.Execute(operation);

            Assert.AreNotEqual(null, result, "result = null");
            Assert.AreEqual((int)HttpStatusCode.NoContent, result.HttpStatusCode, "result.HttpStatusCode mismatch");

            // Retrieve entity
            operation = TableOperation.Retrieve <CustomerEntity>(firstName, lastName);
            TableResult retrievedResult = this.repTable.Execute(operation);

            Assert.AreNotEqual(null, retrievedResult, "retrievedResult = null");
            Assert.AreEqual((int)HttpStatusCode.OK, retrievedResult.HttpStatusCode, "retrievedResult.HttpStatusCode mismatch");
            Assert.AreNotEqual(null, retrievedResult.Result, "retrievedResult.Result = null");
            CustomerEntity customer = (CustomerEntity)retrievedResult.Result;

            Assert.AreEqual(higherViewId, customer._rtable_ViewId, "customer._rtable_ViewId mismatch");
            Assert.AreEqual(newCustomer.PhoneNumber, customer.PhoneNumber, "customer.PhoneNumber mismatch");
            Assert.AreEqual(newCustomer.Email, customer.Email, "customer.Email mismatch");
            Console.WriteLine("Successfully retrieved the entity");

            //
            // Change RTable config to a lower viewId, and force RTable to ignore rows with higher viewId
            //
            long currentViewId = 10;

            Assert.IsTrue(currentViewId < higherViewId, "expected currentViewId < higherViewId !");

            Console.WriteLine("Changing the viewId to currentViewId {0}", currentViewId);
            ReplicatedTableConfiguration    config;
            ReplicatedTableQuorumReadResult readStatus = this.configurationService.RetrieveConfiguration(out config);

            Assert.IsTrue(readStatus.Code == ReplicatedTableQuorumReadCode.Success);
            ReplicatedTableConfigurationStore viewConfg = config.GetView(this.configurationWrapper.GetWriteView().Name);

            viewConfg.ViewId = currentViewId;
            config.SetIgnoreHigherViewIdRowsFlag(true);
            this.configurationService.UpdateConfiguration(config);


            //
            // Retrieve with lower viewId
            //
            Console.WriteLine("\nCalling Retrieve with lower ViewId...");
            operation = TableOperation.Retrieve <CustomerEntity>(firstName, lastName);
            try
            {
                retrievedResult = this.repTable.Execute(operation);

                Assert.AreNotEqual(null, retrievedResult, "retrievedResult = null");
                Assert.AreEqual((int)HttpStatusCode.NotFound, retrievedResult.HttpStatusCode, "retrievedResult.HttpStatusCode mismatch");
            }
            catch (ReplicatedTableStaleViewException)
            {
                Assert.Fail("Retrieve() is expected to NotFound the row, but got RTableStaleViewException !");
            }

            //
            // Replace with lower viewId
            //
            Console.WriteLine("\nCalling Replace with lower ViewId...");
            operation = TableOperation.Replace(customer);
            try
            {
                retrievedResult = this.repTable.Execute(operation);

                Assert.AreNotEqual(null, retrievedResult, "retrievedResult = null");
                Assert.AreEqual((int)HttpStatusCode.NotFound, retrievedResult.HttpStatusCode, "retrievedResult.HttpStatusCode mismatch");
            }
            catch (ReplicatedTableStaleViewException)
            {
                Assert.Fail("Replace() is expected to NotFound the row, but got RTableStaleViewException !");
            }

            //
            // InsertOrMerge with lower viewId
            //
            Console.WriteLine("\nCalling InsertOrMerge with lower ViewId...");
            operation = TableOperation.InsertOrMerge(customer);
            try
            {
                retrievedResult = this.repTable.Execute(operation);

                Assert.AreNotEqual(null, retrievedResult, "retrievedResult = null");
                Assert.AreEqual((int)HttpStatusCode.Conflict, retrievedResult.HttpStatusCode, "retrievedResult.HttpStatusCode mismatch");
            }
            catch (ReplicatedTableStaleViewException)
            {
                Assert.Fail("InsertOrMerge() is expected to get Conflict, but got RTableStaleViewException !");
            }

            //
            // InsertOrReplace with lower viewId
            //
            Console.WriteLine("\nCalling InsertOrReplace with lower ViewId...");
            operation = TableOperation.InsertOrReplace(customer);
            try
            {
                retrievedResult = this.repTable.Execute(operation);

                Assert.AreNotEqual(null, retrievedResult, "retrievedResult = null");
                Assert.AreEqual((int)HttpStatusCode.Conflict, retrievedResult.HttpStatusCode, "retrievedResult.HttpStatusCode mismatch");
            }
            catch (ReplicatedTableStaleViewException)
            {
                Assert.Fail("InsertOrReplace() is expected to get Conflict, but got RTableStaleViewException !");
            }

            //
            // Merge with lower viewId
            //
            Console.WriteLine("\nCalling Merge with lower ViewId...");
            operation = TableOperation.Merge(customer);
            try
            {
                retrievedResult = this.repTable.Execute(operation);

                Assert.AreNotEqual(null, retrievedResult, "retrievedResult = null");
                Assert.AreEqual((int)HttpStatusCode.NotFound, retrievedResult.HttpStatusCode, "retrievedResult.HttpStatusCode mismatch");
            }
            catch (ReplicatedTableStaleViewException)
            {
                Assert.Fail("Merge() is expected to NotFound the row, but got RTableStaleViewException !");
            }

            //
            // Delete with lower viewId
            //
            Console.WriteLine("\nCalling Delete with lower ViewId...");
            operation = TableOperation.Delete(customer);
            try
            {
                retrievedResult = this.repTable.Execute(operation);

                Assert.AreNotEqual(null, retrievedResult, "retrievedResult = null");
                Assert.AreEqual((int)HttpStatusCode.NotFound, retrievedResult.HttpStatusCode, "retrievedResult.HttpStatusCode mismatch");
            }
            catch (ReplicatedTableStaleViewException)
            {
                Assert.Fail("Delete() is expected to NotFound the row, but got RTableStaleViewException !");
            }
        }