// Compute expected utility as a weighted average over all of the SLAs used by all clients
        private float ExpectedUtilityForClients(ReplicaConfiguration config, Dictionary <string, ClientUsageData> clientData)
        {
            float avgExpectedUtility = 0;
            int   totalReads         = clientData.Values.Sum(client => client.NumberOfReads);
            float totalUtility       = 0;

            foreach (string clientName in clientData.Keys)
            {
                float totalClientUtility = 0;
                foreach (ServiceLevelAgreement sla in clientData[clientName].SLAs)
                {
                    float slaUtility = ExpectedUtilityForSla(config, sla, clientData[clientName].ServerRTTs);
                    totalClientUtility += slaUtility;
                }
                float avgClientUtility = 0;
                if (totalClientUtility > 0)
                {
                    avgClientUtility = totalClientUtility / clientData[clientName].SLAs.Count;
                }
                totalUtility += avgClientUtility * clientData[clientName].NumberOfReads;
            }
            if (totalReads != 0)
            {
                avgExpectedUtility = totalUtility / totalReads;
            }
            return(avgExpectedUtility);
        }
        /// <summary>
        /// Read the configuration blob from Azure storage and update the local configuration.
        /// </summary>
        internal bool DownloadConfiguration()
        {
            try
            {
                using (MemoryStream stream = new MemoryStream())
                {
                    configurationBlob.DownloadToStream(stream);
                    stream.Seek(0, 0);
                    BinaryFormatter      formatter   = new BinaryFormatter();
                    ReplicaConfiguration cloudConfig = (ReplicaConfiguration)formatter.Deserialize(stream);

                    if (!configurationBlob.Metadata.ContainsKey(ConstPool.EPOCH_NUMBER))
                    {
                        Console.WriteLine("No Epoch in configuration metadata!"); // this should not happen
                        return(false);                                            // stay with current configuration for now
                    }

                    int currentEpoch = Convert.ToInt32(configurationBlob.Metadata[ConstPool.EPOCH_NUMBER]);
                    if (currentEpoch > config.Epoch)
                    {
                        config.PrimaryServers = cloudConfig.PrimaryServers;
                        config.PrimaryServers.Sort();
                        config.SecondaryServers        = cloudConfig.SecondaryServers ?? new List <string>();
                        config.WriteOnlyPrimaryServers = cloudConfig.WriteOnlyPrimaryServers ?? new List <string>();
                        foreach (string server in config.SecondaryServers)
                        {
                            config.SetSyncPeriod(server, cloudConfig.GetSyncPeriod(server));
                        }

                        config.Epoch = currentEpoch;
                        if (configurationBlob.Metadata[ConstPool.EPOCH_MODIFIED_TIME] != null)
                        {
                            config.EpochModifiedTime = DateTimeOffset.Parse(configurationBlob.Metadata[ConstPool.EPOCH_MODIFIED_TIME]);
                        }
                        else
                        {
                            config.EpochModifiedTime = DateTimeOffset.MinValue;
                        }
                    }
                }
            }
            catch (StorageException se)
            {
                Console.WriteLine(se.ToString());
                Console.WriteLine(se.StackTrace);
                throw se;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                Console.WriteLine(ex.StackTrace);
                throw ex;
            }
            return(true);
        }
Exemple #3
0
 /// <summary>
 /// Returns the <see cref="ReplicaConfiguration"/> for a named container.
 /// If the configuration has not yet been cached locally, it is read from Azure's configuration container.
 /// </summary>
 /// <param name="containerName">Name of the container</param>
 /// <param name="cloudBacked">Whether the configuration should be fetched from Azure</param>
 /// <param name="autoRefresh">If true, the configuration will automatically refresh by reading its state from the azure storage. Hence, all new configurations will be reflected here automatically.</param>
 /// <returns></returns>
 public static ReplicaConfiguration GetConfiguration(string containerName, bool cloudBacked = true, bool autoRefresh = true)
 {
     if (!configurations.ContainsKey(containerName))
     {
         configurations[containerName] = new ReplicaConfiguration(containerName);
         if (cloudBacked)
         {
             configurations[containerName].SyncWithCloud(configurationAccount, autoRefresh);
         }
     }
     return(configurations[containerName]);
 }
Exemple #4
0
        /// <summary>
        /// Periodically uploads SLAs and SessionStates.
        /// SLAs and SessionStates are stored in two Azure tables called.
        /// </summary>
        public void StartUploadConfigurationTask(string containerName, List <ConsistencySLAEngine> engines, SessionState sessionState, ServerMonitor monitor)
        {
            activeUploaders[containerName] = true;
            int                  sleepDuration = 0;
            int                  epoch;
            DateTimeOffset       lastModified;
            ReplicaConfiguration configuration = ClientRegistry.GetConfiguration(containerName, false);

            if (configuration == null)
            {
                activeUploaders[containerName] = false;
            }

            while (activeUploaders[containerName])
            {
                try
                {
                    configuration.SyncWithCloud(ClientRegistry.GetConfigurationAccount());

                    while (!configuration.IsInFastMode())
                    {
                        lock (configuration)
                            Monitor.Wait(configuration, 1000);
                    }

                    epoch = configuration.Epoch;
                    Console.WriteLine("Uploading SLA and SessionState with Epoch: " + epoch);
                    lastModified = configuration.EpochModifiedTime;

                    //    |====a====|-conf in progress-|====b====|
                    //Clients upload their configurations between the middle of a configuration period, and before a configuration epoch is finished.
                    //I.e., after for example a, and before the first next bar, or after b, and before the next upcomming bar.
                    if (DateTimeOffset.Now.Subtract(lastModified).TotalMilliseconds > ConstPool.CONFIGURATION_UPLOAD_INTERVAL / 2)
                    {
                        UploadClientData(containerName, epoch, engines, sessionState, monitor);
                        //Console.WriteLine("Uploaded the configuration to the azure storage. ...");
                        sleepDuration = ConstPool.CONFIGURATION_UPLOAD_INTERVAL;
                    }
                    else
                    {
                        //we try to push the upload to some time after the middle of an epoch duration.
                        sleepDuration = (ConstPool.CONFIGURATION_UPLOAD_INTERVAL / 2) - DateTimeOffset.Now.Subtract(lastModified).Milliseconds;
                    }
                    Thread.Sleep(sleepDuration);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.StackTrace);
                    throw ex;
                }
            }
        }
        private float ComputeUtilityGain(ReplicaConfiguration config, List <ConfigurationAction> actions, Dictionary <string, ClientUsageData> clientData)
        {
            ReplicaConfiguration newConfig = config;

            foreach (ConfigurationAction action in actions)
            {
                newConfig = action.IfApply(newConfig);
            }

            float gain = ExpectedUtilityForClients(newConfig, clientData) - DeliveredUtilityForClients(config, clientData);

            return(gain);
        }
        private float ExpectedUtilityForSla(ReplicaConfiguration config, ServiceLevelAgreement sla, Dictionary <string, LatencyDistribution> serverRTTs)
        {
            float         utility        = 0;
            float         cumulativeProb = 0;
            float         prob           = 0;
            List <string> allServers     = config.GetServers(true, true, false);

            foreach (SubSLA sub in sla)
            {
                foreach (string server in allServers)
                {
                    prob = allServers.Max(s => serverRTTs[s].ProbabilityOfFindingValueLessThanGiven(sub.Latency)
                                          * ProbabilityOfServerConsistency(config, s, sub.Consistency, sub.Bound));
                }
                float subUtility = (1 - cumulativeProb) * prob * sub.Utility;
                utility        += subUtility;
                cumulativeProb += (1 - cumulativeProb) * prob;
            }
            return(utility);
        }
 /// <summary>
 /// Constructor for ConfigurationCloudStore
 /// </summary>
 /// <param name="account">the Azure account where configuration data is stored</param>
 public ConfigurationCloudStore(CloudStorageAccount account, ReplicaConfiguration configuration)
 {
     config = configuration;
     try
     {
         configurationCloudBlobClient = account.CreateCloudBlobClient();
         configurationContainer       = configurationCloudBlobClient.GetContainerReference(ConstPool.CONFIGURATION_CONTAINER_PREFIX + config.Name);
         configurationContainer.CreateIfNotExists();
         configurationBlob = configurationContainer.GetBlockBlobReference(ConstPool.CURRENT_CONFIGURATION_BLOB_NAME);
         if (!configurationBlob.Exists())
         {
             CreateConfiguration(false);
         }
     }
     catch (StorageException ex)
     {
         Console.WriteLine(ex.ToString());
         throw ex;
     }
 }
 public Replicator(string capCloudBlobContainerName)
 {
     configuration = ClientRegistry.GetConfiguration(capCloudBlobContainerName, true);
     name          = configuration.Name;
 }
Exemple #9
0
 public static void RemoveConfiguration(ReplicaConfiguration Configuration)
 {
     configurations.Remove(Configuration.Name);
 }
Exemple #10
0
 public static void AddConfiguration(ReplicaConfiguration Configuration)
 {
     configurations[Configuration.Name] = Configuration;
 }
        private List <ConfigurationAction> ChooseReconfigActions(Dictionary <string, ClientUsageData> clientData, List <ConfigurationConstraint> constraints, ReplicaConfiguration config)
        {
            Dictionary <string, ConfigurationAction> actions = new Dictionary <string, ConfigurationAction>();

            // build sorted list of all SLAs
            SortedSet <ServiceLevelAgreement> SLAs = new SortedSet <ServiceLevelAgreement>(new ServiceLevelAgreementComparer());

            foreach (ClientUsageData client in clientData.Values)
            {
                SLAs.UnionWith(client.SLAs);
            }

            AppendToLogger("Start Computing Actions");
            foreach (string clientName in clientData.Keys)
            {
                foreach (ServiceLevelAgreement sla in clientData[clientName].SLAs)
                {
                    Dictionary <string, ConfigurationAction> tmp = ActionSelector.ComputeActions(this.containerName, config, sla, clientData[clientName]);
                    foreach (string id in tmp.Keys)
                    {
                        if (!actions.ContainsKey(id))
                        {
                            actions[id] = tmp[id];
                        }
                        else
                        {
                            actions[id].Merge(tmp[id]);
                        }

                        //We keep track of clients. We will use this list in the checking phase (below)
                        actions[id].Clients.Add(clientName);

                        AppendToLogger(tmp[id].ToString());
                    }
                }
            }

            AppendToLogger("Start Checking Actions");
            foreach (string clientName in clientData.Keys)
            {
                foreach (ServiceLevelAgreement sla in clientData[clientName].SLAs)
                {
                    foreach (ConfigurationAction action in actions.Values)
                    {
                        if (!action.OriginatingSLAs.Contains(sla.Id) || !action.Clients.Contains(clientName))
                        {
                            ActionSelector.CheckAction(action, sla, clientData[clientName], config);
                        }
                    }
                }
            }

            foreach (ConfigurationAction action in actions.Values)
            {
                AppendToLogger(action.ToString());
            }

            List <ConfigurationAction> pickedAction  = new List <ConfigurationAction>();
            List <ConfigurationAction> sortedActions = actions.Values.ToList();

            //we do not even consider actions with negative gained utility.
            sortedActions.RemoveAll(e => e.GainedUtility < 0);
            sortedActions.Sort(new ConfigurationActionComparer());

            // we sort constraints based on their priority.
            constraints.Sort(new ConfigurationConstraintComparer());

            bool foundAction = false;

            for (int i = sortedActions.Count - 1; i >= 0; i--)
            {
                pickedAction.Clear();
                pickedAction.Add(sortedActions[i]);

                if (constraints.Count() == 0)
                {
                    foundAction = true;
                    break;
                }

                //Remove actions that are not satisfying constraints.
                foreach (ConfigurationConstraint c in constraints)
                {
                    c.Apply(pickedAction, constraints, SLAs, clientData);
                    if (pickedAction.All(e => e.Source == ConfigurationActionSource.Constraint))
                    {
                        //the action is removed because of conflict with other constraints.
                        foundAction = false;
                        break;
                    }
                    else
                    {
                        foundAction = true;
                    }
                }

                if (foundAction)
                {
                    break;
                }
            }

            if (!foundAction)
            {
                //no action is applicable with all constraints. so, we just try to apply constraints.
                //hence, no non-constraint action will be executed to improve utility.
                pickedAction.Clear();
                foreach (ConfigurationConstraint c in constraints)
                {
                    c.Apply(pickedAction, constraints, SLAs, clientData);
                }
            }

            return(pickedAction);
        }
        public List <ConfigurationAction> PickNewConfiguration(CloudStorageAccount account, int currentConfigurationEpoch, ReplicaConfiguration config, List <ConfigurationConstraint> constraints)
        {
            // Read client's data
            Dictionary <string, ClientUsageData> clientData;
            ClientUsageCloudStore store = new ClientUsageCloudStore(account, "configurator");

            clientData = store.ReadClientData(containerName, currentConfigurationEpoch);

            // Choose actions to produce a better configuration
            return(ChooseReconfigActions(clientData, constraints, config));
        }
        /// <summary>
        /// Picks a new configuration given a single SLA and single client's session state
        /// </summary>
        /// <param name="sla">The SLA for which the new configuration should be tailored</param>
        /// <param name="ss">The session state</param>
        /// <param name="constraints">The constraints</param>
        /// <returns>a set of reconfiguration actions</returns>
        public List <ConfigurationAction> PickNewConfiguration(string containerName, ServiceLevelAgreement sla, SessionState ss, ServerMonitor monitor, ReplicaConfiguration config, List <ConfigurationConstraint> constraints)
        {
            Dictionary <string, ClientUsageData> clientData = new Dictionary <string, ClientUsageData>();
            ClientUsageData usage = new ClientUsageData("local");

            // Convert args into client data
            usage.SLAs.Add(sla);
            usage.NumberOfReads  = ss.GetNumberOfReadsPerMonth();
            usage.NumberOfWrites = ss.GetNumberOfWritesPerMonth();
            usage.ServerRTTs     = new Dictionary <string, LatencyDistribution>();
            foreach (ServerState server in monitor.GetAllServersState())
            {
                usage.ServerRTTs.Add(server.Name, server.RTTs);
            }

            // Use client data for a single user
            clientData.Add(usage.ClientName, usage);

            // Choose actions to produce a better configuration
            return(ChooseReconfigActions(clientData, constraints, config));
        }
        // Returns the likelihood that a given server is sufficiently up-to-date to meet the given consistency
        // For many consistencies, this is hard to predict, and better predicitve models are possible.
        public float ProbabilityOfServerConsistency(ReplicaConfiguration config, string server, Consistency consistency, int bound)
        {
            float prob = 0;

            switch (consistency)
            {
            case Consistency.Strong:
                if (config.PrimaryServers.Contains(server) && !config.WriteOnlyPrimaryServers.Contains(server))
                {
                    prob = 1.0F;
                }
                break;

            case Consistency.ReadMyWrites:
            case Consistency.Session:
                // could possibly compute probability based on past performance and read/write ratio
                // for now, arbitrarily return 0.5
                prob = 0.5F;
                break;

            case Consistency.MonotonicReads:
                // almost always will read from the closest server
                prob = 1.0F;
                break;

            case Consistency.Causal:
                // could possibly compute probability based on past performance and read/write ratio
                // for now, arbitrarily return 0.25
                prob = 0.25F;
                break;

            case Consistency.Bounded:
            case Consistency.BoundedMonotonicReads:
                // depends on the sync frequency
                if (bound >= config.GetSyncPeriod(server))
                {
                    prob = 1.0F;
                }
                else
                {
                    prob = bound / config.GetSyncPeriod(server);
                }
                break;

            case Consistency.BoundedReadMyWrites:
            case Consistency.BoundedSession:
                // depends on the sync frequency
                if (bound >= config.GetSyncPeriod(server))
                {
                    prob = 0.5F;
                }
                else
                {
                    prob = bound / config.GetSyncPeriod(server);
                }
                break;

            case Consistency.Eventual:
                if (config.PrimaryServers.Contains(server) || config.SecondaryServers.Contains(server))
                {
                    prob = 1.0F;
                }
                break;

            default:
                prob = 0;
                break;
            }

            return(prob);
        }
        public void Configure(CloudStorageAccount account, int currentConfigurationEpoch, ReplicaConfiguration currentConfig, List <ConfigurationConstraint> constraints)
        {
            List <ConfigurationAction> pickedAction = PickNewConfiguration(account, currentConfigurationEpoch, currentConfig, constraints);

            InstallNewConfiguration(pickedAction);
        }
        /// <summary>
        /// Picks a new configuration given a single SLA and single client's session state
        /// </summary>
        /// <param name="sla">The SLA for which the new configuration should be tailored</param>
        /// <param name="ss">The session state</param>
        /// <param name="constraints">The constraints</param>
        /// <returns>a set of reconfiguration actions</returns>
        public float ComputeUtilityGainFromNewConfiguration(string containerName, ServiceLevelAgreement sla, SessionState ss, ServerMonitor monitor, ReplicaConfiguration config, List <ConfigurationAction> actions)
        {
            Dictionary <string, ClientUsageData> clientData = new Dictionary <string, ClientUsageData>();
            ClientUsageData usage = new ClientUsageData("local");

            // Convert args into client data
            usage.SLAs.Add(sla);
            usage.NumberOfReads  = ss.GetNumberOfReadsPerMonth();
            usage.NumberOfWrites = ss.GetNumberOfWritesPerMonth();
            usage.ServerRTTs     = new Dictionary <string, LatencyDistribution>();
            foreach (ServerState server in monitor.GetAllServersState())
            {
                usage.ServerRTTs.Add(server.Name, server.RTTs);
            }

            // Use client data for a single user
            clientData.Add(usage.ClientName, usage);

            return(ComputeUtilityGain(config, actions, clientData));
        }