Exemplo n.º 1
0
        /// <summary>
        /// Applies the constraint to the given actions.
        /// Note that this function can add several new actions to the list of new actions. Those actions that are added by this constraint set their source field to Constraint.
        /// So, the reconfigurator will notice whether the action is added by the Apply from the constraint or is computed by itself.
        /// </summary>
        /// <param name="newActions"></param>
        /// <param name="constraints"></param>
        /// <param name="SLAs"></param>
        /// <param name="sessionStates"></param>
        internal override void Apply(List <ConfigurationAction> newActions, List <ConfigurationConstraint> constraints, SortedSet <ServiceLevelAgreement> SLAs, Dictionary <string, ClientUsageData> clientData)
        {
            int currentReplicaFactor = Configuration.PrimaryServers.Count + Configuration.SecondaryServers.Count;

            newActions.ForEach(a => currentReplicaFactor += a.NumberOfAddingReplica());

            if (currentReplicaFactor >= MinReplicationFactor && currentReplicaFactor <= MaxReplicationFactor)
            {
                return;
            }

            if (currentReplicaFactor < MinReplicationFactor)
            {
                //We have to add some secondary replica
                //We assume here that configurator does not add any remove replica action because configurator has a tendency of adding replicas
                //Without this assumption, we first need to see if there is such an action, and erase that action from newActions list instead of adding a new replica.

                // Make copy of list of non-replica servers
                List <string> availableServers = new List <string>();
                foreach (string server in Configuration.NonReplicaServers)
                {
                    availableServers.Add(server);
                }

                int mustAdd = MinReplicationFactor - currentReplicaFactor;

                foreach (ConfigurationAction action in newActions)
                {
                    if (action.NumberOfAddingReplica() > 0)
                    {
                        availableServers.Remove(action.ServerName);
                    }
                    else if (action.NumberOfAddingReplica() < 0)
                    {
                        availableServers.Add(action.ServerName);
                    }
                }


                if (availableServers.Count < mustAdd)
                {
                    throw new Exception("There are not enough servers to enforce this constraint.");
                }

                List <ConfigurationAction> toBeAdded = new List <ConfigurationAction>();
                while (mustAdd > 0)
                {
                    //we should add a new replica
                    string serverName          = availableServers.First();
                    ConfigurationAction action = new AddSecondaryServer(Configuration.Name, serverName, 0, null, ConfigurationActionSource.Constraint);
                    bool compatible            = true;
                    foreach (ConfigurationConstraint constraint in constraints)
                    {
                        if (!constraint.Compatible(action))
                        {
                            compatible = false;
                            break;
                        }
                    }

                    if (compatible)
                    {
                        toBeAdded.Add(action);
                        mustAdd--;
                    }

                    availableServers.RemoveAt(0);
                    if (mustAdd > 0 && availableServers.Count == 0)
                    {
                        throw new Exception("There are not enough servers to enforce this constraint.");
                    }
                }

                toBeAdded.ForEach(a => newActions.Add(a));
            }

            if (currentReplicaFactor > MaxReplicationFactor)
            {
                //The asumption for the minimum replication factor does not hold here.
                //I.e., there can be an action in newActions list that is adding a new replica, hence total  number of replicas has become more than the maximum allowed.
                //Therefore, instead of creating a new action to remove a replica, we first need to remove addReplica action from the newActions list.

                int mustRemove = currentReplicaFactor - MaxReplicationFactor;

                List <ConfigurationAction> toBeRemoved = new List <ConfigurationAction>();

                //first, we try to remove a secondary replica to meet the constraint.
                List <RemoveSecondaryServer> removeActions = new List <RemoveSecondaryServer>();

                // TODO: Make sure that this is doing the right thing.  This code seems strange to me.
                // Why only the first SLA?  And why remove all secondaries?

                ServiceLevelAgreement firstSLA = SLAs.First();
                string clientName = "";
                foreach (ClientUsageData usage in clientData.Values)
                {
                    if (usage.SLAs.Contains(firstSLA))
                    {
                        clientName = usage.ClientName;
                        break;
                    }
                }

                foreach (string server in Configuration.SecondaryServers)
                {
                    RemoveSecondaryServer action = new RemoveSecondaryServer(containerName, server, 0, null, ConfigurationActionSource.Constraint, clientData[clientName].NumberOfReads, clientData[clientName].NumberOfWrites);
                    action.Clients.Add(clientName);
                    removeActions.Add(action);
                }

                foreach (string client in clientData.Keys)
                {
                    foreach (ServiceLevelAgreement sla in clientData[client].SLAs)
                    {
                        foreach (ConfigurationAction action in removeActions)
                        {
                            if (!action.OriginatingSLAs.Contains(sla.Id) || !action.Clients.Contains(client))
                            {
                                ActionSelector.CheckAction(action, sla, clientData[client], Configuration);
                            }
                        }
                    }
                }

                removeActions.Sort(new ConfigurationActionComparer());
                float totalLostUtility = 0;
                float totalGainUtility = 0;
                newActions.ForEach(a => totalGainUtility += a.GainedUtility);

                foreach (RemoveSecondaryServer action in removeActions)
                {
                    if (action.GainedUtility + totalLostUtility + totalGainUtility > 0)
                    {
                        //we need one final test.
                        //we need to make sure that this action does not violate any other constraint.
                        bool compatible = true;
                        foreach (ConfigurationConstraint cc in constraints)
                        {
                            if (!cc.Compatible(action))
                            {
                                compatible = false;
                                break;
                            }
                        }
                        if (compatible)
                        {
                            totalLostUtility += action.GainedUtility;
                            mustRemove--;
                            newActions.Add(action);
                        }
                    }
                    if (mustRemove == 0)
                    {
                        return;
                    }
                }


                //then, we adding a new replica in newactions
                foreach (ConfigurationAction action in newActions)
                {
                    if (action.Source == ConfigurationActionSource.NonConstraint && action.NumberOfAddingReplica() > 0)
                    {
                        toBeRemoved.Add(action);
                        mustRemove--;
                    }

                    if (mustRemove == 0)
                    {
                        break;
                    }
                }

                newActions.RemoveAll(r => toBeRemoved.Contains(r));

                if (mustRemove == 0)
                {
                    return;
                }

                List <ConfigurationAction> toBeAdded = new List <ConfigurationAction>();
                //Removing configurator actions does not suffice to ensure the constraint.
                //Hence, we need to start removing secondary replicas.
                while (mustRemove > 0 && Configuration.SecondaryServers.Count > 0)
                {
                    string serverName          = Configuration.SecondaryServers.First();
                    ConfigurationAction action = new RemoveSecondaryServer(Configuration.Name, serverName, 0, null, ConfigurationActionSource.Constraint);
                    bool compatible            = true;
                    foreach (ConfigurationConstraint constraint in constraints)
                    {
                        if (!constraint.Compatible(action))
                        {
                            compatible = false;
                            break;
                        }
                    }

                    if (compatible)
                    {
                        toBeAdded.Add(action);
                        mustRemove--;
                    }
                }
                toBeAdded.ForEach(a => newActions.Add(a));

                if (mustRemove == 0)
                {
                    return;
                }

                //Removing secondaries was not enough either. we have to start removing primaries.
                toBeAdded = new List <ConfigurationAction>();
                while (mustRemove > 0 && Configuration.PrimaryServers.Count > 1)
                {
                    string serverName           = Configuration.PrimaryServers.Last();
                    ConfigurationAction action1 = new DowngradePrimary(Configuration.Name, serverName, 0, null, ConfigurationActionSource.Constraint);
                    ConfigurationAction action2 = new RemoveSecondaryServer(Configuration.Name, serverName, 0, null, ConfigurationActionSource.Constraint);
                    bool compatible             = true;
                    foreach (ConfigurationConstraint constraint in constraints)
                    {
                        if (!constraint.Compatible(action1) || !constraint.Compatible(action2))
                        {
                            compatible = false;
                            break;
                        }
                    }

                    if (compatible)
                    {
                        toBeAdded.Add(action1);
                        toBeAdded.Add(action2);
                        mustRemove--;
                    }
                }
                Debug.Assert(mustRemove == 0, "mustRemove should be zero by now. Something is wrong");
                toBeAdded.ForEach(a => newActions.Add(a));
            }
        }
Exemplo n.º 2
0
        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);
        }