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; }
/// <summary> /// True, if the read and write views are the same. False, otherwise. /// </summary> public bool IsViewStable() { int viewStableCount = 0; foreach (var blob in this.blobs) { ReplicatedTableConfigurationStore configurationStore; if (!CloudBlobHelpers.TryReadBlob <ReplicatedTableConfigurationStore>(blob.Value, out configurationStore)) { continue; } if (configurationStore.ReadViewHeadIndex == 0) { viewStableCount++; } } return(viewStableCount >= this.quorumSize); }
public void UpdateConfiguration(List <ReplicaInfo> replicaChain, int readViewHeadIndex, bool convertXStoreTableMode = false, long viewId = 0) { View currentView = GetWriteView(); if (viewId == 0) { if (!currentView.IsEmpty) { viewId = currentView.ViewId + 1; } else { viewId = 1; } } ReplicatedTableConfigurationStore newConfig = new ReplicatedTableConfigurationStore { LeaseDuration = Constants.LeaseDurationInSec, Timestamp = DateTime.UtcNow, ReplicaChain = replicaChain, ReadViewHeadIndex = readViewHeadIndex, ConvertXStoreTableMode = convertXStoreTableMode, ViewId = viewId }; //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 = viewId; } } Parallel.ForEach(this.configManager.GetBlobs(), blob => { ReplicatedTableConfigurationStore configurationStore = null; string eTag; /* * TODO: (per Parveen Patel <*****@*****.**>) * The below code is incomplete because we are supposed to use eTag to make the changes if the old blob exists. * This is to support multiple clients updating the config, not a high priority scenario but something we should look at. */ ReplicatedTableReadBlobResult result = CloudBlobHelpers.TryReadBlob( blob, out configurationStore, out eTag, JsonStore <ReplicatedTableConfigurationStore> .Deserialize); if (result.Code != ReadBlobCode.Success) { //This is the first time we are uploading the config configurationStore = new ReplicatedTableConfigurationStore(); } configurationStore = newConfig; CloudBlobHelpers.TryWriteBlob(blob, configurationStore.ToJson()); }); this.configManager.Invalidate(); }
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; } } } }