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); }
private void ThrowIfAnyPartitionViewHasManyReplicasInConversionMode(ReplicatedTableConfiguredTable config) { if (config.ConvertToRTable == false || config.PartitionsToViewMap == null) { return; } /* * Key = "" - View = "" => Ignore * Key = "" - View = "viewName" => Ignore * Key = "X" - View = "" => Should never happen (already tken care by the flow) * Key = "Y" - View = "viewName" => 'viewName' can't have more than 1 replica */ foreach (var entry in config.PartitionsToViewMap.Where(e => !string.IsNullOrEmpty(e.Key))) { string viewName = entry.Value; ReplicatedTableConfigurationStore viewConfig = GetView(viewName); // Assert (viewConfig != null) // In Conversion mode, view should not have more than 1 replica List <ReplicaInfo> chainList = viewConfig.GetCurrentReplicaChain(); if (chainList.Count <= 1) { continue; } var msg = string.Format("Table:\'{0}\' refers a partition view:\'{1}\' with more than 1 replica while in Conversion mode!", config.TableName, viewName); throw new Exception(msg); } }
private void ThrowIfViewBreaksTableConstraint(string viewName, ReplicatedTableConfigurationStore config) { foreach (ReplicatedTableConfiguredTable table in tableList) { if (table.ConvertToRTable == false || !table.IsViewReferenced(viewName)) { continue; } // Conversion mode: view shoud not have more than 1 replica List <ReplicaInfo> chainList = config.GetCurrentReplicaChain(); if (chainList.Count <= 1) { continue; } var msg = string.Format("Table:\'{0}\' should not have a view:\'{1}\' with more than 1 replica since it is in Conversion mode!", table.TableName, viewName); 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; 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); }
private void ThrowIfViewHasManyReplicasInConvertionMode(ReplicatedTableConfiguredTable config) { if (config.ConvertToRTable == false || string.IsNullOrEmpty(config.ViewName)) { return; } ReplicatedTableConfigurationStore viewConfig = GetView(config.ViewName); // Assert (viewConfig != null) // In Convertion mode, view should not have more than 1 replica List <ReplicaInfo> chainList = viewConfig.GetCurrentReplicaChain(); if (chainList.Count <= 1) { return; } var msg = string.Format("Table:\'{0}\' refers a view:\'{1}\' with more than 1 replica while in Convertion mode!", config.TableName, config.ViewName); throw new Exception(msg); }
private void ThrowIfViewIsNotValid(string viewName, ReplicatedTableConfigurationStore config) { if (config.ReplicaChain == null || config.ReplicaChain.Any(replica => replica == null)) { var msg = string.Format("View:\'{0}\' has a null replica(s) !!!", viewName); throw new Exception(msg); } List <ReplicaInfo> chainList = config.GetCurrentReplicaChain(); if (chainList.Any()) { /* RULE 1: * ======= * Read replicas rule: * - [R] replicas are contiguous from Tail backwards * - [R] replica count >= 1 */ string readPattern = "^W*R+$"; /* RULE 2: * ======= * Write replicas rule: * - [W] replicas are contiguous from Head onwards * - [W] replica count = 0 or = ChainLength */ string writePattern = "^((R+)|(W+))$"; // Get replica sequences string readSeq = ""; string writeSeq = ""; foreach (var replica in chainList) { // Read sequence: if (replica.IsReadable()) { readSeq += "R"; } else { readSeq += "W"; } // Write sequence: if (replica.IsWritable()) { writeSeq += "W"; } else { writeSeq += "R"; } } // Verify RULE 1: if (!Regex.IsMatch(readSeq, readPattern)) { var msg = string.Format("View:\'{0}\' has invalid Read chain:\'{1}\' !!!", viewName, readSeq); throw new Exception(msg); } // Verify RULE 2: if (!Regex.IsMatch(writeSeq, writePattern)) { var msg = string.Format("View:\'{0}\' has invalid Write chain:\'{1}\' !!!", viewName, writeSeq); throw new Exception(msg); } } }
private static void MoveReplicaToFrontAndSetViewToReadOnly(string viewName, ReplicatedTableConfigurationStore conf, string storageAccountName) { List<ReplicaInfo> list = conf.ReplicaChain; int matchIndex = list.FindIndex(r => r.StorageAccountName == storageAccountName); if (matchIndex == -1) { return; } // - Ensure its status is *None* ReplicaInfo candidateReplica = list[matchIndex]; candidateReplica.Status = ReplicaStatus.None; // - Move it to the front of the chain list.RemoveAt(matchIndex); list.Insert(0, candidateReplica); // Set all active replicas to *ReadOnly* foreach (ReplicaInfo replica in conf.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 conf.ViewId++; }
private static void EnableWriteOnReplicas(string viewName, ReplicatedTableConfigurationStore conf, string storageAccountName) { List<ReplicaInfo> list = conf.ReplicaChain; if (!list.Any() || list[0].StorageAccountName != storageAccountName) { return; } // First, enable Write on all replicas foreach (ReplicaInfo replica in conf.GetCurrentReplicaChain()) { replica.Status = ReplicaStatus.ReadWrite; } // Then, set the head to WriteOnly list[0].Status = ReplicaStatus.WriteOnly; // one replica chain ? Force to ReadWrite if (conf.GetCurrentReplicaChain().Count == 1) { list[0].Status = ReplicaStatus.ReadWrite; } // Update view id conf.ViewId++; }
private void ThrowIfViewIsNotValid(string viewName, ReplicatedTableConfigurationStore config) { if (config.ReplicaChain == null || config.ReplicaChain.Any(replica => replica == null)) { var msg = string.Format("View:\'{0}\' has a null replica(s) !!!", viewName); throw new Exception(msg); } List<ReplicaInfo> chainList = config.GetCurrentReplicaChain(); if (chainList.Any()) { /* RULE 1: * ======= * Read replicas rule: * - [R] replicas are contiguous from Tail backwards * - [R] replica count >= 1 */ string readPattern = "^W*R+$"; /* RULE 2: * ======= * Write replicas rule: * - [W] replicas are contiguous from Head onwards * - [W] replica count = 0 or = ChainLength */ string writePattern = "^((R+)|(W+))$"; // Get replica sequences string readSeq = ""; string writeSeq = ""; foreach (var replica in chainList) { // Read sequence: if (replica.IsReadable()) { readSeq += "R"; } else { readSeq += "W"; } // Write sequence: if (replica.IsWritable()) { writeSeq += "W"; } else { writeSeq += "R"; } } // Verify RULE 1: if (!Regex.IsMatch(readSeq, readPattern)) { var msg = string.Format("View:\'{0}\' has invalid Read chain:\'{1}\' !!!", viewName, readSeq); throw new Exception(msg); } // Verify RULE 2: if (!Regex.IsMatch(writeSeq, writePattern)) { var msg = string.Format("View:\'{0}\' has invalid Write chain:\'{1}\' !!!", viewName, writeSeq); 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) { view.Chain.Add(new Tuple<ReplicaInfo, CloudTableClient>(replica, tableClient)); } } // Infered: first readable replica view.ReadHeadIndex = view.Chain.FindIndex(tuple => tuple.Item1.IsReadable()); } return view; }