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); }
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); } }
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); }
public static List <ReplicatedTableReadBlobResult> TryReadAllBlobs <T>(List <CloudBlockBlob> blobs, out List <T> values, out List <string> eTags, Func <string, T> ParseBlobFunc) where T : class { int numberOfBlobs = blobs.Count; T[] valuesArray = new T[numberOfBlobs]; string[] eTagsArray = new string[numberOfBlobs]; ReplicatedTableReadBlobResult[] resultArray = new ReplicatedTableReadBlobResult[numberOfBlobs]; // read from all the blobs in parallel Parallel.For(0, numberOfBlobs, index => { DateTime startTime = DateTime.UtcNow; T currentValue; string currentETag; resultArray[index] = TryReadBlob(blobs[index], out currentValue, out currentETag, ParseBlobFunc); valuesArray[index] = currentValue; eTagsArray[index] = currentETag; ReplicatedTableLogger.LogInformational("TryReadBlob #{0} took {1}", index, DateTime.UtcNow - startTime); }); values = valuesArray.ToList(); eTags = eTagsArray.ToList(); return(resultArray.ToList()); }
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)); } }
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; }
/* * 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); }
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)); } }
public StopWatchInternal(string tableName, string context, IReplicatedTableConfigurationWrapper replicatedTableConfigurationWrapper) { this._tableName = tableName; this._context = context; if (replicatedTableConfigurationWrapper.IsIntrumentationEnabled()) { ReplicatedTableLogger.LogVerbose("[Instrumentation] {0}:{1} started", _tableName, _context); _stopWatch = Stopwatch.StartNew(); } }
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); }
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(); }
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); } }
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); }
private bool DoesViewNeedRefresh() { lock (this) { if ((DateTime.UtcNow - this.lastViewRefreshTime) > TimeSpan.FromSeconds(Constants.LeaseRenewalIntervalInSec)) { ReplicatedTableLogger.LogInformational("Need to renew lease on the view/refresh the view"); return(true); } return(false); } }
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); }
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)); } }
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); } }
/* * 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); }
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); }
private void Dispose(bool disposing) { if (_disposed) { return; } if (disposing) { if (_stopWatch != null) { _stopWatch.Stop(); ReplicatedTableLogger.LogVerbose("[Instrumentation] {0}:{1} took {2} ms", _tableName, _context, _stopWatch.ElapsedMilliseconds); } } _disposed = true; }
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); }
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)); } }
/// <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); }
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); }
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++; }
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); }