/// <summary> /// Connection string provided by user /// </summary> /// <param name="replica"></param> private void NewStrategyToSetConnectionString(ReplicaInfo replica) { if (this.connectionStringMap.ContainsKey(replica.StorageAccountName)) { replica.ConnectionString = this.connectionStringMap[replica.StorageAccountName]; } else { replica.ConnectionString = null; } }
/* * 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 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 AddReplicaTest() { Assert.IsTrue(this.repTable.Exists(), "RTable does not exist"); View v = this.configurationWrapper.GetWriteView(); int index = v.Chain.Count - 1; string accountName = v.GetReplicaInfo(index).StorageAccountName; List<ReplicaInfo> replicas = new List<ReplicaInfo>(); for (int i = 0; i <= index; i++) { replicas.Add(v.Chain[i].Item1); } //Just add the last replica again at the head to simulate a new replica addition ReplicaInfo newReplica = new ReplicaInfo() { StorageAccountName = accountName, }; //Add the new replica at the head replicas.Insert(0, newReplica); int readViewHeadIndex = 1; this.UpdateConfiguration(replicas, readViewHeadIndex); // validate all state Assert.IsFalse(this.configurationWrapper.IsViewStable(), "View = {0}", this.configurationWrapper.GetWriteView().IsStable); View readView = this.configurationWrapper.GetReadView(); View writeView = this.configurationWrapper.GetWriteView(); long viewIdAfterFirstUpdate = writeView.ViewId; // Actually, both read and write views point to the same view Assert.IsTrue(readView == writeView); int headIndex = 0; long readViewHeadViewId = readView.GetReplicaInfo(readViewHeadIndex).ViewInWhichAddedToChain; Assert.IsTrue(writeView.GetReplicaInfo(headIndex).ViewInWhichAddedToChain == readViewHeadViewId + 1); //Now, make the read and write views the same this.UpdateConfiguration(replicas, 0); // validate all state Assert.IsTrue(this.configurationWrapper.IsViewStable()); readView = this.configurationWrapper.GetReadView(); writeView = this.configurationWrapper.GetWriteView(); Assert.IsTrue(readView == writeView); Assert.IsTrue(readView.ViewId == viewIdAfterFirstUpdate + 1); }
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 override bool Equals(object obj) { ReplicaInfo other = obj as ReplicaInfo; if (other == null) { return(false); } if (StorageAccountName != other.StorageAccountName) { return(false); } if (ViewInWhichAddedToChain != other.ViewInWhichAddedToChain) { return(false); } return(true); }
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 ReplicatedTableRepairResult RepairTable(string tableName, string storageAccountName, ReplicatedTableConfiguration configuration) { string viewName = ""; try { ReplicatedTableConfiguredTable tableConfig; if (!configuration.IsConfiguredTable(tableName, out tableConfig)) { return(new ReplicatedTableRepairResult(ReplicatedTableRepairCode.NotConfiguredTable, tableName)); } viewName = tableConfig.ViewName; List <ReplicaInfo> list = configuration.GetView(viewName).ReplicaChain; if (!list.Any() || list[0].StorageAccountName != storageAccountName) { return(new ReplicatedTableRepairResult(ReplicatedTableRepairCode.NotImpactedTable, tableName, viewName, storageAccountName)); } ReplicaInfo head = list[0]; if (head.Status != ReplicaStatus.WriteOnly) { return(new ReplicatedTableRepairResult(ReplicatedTableRepairCode.StableTable, tableName, viewName, storageAccountName)); } int viewIdToRecoverFrom = (int)head.ViewWhenTurnedOff; ReplicatedTableLogger.LogInformational("RepairTable={0}, View={1}, StorageAccountName={2}, from viewId={3} ...", tableName, viewName, storageAccountName, viewIdToRecoverFrom); // Repairing ... ReconfigurationStatus status = new ReplicatedTable(tableName, this).RepairTable(viewIdToRecoverFrom, null); ReplicatedTableLogger.LogInformational("RepairTable={0}, View={1}, StorageAccountName={2}, from viewId={3} => Status={4}", tableName, viewName, storageAccountName, viewIdToRecoverFrom, status); if (status == ReconfigurationStatus.SUCCESS) { return(new ReplicatedTableRepairResult(ReplicatedTableRepairCode.Success, tableName, viewName, storageAccountName)); } // Failure! return(new ReplicatedTableRepairResult(ReplicatedTableRepairCode.Error, tableName, viewName, storageAccountName) { Status = status, }); } catch (Exception ex) { return(new ReplicatedTableRepairResult(ReplicatedTableRepairCode.Error, tableName, viewName, storageAccountName) { Status = ReconfigurationStatus.FAILURE, Message = ex.ToString(), }); } }
/// <summary> /// Connection string infered from blob content /// </summary> /// <param name="replica"></param> private void OldStrategyToSetConnectionString(ReplicaInfo replica) { string connectionString = String.Format(Constants.ShortConnectioStringTemplate, useHttps ? "https" : "http", replica.StorageAccountName, replica.StorageAccountKey); replica.ConnectionString = SecureStringHelper.ToSecureString(connectionString); }
/* * Class functions: */ protected internal static 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; }
private void RefreshReadAndWriteViewsFromBlobs(object arg) { lock (this) { this.lastRenewedReadView = new View(); this.lastRenewedWriteView = new View(); DateTime refreshStartTime = DateTime.UtcNow; Dictionary <long, List <CloudBlockBlob> > viewResult = new Dictionary <long, List <CloudBlockBlob> >(); foreach (var blob in this.blobs) { ReplicatedTableConfigurationStore configurationStore; if (!CloudBlobHelpers.TryReadBlob <ReplicatedTableConfigurationStore>(blob.Value, out configurationStore)) { continue; } if (configurationStore.ViewId <= 0) { ReplicatedTableLogger.LogInformational("ViewId={0} is invalid. Must be >= 1. Skipping this blob {1}.", configurationStore.ViewId, blob.Value.Uri); continue; } List <CloudBlockBlob> viewBlobs; if (!viewResult.TryGetValue(configurationStore.ViewId, out viewBlobs)) { viewBlobs = new List <CloudBlockBlob>(); viewResult.Add(configurationStore.ViewId, viewBlobs); } viewBlobs.Add(blob.Value); if (viewBlobs.Count >= this.quorumSize) { this.lastRenewedReadView.ViewId = this.lastRenewedWriteView.ViewId = configurationStore.ViewId; for (int i = 0; i < configurationStore.ReplicaChain.Count; i++) { ReplicaInfo replica = configurationStore.ReplicaChain[i]; CloudTableClient tableClient = GetTableClientForReplica(replica); if (replica != null && tableClient != null) { //Update the write view always this.lastRenewedWriteView.Chain.Add(new Tuple <ReplicaInfo, CloudTableClient>(replica, tableClient)); //Update the read view only for replicas part of the view if (i >= configurationStore.ReadViewHeadIndex) { this.lastRenewedReadView.Chain.Add(new Tuple <ReplicaInfo, CloudTableClient>(replica, tableClient)); } //Note the time when the view was updated this.lastViewRefreshTime = refreshStartTime; this.ConvertXStoreTableMode = configurationStore.ConvertXStoreTableMode; } } this.lastRenewedWriteView.ReadHeadIndex = configurationStore.ReadViewHeadIndex; break; } } } }