예제 #1
0
        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());
        }
예제 #2
0
        public static ReplicatedTableQuorumReadResult TryReadBlobQuorumFast <T>(List <CloudBlockBlob> blobs, out T value, out List <string> eTags, Func <string, T> ParseBlobFunc)
            where T : class
        {
            value = default(T);
            eTags = null;

            int numberOfBlobs = blobs.Count;

            var valuesArray = new List <T>(new T[numberOfBlobs]);
            var eTagsArray  = new List <string>(new string[numberOfBlobs]);
            var resultArray = new List <ReplicatedTableReadBlobResult>(new ReplicatedTableReadBlobResult[numberOfBlobs]);

            var cancel = new CancellationTokenSource();


            /*
             * Read async all the blobs in parallel
             */
            Parallel.For(0, numberOfBlobs, async(index) =>
            {
                valuesArray[index] = default(T);
                eTagsArray[index]  = null;
                resultArray[index] = new ReplicatedTableReadBlobResult(ReadBlobCode.NullObject, "downloaded not started yet!");

                DateTime startTime = DateTime.UtcNow;

                resultArray[index] = await TryReadBlobAsync(
                    blobs[index],
                    (currentValue, currentETag) =>
                {
                    valuesArray[index] = currentValue;
                    eTagsArray[index]  = currentETag;
                },
                    ParseBlobFunc,
                    cancel.Token);

                if (resultArray[index].Code == ReadBlobCode.Success)
                {
                    ReplicatedTableLogger.LogInformational("TryReadBlobAsync #{0} took {1}", index, DateTime.UtcNow - startTime);
                }
            });


            /*
             * Poll for "Quorum" progress ...
             */
            ReplicatedTableQuorumReadResult majority;
            int quorumIndex;

            do
            {
                Thread.Sleep(Constants.QuorumPollingInMilliSeconds);


                // "resultArray" may change OOB just after Evaluate Quorum step below.
                // In such case, we may exit the loop because all blobs are retrieved, while "majority" has a stale value!
                // Therefore, we have to determine, before Evaluate Quorum step, if we'll exit the loop or no.
                //      If Exist, then "majority" would be final.
                //      If No, then we'll loop to compute the latest, unless we break because we already have Quorum without all blobs.
                bool allBlobsRetrieved = true;

                // IMPORTANT: foreach()/LINQ throws when "resultArray" changes (race condition).
                for (int result = 0; result < resultArray.Count; result++)
                {
                    if (resultArray[result].Code == ReadBlobCode.NullObject)
                    {
                        allBlobsRetrieved = false;
                        break;
                    }
                }


                // Evaluate Quorum ...
                majority = FindMajority(resultArray.AsReadOnly(), valuesArray.AsReadOnly(), out quorumIndex);

                if (majority.Code == ReplicatedTableQuorumReadCode.NotFound ||
                    majority.Code == ReplicatedTableQuorumReadCode.UpdateInProgress ||
                    majority.Code == ReplicatedTableQuorumReadCode.Exception ||
                    majority.Code == ReplicatedTableQuorumReadCode.Success)
                {
                    // Quorum => cancel tasks and exit
                    cancel.Cancel();
                    break;
                }
                //else
                if (allBlobsRetrieved)
                {
                    // All blobs 'were' retrieved => exit
                    break;
                }

                // keep polling ...
            } while (true);


            cancel = null;


            if (majority.Code == ReplicatedTableQuorumReadCode.Success)
            {
                value = valuesArray[quorumIndex];
                eTags = eTagsArray;
            }

            return(majority);
        }
        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();
        }