public void TurnReplicaOff(string storageAccountName)
        {
            if (string.IsNullOrEmpty(storageAccountName))
            {
                throw new ArgumentNullException("storageAccountName");
            }

            ReplicatedTableConfiguration configuration = null;

            // - Retrieve configuration ...
            ReplicatedTableQuorumReadResult readResult = RetrieveConfiguration(out configuration);

            if (readResult.Code != ReplicatedTableQuorumReadCode.Success)
            {
                var msg = string.Format("TurnReplicaOff={0}: failed to read configuration, \n{1}", storageAccountName, readResult.ToString());

                ReplicatedTableLogger.LogError(msg);
                throw new Exception(msg);
            }

            // - Update all views ...
            configuration.TurnReplicaOff(storageAccountName);

            // - Write back configuration ...
            ReplicatedTableQuorumWriteResult writeResult = UpdateConfigurationInternal(configuration, true);

            if (writeResult.Code != ReplicatedTableQuorumWriteCode.Success)
            {
                var msg = string.Format("TurnReplicaOff={0}: failed to update configuration, \n{1}", storageAccountName, writeResult.ToString());

                ReplicatedTableLogger.LogError(msg);
                throw new Exception(msg);
            }
        }
예제 #2
0
        public static bool TryReadBlob <T>(CloudBlockBlob blob, out T configurationStore)
            where T : class
        {
            configurationStore = default(T);
            try
            {
                string content = blob.DownloadText();
                if (content == Constants.ConfigurationStoreUpdatingText)
                {
                    return(false);
                }

                string blobContent = content;
                configurationStore = JsonStore <T> .Deserialize(blobContent);

                return(true);
            }
            catch (Exception e)
            {
                ReplicatedTableLogger.LogError("Error reading blob: {0}. Exception: {1}",
                                               blob.Uri,
                                               e.Message);
            }

            return(false);
        }
예제 #3
0
파일: View.cs 프로젝트: srinathsetty/rtable
        public static View InitFromConfigVer2(string name, ReplicatedTableConfigurationStore configurationStore, Action <ReplicaInfo> SetConnectionString)
        {
            View view = new View(name);

            if (configurationStore != null)
            {
                view.ViewId = configurationStore.ViewId;

                foreach (ReplicaInfo replica in configurationStore.GetCurrentReplicaChain())
                {
                    SetConnectionString(replica);

                    CloudTableClient tableClient = ReplicatedTableConfigurationManager.GetTableClientForReplica(replica);
                    if (tableClient == null)
                    {
                        // All replicas MUST exist or View is not relevant
                        view.Chain.Clear();

                        ReplicatedTableLogger.LogError("ViewName={0} could not load replica ({1})", name, replica);
                        break;
                    }

                    view.Chain.Add(new Tuple <ReplicaInfo, CloudTableClient>(replica, tableClient));
                }

                // Infered: first readable replica
                view.ReadHeadIndex = view.Chain.FindIndex(tuple => tuple.Item1.IsReadable());
            }

            return(view);
        }
예제 #4
0
        private void Initialize()
        {
            if ((this.blobLocations.Count % 2) == 0)
            {
                throw new ArgumentException("Number of blob locations must be odd");
            }

            foreach (var blobLocation in blobLocations)
            {
                string accountConnectionString = String.Format(Constants.ShortConnectioStringTemplate,
                                                               ((this.useHttps == true) ? "https" : "http"),
                                                               blobLocation.StorageAccountName,
                                                               blobLocation.StorageAccountKey);

                try
                {
                    CloudBlockBlob blob = CloudBlobHelpers.GetBlockBlob(accountConnectionString, blobLocation.BlobPath);
                    this.blobs.Add(blobLocation.StorageAccountName + ';' + blobLocation.BlobPath, blob);
                }
                catch (Exception e)
                {
                    ReplicatedTableLogger.LogError("Failed to init blob Acc={0}, Blob={1}. Exception: {2}",
                                                   blobLocation.StorageAccountName,
                                                   blobLocation.BlobPath,
                                                   e.Message);
                }
            }

            int quorumSize = (this.blobLocations.Count / 2) + 1;

            if (this.blobs.Count < quorumSize)
            {
                throw new Exception(string.Format("Retrieved blobs count ({0}) is less than quorum !", this.blobs.Count));
            }
        }
예제 #5
0
        private ReplicatedTableQuorumWriteResult UpdateConfigurationInternal(ReplicatedTableConfiguration configuration, bool useConditionalUpdate)
        {
            SanitizeConfiguration(configuration);

            // - Upload configuration ...
            Func <ReplicatedTableConfiguration, ReplicatedTableConfiguration, bool> comparer = (a, b) => a.Id == b.Id;

            if (!useConditionalUpdate)
            {
                comparer = (a, b) => true;
            }

            ReplicatedTableQuorumWriteResult
                result = CloudBlobHelpers.TryWriteBlobQuorum(
                this.configManager.GetBlobs(),
                configuration,
                ReplicatedTableConfiguration.FromJson,
                comparer,
                ReplicatedTableConfiguration.GenerateNewConfigId);

            if (result.Code == ReplicatedTableQuorumWriteCode.Success)
            {
                this.configManager.Invalidate();
            }
            else
            {
                ReplicatedTableLogger.LogError("Failed to update configuration, \n{0}", result.ToString());
            }

            return(result);
        }
        public void UpdateConfiguration(List <ReplicaInfo> replicaChain, int readViewHeadIndex, bool convertXStoreTableMode = false)
        {
            Parallel.ForEach(this.blobs, blob =>
            {
                ReplicatedTableConfigurationStore configurationStore = null;
                long newViewId = 0;
                if (!CloudBlobHelpers.TryReadBlob <ReplicatedTableConfigurationStore>(blob.Value, out configurationStore))
                {
                    //This is the first time we are uploading the config
                    configurationStore = new ReplicatedTableConfigurationStore();
                }

                newViewId = configurationStore.ViewId + 1;

                configurationStore.LeaseDuration          = Constants.LeaseDurationInSec;
                configurationStore.Timestamp              = DateTime.UtcNow;
                configurationStore.ReplicaChain           = replicaChain;
                configurationStore.ReadViewHeadIndex      = readViewHeadIndex;
                configurationStore.ConvertXStoreTableMode = convertXStoreTableMode;

                configurationStore.ViewId = newViewId;

                //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 (readViewHeadIndex != 0)
                {
                    for (int i = 0; i < readViewHeadIndex; i++)
                    {
                        replicaChain[i].ViewInWhichAddedToChain = newViewId;
                    }
                }

                try
                {
                    //Step 1: Delete the current configuration
                    blob.Value.UploadText(Constants.ConfigurationStoreUpdatingText);

                    //Step 2: Wait for L + CF to make sure no pending transaction working on old views
                    // Chunzhi: removed this, original code hangs here
                    // Matt: restore this: it's essential for consistency.
                    Thread.Sleep(TimeSpan.FromSeconds(Constants.LeaseDurationInSec +
                                                      Constants.ClockFactorInSec));

                    //Step 3: Update new config
                    blob.Value.UploadText(JsonStore <ReplicatedTableConfigurationStore> .Serialize(configurationStore));
                }
                catch (StorageException e)
                {
                    ReplicatedTableLogger.LogError("Updating the blob: {0} failed. Exception: {1}", blob.Value, e.Message);
                }
            });

            //Invalidate the lastViewRefreshTime so that updated views get returned
            this.lastViewRefreshTime = DateTime.MinValue;
        }
예제 #7
0
        public static async Task <ReplicatedTableReadBlobResult> TryReadBlobAsync <T>(CloudBlockBlob blob, Action <T, string> callback, Func <string, T> ParseBlobFunc, CancellationToken ct)
            where T : class
        {
            try
            {
                BlobRequestOptions options = new BlobRequestOptions()
                {
                    ServerTimeout        = TimeSpan.FromSeconds(5),
                    MaximumExecutionTime = TimeSpan.FromSeconds(30)
                };
                string content = await blob.DownloadTextAsync(null, null, options, null, ct);

                if (content == Constants.ConfigurationStoreUpdatingText)
                {
                    return(new ReplicatedTableReadBlobResult(ReadBlobCode.UpdateInProgress, "Blob update in progress ..."));
                }

                // ParseBlobFunc != null
                T      configuration = ParseBlobFunc(content);
                string eTag          = blob.Properties.ETag;

                // callback != null
                callback(configuration, eTag);

                return(new ReplicatedTableReadBlobResult(ReadBlobCode.Success, ""));
            }
            catch (StorageException e)
            {
                var msg = string.Format("Error reading blob: {0}. StorageException: {1}", blob.Uri, e.Message);
                ReplicatedTableLogger.LogError(msg);

                if (e.RequestInformation != null &&
                    e.RequestInformation.HttpStatusCode == (int)HttpStatusCode.NotFound)
                {
                    return(new ReplicatedTableReadBlobResult(ReadBlobCode.NotFound, msg));
                }

                return(new ReplicatedTableReadBlobResult(ReadBlobCode.StorageException, msg));
            }
            catch (OperationCanceledException)
            {
                var msg = string.Format("TryReadBlobAsync cancelled ({0})", blob.Uri);
                ReplicatedTableLogger.LogInformational(msg);

                return(new ReplicatedTableReadBlobResult(ReadBlobCode.Exception, msg));
            }
            catch (Exception e)
            {
                var msg = string.Format("Error reading blob: {0}. Exception: {1}", blob.Uri, e.Message);
                ReplicatedTableLogger.LogError(msg);

                return(new ReplicatedTableReadBlobResult(ReadBlobCode.Exception, msg));
            }
        }
예제 #8
0
        /*
         * Class functions:
         */
        static internal protected CloudTableClient GetTableClientForReplica(ReplicaInfo replica)
        {
            CloudTableClient tableClient = null;

            if (!CloudBlobHelpers.TryCreateCloudTableClient(replica.ConnectionString, out tableClient))
            {
                ReplicatedTableLogger.LogError("No table client created for replica info: {0}", replica);
            }

            return(tableClient);
        }
예제 #9
0
파일: View.cs 프로젝트: isabella232/rtable
        public static View InitFromConfigVer1(string name, ReplicatedTableConfigurationStore configurationStore, Action <ReplicaInfo> SetConnectionString)
        {
            View view = new View(name);

            if (configurationStore != null)
            {
                view.ViewId        = configurationStore.ViewId;
                view.ReadHeadIndex = configurationStore.ReadViewHeadIndex;
                view.RefreshTime   = DateTime.UtcNow;

                foreach (ReplicaInfo replica in configurationStore.ReplicaChain)
                {
                    if (replica == null)
                    {
                        continue;
                    }

                    SetConnectionString(replica);

                    CloudTableClient tableClient = ReplicatedTableConfigurationManager.GetTableClientForReplica(replica);
                    if (tableClient == null)
                    {
                        // All replicas MUST exist or View is not relevant
                        view.Chain.Clear();

                        ReplicatedTableLogger.LogError("ViewName={0} could not load replica ({1})", name, replica);
                        break;
                    }

                    view.Chain.Add(new Tuple <ReplicaInfo, CloudTableClient>(replica, tableClient));
                }

                // If not configured use Tail. Chain must be defined at this point, so don't move this code up!
                view.ReadTailIndex = configurationStore.ReadViewTailIndex;
                if (view.ReadTailIndex < 0)
                {
                    view.ReadTailIndex = view.TailIndex;
                }

                if (!view.IsEmpty)
                {
                    ReplicaInfo head = view.GetReplicaInfo(0);
                    head.Status = ReplicaStatus.WriteOnly;

                    if (view.IsStable)
                    {
                        head.Status = ReplicaStatus.ReadWrite;
                    }
                }
            }

            return(view);
        }
예제 #10
0
        public void TurnReplicaOff(string storageAccountName)
        {
            if (string.IsNullOrEmpty(storageAccountName))
            {
                throw new ArgumentNullException("storageAccountName");
            }

            ReplicatedTableConfiguration configuration = null;

            // - Retrieve configuration ...
            ReplicatedTableQuorumReadResult readResult = RetrieveConfiguration(out configuration);

            if (readResult.Code != ReplicatedTableQuorumReadCode.Success)
            {
                var msg = string.Format("TurnReplicaOff={0}: failed to read configuration, \n{1}", storageAccountName, readResult.ToString());

                ReplicatedTableLogger.LogError(msg);
                throw new Exception(msg);
            }

            // - Parse/Update all views ...
            foreach (var viewConf in configuration.viewMap.Values)
            {
                var foundReplicas = viewConf.GetCurrentReplicaChain()
                                    .FindAll(r => r.StorageAccountName == storageAccountName);

                if (!foundReplicas.Any())
                {
                    continue;
                }

                foreach (var replica in foundReplicas)
                {
                    replica.Status            = ReplicaStatus.None;
                    replica.ViewWhenTurnedOff = viewConf.ViewId;
                }

                // Update view id
                viewConf.ViewId++;
            }

            // - Write back configuration ...
            ReplicatedTableQuorumWriteResult writeResult = UpdateConfigurationInternal(configuration, true);

            if (writeResult.Code != ReplicatedTableQuorumWriteCode.Success)
            {
                var msg = string.Format("TurnReplicaOff={0}: failed to update configuration, \n{1}", storageAccountName, writeResult.ToString());

                ReplicatedTableLogger.LogError(msg);
                throw new Exception(msg);
            }
        }
예제 #11
0
        internal protected void MoveReplicaToHeadAndSetViewToReadOnly(string viewName, string storageAccountName)
        {
            // Assert (storageAccountName != null)

            int matchIndex = ReplicaChain.FindIndex(r => r.StorageAccountName == storageAccountName);

            if (matchIndex == -1)
            {
                return;
            }

            // - Ensure its status is *None*
            ReplicaInfo candidateReplica = ReplicaChain[matchIndex];

            var oldStatus = candidateReplica.Status;

            candidateReplica.Status = ReplicaStatus.None;

            // First check it will be possible to modify the sequence
            foreach (ReplicaInfo replica in GetCurrentReplicaChain())
            {
                // Change is not possible
                if (replica.Status == ReplicaStatus.WriteOnly)
                {
                    // Restore previous status
                    candidateReplica.Status = oldStatus;

                    var msg = string.Format("View:\'{0}\' : can't set a WriteOnly replica to ReadOnly !!!", viewName);

                    ReplicatedTableLogger.LogError(msg);
                    throw new Exception(msg);
                }
            }

            // Do the change ...

            // - Move it to the front of the chain
            ReplicaChain.RemoveAt(matchIndex);
            ReplicaChain.Insert(0, candidateReplica);

            // Set all active replicas to *ReadOnly*
            foreach (ReplicaInfo replica in GetCurrentReplicaChain())
            {
                replica.Status = ReplicaStatus.ReadOnly;
            }

            // Update view id
            ViewId++;

            // Reset 'ReadViewTailIndex' => user has to set it again
            ResetReadViewTailIndex();
        }
예제 #12
0
        public View GetTableView(string tableName)
        {
            ReplicatedTableConfiguredTable config;

            if (IsConfiguredTable(tableName, out config))
            {
                return(GetView(config.ViewName));
            }

            var msg = string.Format("Table={0}: is not configured!", tableName);

            ReplicatedTableLogger.LogError(msg);
            throw new Exception(msg);
        }
예제 #13
0
        public bool ConvertToRTable(string tableName)
        {
            ReplicatedTableConfiguredTable config;

            if (IsConfiguredTable(tableName, out config))
            {
                return(config.ConvertToRTable);
            }

            var msg = string.Format("Table={0}: is not configured!", tableName);

            ReplicatedTableLogger.LogError(msg);
            throw new Exception(msg);
        }
        private CloudTableClient GetTableClientForReplica(ReplicaInfo replica)
        {
            string connectionString = String.Format(cloudStorageAccountTemplate,
                                                    this.useHttps ? "https" : "http",
                                                    replica.StorageAccountName,
                                                    replica.StorageAccountKey);

            CloudTableClient tableClient = null;

            if (!CloudBlobHelpers.TryCreateCloudTableClient(connectionString, out tableClient))
            {
                ReplicatedTableLogger.LogError("No table client created for replica info: {0}", replica);
            }

            return(tableClient);
        }
예제 #15
0
        public static ReplicatedTableReadBlobResult TryReadBlob <T>(CloudBlockBlob blob, out T configuration, out string eTag, Func <string, T> ParseBlobFunc)
            where T : class
        {
            configuration = default(T);
            eTag          = null;

            try
            {
                BlobRequestOptions options = new BlobRequestOptions()
                {
                    ServerTimeout        = TimeSpan.FromSeconds(5),
                    MaximumExecutionTime = TimeSpan.FromSeconds(30)
                };
                string content = blob.DownloadText(null, null, options, null);
                if (content == Constants.ConfigurationStoreUpdatingText)
                {
                    return(new ReplicatedTableReadBlobResult(ReadBlobCode.UpdateInProgress, "Blob update in progress ..."));
                }

                configuration = ParseBlobFunc(content);
                eTag          = blob.Properties.ETag;

                return(new ReplicatedTableReadBlobResult(ReadBlobCode.Success, ""));
            }
            catch (StorageException e)
            {
                var msg = string.Format("Error reading blob: {0}. StorageException: {1}", blob.Uri, e.Message);
                ReplicatedTableLogger.LogError(msg);

                if (e.RequestInformation != null &&
                    e.RequestInformation.HttpStatusCode == (int)HttpStatusCode.NotFound)
                {
                    return(new ReplicatedTableReadBlobResult(ReadBlobCode.NotFound, msg));
                }

                return(new ReplicatedTableReadBlobResult(ReadBlobCode.StorageException, msg));
            }
            catch (Exception e)
            {
                var msg = string.Format("Error reading blob: {0}. Exception: {1}", blob.Uri, e.Message);
                ReplicatedTableLogger.LogError(msg);

                return(new ReplicatedTableReadBlobResult(ReadBlobCode.Exception, msg));
            }
        }
예제 #16
0
        public static void TryWriteBlob(CloudBlockBlob blob, string content)
        {
            try
            {
                //Step 1: Delete the current configuration
                blob.UploadText(Constants.ConfigurationStoreUpdatingText);

                //Step 2: Wait for L + CF to make sure no pending transaction working on old views
                Thread.Sleep(TimeSpan.FromSeconds(Constants.LeaseDurationInSec + Constants.ClockFactorInSec));

                //Step 3: Update new config
                blob.UploadText(content);
            }
            catch (StorageException e)
            {
                ReplicatedTableLogger.LogError("Updating the blob: {0} failed. Exception: {1}", blob, e.Message);
            }
        }
예제 #17
0
        /*
         * Configuration management APIs
         */
        public ReplicatedTableQuorumReadResult RetrieveConfiguration(out ReplicatedTableConfiguration configuration)
        {
            List <string> eTags;

            ReplicatedTableQuorumReadResult
                result = CloudBlobHelpers.TryReadBlobQuorum(
                this.configManager.GetBlobs(),
                out configuration,
                out eTags,
                ReplicatedTableConfiguration.FromJson);

            if (result.Code != ReplicatedTableQuorumReadCode.Success)
            {
                ReplicatedTableLogger.LogError("Failed to read configuration, \n{0}", result.ToString());
            }

            return(result);
        }
예제 #18
0
        public static bool TryCreateCloudTableClient(string storageAccountConnectionString,
                                                     out CloudTableClient cloudTableClient)
        {
            cloudTableClient = null;

            try
            {
                cloudTableClient = CloudStorageAccount.Parse(storageAccountConnectionString).CreateCloudTableClient();
                return(true);
            }
            catch (Exception e)
            {
                ReplicatedTableLogger.LogError("Error creating cloud table client: Connection string {0}. Exception: {1}",
                                               storageAccountConnectionString,
                                               e.Message);
            }

            return(false);
        }
예제 #19
0
        public ReplicatedTableQuorumWriteResult UploadConfigurationToBlobs(List <int> blobIndexes, ReplicatedTableConfiguration configuration)
        {
            if (blobIndexes == null || !blobIndexes.Any())
            {
                throw new ArgumentNullException("blobIndexes");
            }

            if (configuration == null)
            {
                throw new ArgumentNullException("configuration");
            }

            List <CloudBlockBlob> blobs = new List <CloudBlockBlob>();

            foreach (var blobIndex in blobIndexes)
            {
                if (blobIndex < this.configManager.GetBlobs().Count)
                {
                    blobs.Add(this.configManager.GetBlobs()[blobIndex]);
                    continue;
                }

                var msg = string.Format("blobIndex={0} >= BlobCount={1}", blobIndex, this.configManager.GetBlobs().Count);

                ReplicatedTableLogger.LogError(msg);
                throw new Exception(msg);
            }

            SanitizeConfiguration(configuration);

            // - Upload to blobs ...
            ReplicatedTableQuorumWriteResult result = CloudBlobHelpers.TryUploadBlobs(blobs, configuration);

            this.configManager.Invalidate();

            if (result.Code != ReplicatedTableQuorumWriteCode.Success)
            {
                ReplicatedTableLogger.LogError("Failed to upload configuration to blobs, \n{0}", result.ToString());
            }

            return(result);
        }
예제 #20
0
        /// <summary>
        /// Convert SecureString to String
        /// </summary>
        /// <param name="secureText"></param>
        /// <returns></returns>
        public static string ToString(SecureString secureText)
        {
            IntPtr unmanagedPtr = IntPtr.Zero;

            try
            {
                unmanagedPtr = Marshal.SecureStringToGlobalAllocUnicode(secureText);
                return(Marshal.PtrToStringUni(unmanagedPtr));
            }
            catch (Exception ex)
            {
                ReplicatedTableLogger.LogError("Exception converting from SecureString : {0}", ex);
            }
            finally
            {
                Marshal.ZeroFreeGlobalAllocUnicode(unmanagedPtr);
            }

            return(null);
        }
예제 #21
0
        public static ReplicatedTableWriteBlobResult TryWriteBlob(CloudBlockBlob blob, string content, string eTag)
        {
            try
            {
                AccessCondition condition = string.IsNullOrEmpty(eTag)
                                                ? AccessCondition.GenerateEmptyCondition()
                                                : AccessCondition.GenerateIfMatchCondition(eTag);

                blob.UploadText(content, accessCondition: condition);

                return(new ReplicatedTableWriteBlobResult(true, ""));
            }
            catch (StorageException e)
            {
                var msg = string.Format("Updating the blob: {0} failed. Exception: {1}", blob, e.Message);

                ReplicatedTableLogger.LogError(msg);
                return(new ReplicatedTableWriteBlobResult(false, msg));
            }
        }
예제 #22
0
        public static bool TryCreateCloudTableClient(SecureString connectionString, out CloudTableClient cloudTableClient)
        {
            cloudTableClient = null;

            try
            {
                string decryptConnectionString = SecureStringHelper.ToString(connectionString);
                cloudTableClient = CloudStorageAccount.Parse(decryptConnectionString).CreateCloudTableClient();

                return(true);
            }
            catch (Exception e)
            {
                ReplicatedTableLogger.LogError(
                    "Error creating cloud table client: Connection string {0}. Exception: {1}",
                    "********",
                    e.Message);
            }

            return(false);
        }
예제 #23
0
파일: View.cs 프로젝트: isabella232/rtable
        public static View InitFromConfigVer2(string name, ReplicatedTableConfigurationStore configurationStore, Action <ReplicaInfo> SetConnectionString)
        {
            View view = new View(name);

            if (configurationStore != null)
            {
                view.ViewId      = configurationStore.ViewId;
                view.RefreshTime = DateTime.UtcNow;

                foreach (ReplicaInfo replica in configurationStore.GetCurrentReplicaChain())
                {
                    SetConnectionString(replica);

                    CloudTableClient tableClient = ReplicatedTableConfigurationManager.GetTableClientForReplica(replica);
                    if (tableClient == null)
                    {
                        // All replicas MUST exist or View is not relevant
                        view.Chain.Clear();

                        ReplicatedTableLogger.LogError("ViewName={0} could not load replica ({1})", name, replica);
                        break;
                    }

                    view.Chain.Add(new Tuple <ReplicaInfo, CloudTableClient>(replica, tableClient));
                }

                // Infered: first readable replica
                view.ReadHeadIndex = view.Chain.FindIndex(tuple => tuple.Item1.IsReadable());

                // If not configured use Tail. Chain must be defined at this point, so don't move this code up!
                view.ReadTailIndex = configurationStore.ReadViewTailIndex;
                if (view.ReadTailIndex < 0)
                {
                    view.ReadTailIndex = view.TailIndex;
                }
            }

            return(view);
        }
        public bool IsTableViewStable(string tableName, string viewToUse = null)
        {
            ReplicatedTableConfiguredTable config;

            if (IsConfiguredTable(tableName, out config))
            {
                // Use table default view
                if (string.IsNullOrEmpty(viewToUse))
                {
                    viewToUse = config.ViewName;
                }

                if (config.IsViewReferenced(viewToUse))
                {
                    return(IsViewStable(viewToUse));
                }
            }

            var msg = string.Format("Table={0}: is not configured or ViewToUse={1} is not referenced!", tableName, viewToUse);

            ReplicatedTableLogger.LogError(msg);
            throw new Exception(msg);
        }
        internal protected void MoveReplicaToHeadAndSetViewToReadOnly(string viewName, string storageAccountName)
        {
            // Assert (storageAccountName != null)

            int matchIndex = ReplicaChain.FindIndex(r => r.StorageAccountName == storageAccountName);

            if (matchIndex == -1)
            {
                return;
            }

            // - Ensure its status is *None*
            ReplicaInfo candidateReplica = ReplicaChain[matchIndex];

            candidateReplica.Status = ReplicaStatus.None;

            // - Move it to the front of the chain
            ReplicaChain.RemoveAt(matchIndex);
            ReplicaChain.Insert(0, candidateReplica);

            // Set all active replicas to *ReadOnly*
            foreach (ReplicaInfo replica in GetCurrentReplicaChain())
            {
                if (replica.Status == ReplicaStatus.WriteOnly)
                {
                    var msg = string.Format("View:\'{0}\' : can't set a WriteOnly replica to ReadOnly !!!", viewName);

                    ReplicatedTableLogger.LogError(msg);
                    throw new Exception(msg);
                }

                replica.Status = ReplicaStatus.ReadOnly;
            }

            // Update view id
            ViewId++;
        }
예제 #26
0
        private void SaveConfigAndRefreshItsIdAndValidateIsLoaded(ReplicatedTableConfiguration configuration, string iteration, bool validateConfigIsLoaded = true)
        {
            string msg = "";

            ReplicatedTableQuorumWriteResult writeResult = UpdateConfigurationInternal(configuration, true);

            if (writeResult.Code != ReplicatedTableQuorumWriteCode.Success)
            {
                msg = string.Format("{0} : Failed to update configuration, \n{1}", iteration, writeResult.ToString());

                ReplicatedTableLogger.LogError(msg);
                throw new Exception(msg);
            }

            // Update config with new Id
            configuration.Id = new Guid(writeResult.Message);

            // do we need to validate if the config is loaded by the config manager ?
            if (!validateConfigIsLoaded)
            {
                return;
            }

            // - Confirm the new config is the current loaded into the RTable config manager
            if (configuration.Id == this.configManager.GetCurrentRunningConfigId())
            {
                return;
            }

            msg = string.Format("{0} : ConfigId({1}) != currently running configurationId({2})",
                                iteration,
                                configuration.Id,
                                this.configManager.GetCurrentRunningConfigId());

            ReplicatedTableLogger.LogError(msg);
            throw new Exception(msg);
        }
예제 #27
0
        public void TurnReplicaOn(string storageAccountName, List <string> tablesToRepair, out List <ReplicatedTableRepairResult> failures)
        {
            if (string.IsNullOrEmpty(storageAccountName))
            {
                throw new ArgumentNullException("storageAccountName");
            }

            if (tablesToRepair == null)
            {
                throw new ArgumentNullException("tablesToRepair");
            }

            ReplicatedTableConfiguration configuration = null;

            failures = new List <ReplicatedTableRepairResult>();

            // - Retrieve configuration ...
            ReplicatedTableQuorumReadResult readResult = RetrieveConfiguration(out configuration);

            if (readResult.Code != ReplicatedTableQuorumReadCode.Success)
            {
                var msg = string.Format("TurnReplicaOn={0}: failed to read configuration, \n{1}", storageAccountName, readResult.ToString());

                ReplicatedTableLogger.LogError(msg);
                throw new Exception(msg);
            }


            /* - Phase 1:
             *      Move the *replica* to the front and set it to None.
             *      Make the view ReadOnly.
             **/
            #region Phase 1

            configuration.MoveReplicaToHeadAndSetViewToReadOnly(storageAccountName);

            // - Write back configuration, refresh its Id with the new one,
            //   but don't validate it is loaded bcz if all views of the config are empty, the config won't be refreshed by RefreshReadAndWriteViewsFromBlobs() thread!
            SaveConfigAndRefreshItsIdAndValidateIsLoaded(configuration, "Phase 1", false);

            #endregion

            /**
             * Chain is such: [None] -> [RO] -> ... -> [RO]
             *            or: [None] -> [None] -> ... -> [None]
             **/


            // - Wait for L + CF to make sure no pending transaction working on old views
            Thread.Sleep(TimeSpan.FromSeconds(Constants.LeaseDurationInSec + Constants.ClockFactorInSec));


            /* - Phase 2:
             *      Set the *replica* (head) to WriteOnly and other active replicas to ReadWrite.
             *   Or, in case of one replic chain
             *      Set only the *replica* (head) to ReadWrite.
             **/
            #region Phase 2

            configuration.EnableWriteOnReplicas(storageAccountName);

            // - Write back configuration, refresh its Id with the new one,
            //   and then validate it is loaded now (it has to be working since next Phase is "Repair")
            SaveConfigAndRefreshItsIdAndValidateIsLoaded(configuration, "Phase 2");

            #endregion

            /**
             * Chain is such: [W] -> [RW] -> ... -> [RW]
             *            or: [RW] -> [None] -> ... -> [None]
             **/


            // To be safe:
            // - Wait for L + CF to make sure no pending transaction working on old views
            Thread.Sleep(TimeSpan.FromSeconds(Constants.LeaseDurationInSec + Constants.ClockFactorInSec));


            /* - Phase 3:
             *      Repair all tables
             **/
            #region Phase 3

            foreach (var tableName in tablesToRepair)
            {
                ReplicatedTableRepairResult result = RepairTable(tableName, storageAccountName, configuration);
                if (result.Code != ReplicatedTableRepairCode.Error)
                {
                    ReplicatedTableLogger.LogInformational(result.ToString());
                    continue;
                }

                ReplicatedTableLogger.LogError(result.ToString());

                // List of tables (and corresponding views) failed to repair!
                failures.Add(result);
            }

            #endregion


            /* - Phase 4:
             *      Set the *replica* (head) to ReadWrite.
             **/
            #region Phase 4

            configuration.EnableReadWriteOnReplicas(storageAccountName, failures.Select(r => r.ViewName).ToList());

            // - Write back configuration, refresh its Id with the new one,
            //   and then validate it is loaded now (i.e. it is a working config)
            SaveConfigAndRefreshItsIdAndValidateIsLoaded(configuration, "Phase 4");

            #endregion

            /**
             * Chain is such: [RW] -> [RW] -> ... -> [RW] if all configured table repaired
             *            or:  [W] -> [RW] -> ... -> [RW] if at least one configured table failed repair !
             **/
        }
예제 #28
0
        /// <summary>
        /// Parses the RTable configuration blobs.
        /// Returns the list of views, the list of configured tables and the lease duration.
        /// If null is returned, then the value of tableConfigList/leaseDuration are not relevant.
        /// </summary>
        /// <param name="blobs"></param>
        /// <param name="useHttps"></param>
        /// <param name="tableConfigList"></param>
        /// <param name="leaseDuration"></param>
        /// <returns></returns>
        public List <View> ParseBlob(
            List <CloudBlockBlob> blobs,
            Action <ReplicaInfo> SetConnectionString,
            out List <ReplicatedTableConfiguredTable> tableConfigList,
            out int leaseDuration,
            out Guid configId)
        {
            tableConfigList = null;
            leaseDuration   = 0;
            configId        = Guid.Empty;

            ReplicatedTableConfigurationStore configurationStore;
            List <string> eTags;

            ReplicatedTableQuorumReadResult result = CloudBlobHelpers.TryReadBlobQuorum(
                blobs,
                out configurationStore,
                out eTags,
                JsonStore <ReplicatedTableConfigurationStore> .Deserialize);

            if (result.Code != ReplicatedTableQuorumReadCode.Success)
            {
                ReplicatedTableLogger.LogError("Unable to refresh view, \n{0}", result.ToString());
                return(null);
            }


            /**
             * View:
             */
            var view = View.InitFromConfigVer1(DefaultViewName, configurationStore, SetConnectionString);

            view.RefreshTime = DateTime.UtcNow;

            if (view.ViewId <= 0)
            {
                ReplicatedTableLogger.LogError("ViewId={0} is invalid. Must be >= 1.", view.ViewId);
                return(null);
            }

            if (view.IsEmpty)
            {
                ReplicatedTableLogger.LogError("ViewName={0} is empty, skipping ...", view.Name);
                return(null);
            }


            /**
             * Tables:
             */
            tableConfigList = new List <ReplicatedTableConfiguredTable>
            {
                new ReplicatedTableConfiguredTable
                {
                    TableName       = AllTables,
                    ViewName        = DefaultViewName,
                    ConvertToRTable = configurationStore.ConvertXStoreTableMode,
                }
            };


            // - lease duration
            leaseDuration = configurationStore.LeaseDuration;

            return(new List <View> {
                view
            });
        }
        /// <summary>
        /// Parses the RTable configuration blobs.
        /// Returns the list of views, the list of configured tables and the lease duration.
        /// If null is returned, then the value of tableConfigList/leaseDuration are not relevant.
        /// </summary>
        /// <param name="blobs"></param>
        /// <param name="useHttps"></param>
        /// <param name="tableConfigList"></param>
        /// <param name="leaseDuration"></param>
        /// <returns></returns>
        public List <View> ParseBlob(
            List <CloudBlockBlob> blobs,
            Action <ReplicaInfo> SetConnectionString,
            out List <ReplicatedTableConfiguredTable> tableConfigList,
            out int leaseDuration,
            out Guid configId)
        {
            tableConfigList = null;
            leaseDuration   = 0;
            configId        = Guid.Empty;

            ReplicatedTableConfiguration configuration;
            List <string> eTags;

            ReplicatedTableQuorumReadResult result = CloudBlobHelpers.TryReadBlobQuorum(
                blobs,
                out configuration,
                out eTags,
                ReplicatedTableConfiguration.FromJson);

            if (result.Code != ReplicatedTableQuorumReadCode.Success)
            {
                ReplicatedTableLogger.LogError("Unable to refresh views, \n{0}", result.ToString());
                return(null);
            }


            /**
             * Views:
             */
            var viewList = new List <View>();

            foreach (var entry in configuration.viewMap)
            {
                ReplicatedTableConfigurationStore configurationStore = entry.Value;

                var view = View.InitFromConfigVer2(entry.Key, configurationStore, SetConnectionString);
                view.RefreshTime = DateTime.UtcNow;

                if (view.ViewId <= 0)
                {
                    ReplicatedTableLogger.LogError("ViewId={0} of  ViewName={1} is invalid. Must be >= 1.", view.ViewId, view.Name);
                    continue;
                }

                if (view.IsEmpty)
                {
                    ReplicatedTableLogger.LogError("ViewName={0} is empty, skipping ...", view.Name);
                    continue;
                }

                // - ERROR!
                if (view.ReadHeadIndex > view.TailIndex)
                {
                    ReplicatedTableLogger.LogError("ReadHeadIndex={0} of  ViewName={1} is out of range. Must be <= {2}", view.ReadHeadIndex, view.Name, view.TailIndex);
                    continue;
                }

                viewList.Add(view);
            }

            if (!viewList.Any())
            {
                ReplicatedTableLogger.LogError("Config has no active Views !");
                return(null);
            }


            /**
             * Tables:
             */
            tableConfigList = configuration.tableList.ToList();


            // - lease duration
            leaseDuration = configuration.LeaseDuration;

            // - ConfigId
            configId = configuration.GetConfigId();

            return(viewList);
        }