Пример #1
0
void CSSHScheduler::makeScheduleImpl(const CTopology& _topology,
                                     const CAgentChannel::weakConnectionPtrVector_t& _channels)
{
    m_schedule.clear();

    size_t nofChannels = _channels.size();
    // Fill host name to channel index map in order to reduce number of regex matches and speed up scheduling.
    map<string, vector<size_t>> hostToChannelMap;
    for (size_t iChannel = 0; iChannel < nofChannels; ++iChannel)
    {
        const auto& v = _channels[iChannel];
        if (v.expired())
            continue;
        auto ptr = v.lock();
        const SHostInfoCmd& hostInfo = ptr->getRemoteHostInfo();
        hostToChannelMap[hostInfo.m_host].push_back(iChannel);
    }

    // TODO: before scheduling the collections we have to sort them by a number of tasks in the collection.
    // TODO: for the moment we are not able to schedule collection without requirements.

    // Collect all tasks that belong to collections
    set<uint64_t> tasksInCollections;
    CollectionMap_t collectionMap;
    CTopology::TaskCollectionIteratorPair_t collections = _topology.getTaskCollectionIterator();
    for (auto it = collections.first; it != collections.second; it++)
    {
        const vector<uint64_t>& taskHashes = _topology.getTaskHashesByTaskCollectionHash(it->first);
        tasksInCollections.insert(taskHashes.begin(), taskHashes.end());
        collectionMap[it->second->getNofTasks()].push_back(it->first);
    }

    set<uint64_t> scheduledTasks;

    scheduleCollections(_topology, _channels, hostToChannelMap, scheduledTasks, collectionMap, true);
    scheduleTasks(_topology, _channels, hostToChannelMap, scheduledTasks, tasksInCollections, true);
    scheduleCollections(_topology, _channels, hostToChannelMap, scheduledTasks, collectionMap, false);
    scheduleTasks(_topology, _channels, hostToChannelMap, scheduledTasks, tasksInCollections, false);

    size_t totalNofTasks = _topology.getMainGroup()->getTotalNofTasks();
    if (totalNofTasks != m_schedule.size())
    {
        printSchedule();
        stringstream ss;
        ss << "Unable to make a schedule for tasks. Number of requested tasks: " << totalNofTasks
           << ". Number of scheduled tasks: " << m_schedule.size();
        throw runtime_error(ss.str());
    }

    printSchedule();
}
Пример #2
0
ALERROR CSystemMap::ExecuteCreator (STopologyCreateCtx &Ctx, CTopology &Topology, CXMLElement *pCreator)

//	ExecuteCreator
//
//	Runs a specific creator

	{
	ALERROR error;
	int i;

	//	If this is a root node tag then we add it and all its connections.

	if (strEquals(pCreator->GetTag(), ROOT_NODE_TAG))
		{
		if (error = Topology.AddTopologyNode(Ctx, pCreator->GetAttribute(ID_ATTRIB)))
			return error;
		}

	//	Otherwise we process the creator element

	else
		{
		for (i = 0; i < pCreator->GetContentElementCount(); i++)
			{
			CXMLElement *pDirective = pCreator->GetContentElement(i);

			if (strEquals(pDirective->GetTag(), NODE_TAG))
				{
				if (error = Topology.AddTopologyNode(Ctx, pDirective->GetAttribute(ID_ATTRIB)))
					return error;
				}
			else if (strEquals(pDirective->GetTag(), STARGATE_TAG) || strEquals(pDirective->GetTag(), STARGATES_TAG))
				{
				if (error = Topology.AddStargateFromXML(Ctx, pDirective))
					return error;
				}
			else
				{
				Ctx.sError = strPatternSubst(CONSTLIT("Unknown TopologyCreator directive: %s."), pDirective->GetTag());
				return ERR_FAIL;
				}
			}
		}

	return NOERROR;
	}
Пример #3
0
Файл: Test.cpp Проект: ktf/DDS
void check_topology_maps(const string& _topoName)
{
    CTopology topology;
    string topoFile(_topoName + ".xml");
    topology.init(topoFile, true);

    output_test_stream output1(_topoName + "_maps_1.txt", true);
    for (const auto& v : topology.getTopoIndexToTopoElementMap())
    {
        output1 << v.first.getPath() << " " << v.second->getPath() << "\n";
        // std::cout << v.first.getPath() << " " << v.second->getPath() << "\n";
    }
    BOOST_CHECK(output1.match_pattern());

    output_test_stream output2(_topoName + "_maps_2.txt", true);
    check_topology_map_task(topology.getHashToTaskInfoMap(), output2);

    output_test_stream output3(_topoName + "_maps_3.txt", true);
    check_topology_map(topology.getHashToTaskCollectionMap(), output3);

    output_test_stream output4(_topoName + "_maps_4.txt", true);
    check_topology_map(topology.getHashPathToTaskMap(), output4);

    output_test_stream output5(_topoName + "_maps_5.txt", true);
    check_topology_map(topology.getHashPathToTaskCollectionMap(), output5);
}
Пример #4
0
void ITopologyProcessor::RestoreMarks (CTopology &Topology, TArray<bool> &Saved)

//	RestoreMarks
//
//	Restore the mark for nodes

	{
	Topology.GetTopologyNodeList().RestoreMarks(Saved);
	}
Пример #5
0
void ITopologyProcessor::SaveAndMarkNodes (CTopology &Topology, CTopologyNodeList &NodeList, TArray<bool> *retSaved)

//	SaveAndMarkNodes
//
//	Saves the mark for all topology nodes. Then it marks all nodes in the NodeList
//	and clears the mark on all others.

	{
	int i;

	Topology.GetTopologyNodeList().SaveAndSetMarks(false, retSaved);

	for (i = 0; i < NodeList.GetCount(); i++)
		NodeList[i]->SetMarked(true);
	}
Пример #6
0
void CSSHScheduler::scheduleCollections(const CTopology& _topology,
                                        const CAgentChannel::weakConnectionPtrVector_t& _channels,
                                        map<string, vector<size_t>>& _hostToChannelMap,
                                        set<uint64_t>& _scheduledTasks,
                                        const CollectionMap_t& _collectionMap,
                                        bool useRequirement)
{
    for (const auto& it_col : _collectionMap)
    {
        for (auto id : it_col.second)
        {
            TaskCollectionPtr_t collection = _topology.getTaskCollectionByHash(id);

            // First path only for collections with requirements;
            // Second path for collections without requirements.
            if ((useRequirement && collection->getRequirement() == nullptr) ||
                (!useRequirement && collection->getRequirement() != nullptr))
                continue;

            bool collectionAssigned = false;

            for (auto& v : _hostToChannelMap)
            {
                if (v.second.size() >= collection->getNofTasks() &&
                    (!useRequirement || (useRequirement && collection->getRequirement()->hostPatterMatches(v.first))))
                {
                    const vector<uint64_t>& taskHashes = _topology.getTaskHashesByTaskCollectionHash(id);
                    for (auto hash : taskHashes)
                    {
                        const STaskInfo& info = _topology.getTaskInfoByHash(hash);

                        size_t channelIndex = v.second.back();
                        const auto& channel = _channels[channelIndex];

                        SSchedule schedule;
                        schedule.m_channel = channel;
                        schedule.m_task = info.m_task;
                        schedule.m_taskID = hash;
                        schedule.m_taskIndex = info.m_taskIndex;
                        schedule.m_collectionIndex = info.m_collectionIndex;
                        m_schedule.push_back(schedule);

                        v.second.pop_back();

                        _scheduledTasks.insert(hash);
                    }
                    collectionAssigned = true;
                    break;
                }
            }

            if (!collectionAssigned)
            {
                printSchedule();
                stringstream ss;
                ss << "Unable to schedule collection <" << id << "> with path " << collection->getPath();
                throw runtime_error(ss.str());
            }
        }
    }
}
Пример #7
0
int main(int argc, char* argv[])
{
    try
    {
        chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now();

        CUserDefaults::instance(); // Initialize user defaults
        Logger::instance().init(); // Initialize log

        size_t nInstances(0);
        size_t nMaxValue(g_maxValue);
        size_t type(0);
        size_t timeout(g_timeout);
        bool testErrors(true);

        // Generic options
        bpo::options_description options("task-test_key_value options");
        options.add_options()("help,h", "Produce help message");
        options.add_options()(
            "instances,i", bpo::value<size_t>(&nInstances)->default_value(0), "A number of instances");
        options.add_options()(
            "max-value", bpo::value<size_t>(&nMaxValue)->default_value(g_maxValue), "A max value of the property");
        options.add_options()("type,t", bpo::value<size_t>(&type)->default_value(0), "Type of task. Must be 0 or 1.");
        options.add_options()("test-errors",
                              "Indicates that taks will also put incorrect data and test the error messages.");
        options.add_options()("timeout",
                              bpo::value<size_t>(&timeout)->default_value(g_timeout),
                              "A max timeout for a task to get all properties.");

        // Parsing command-line
        bpo::variables_map vm;
        bpo::store(bpo::command_line_parser(argc, argv).options(options).run(), vm);
        bpo::notify(vm);

        if (vm.count("help") || vm.empty())
        {
            cout << options;
            return 0;
        }

        testErrors = vm.count("test-errors");

        LOG(info) << "Start task with type " << type;

        // Get list of READ and WRITE properties from topology
        CTopology topo;
        topo.init();
        uint64_t taskId = env_prop<EEnvProp::task_id>();
        const STopoRuntimeTask& runtimeTask = topo.getRuntimeTaskById(taskId);
        const CTopoProperty::PtrMap_t& properties = runtimeTask.m_task->getProperties();
        vector<string> readPropertyNames;
        vector<string> writePropertyNames;
        for (auto property : properties)
        {
            CTopoProperty::EAccessType accessType = property.second->getAccessType();
            string propertyName(property.first);
            if (accessType == CTopoProperty::EAccessType::READ)
            {
                readPropertyNames.push_back(propertyName);
            }
            else
            {
                writePropertyNames.push_back(propertyName);
            }
        }

        // DDS Intercom API
        CIntercomService service;
        CKeyValue keyValue(service);
        mutex keyMutex;
        condition_variable keyCondition;
        // on task done condition
        condition_variable onTaskDoneCondition;

        map<string, string> keyValueCache;
        size_t numWaits = 0;
        size_t numUpdateKeyValueCalls = 0;
        size_t currentIteration = (type == 0) ? 1 : 0;
        size_t numTaskDone = 0;

        // Subscribe on error events
        service.subscribeOnError([/*&keyCondition*/](EErrorCode _errorCode, const string& _msg) {
            LOG(error) << "Key-value error code: " << _errorCode << ", message: " << _msg;
        });

        // Subscribe on task done notifications
        service.subscribeOnTaskDone(
            [&numTaskDone, nInstances, &onTaskDoneCondition](uint64_t _taskID, uint32_t _exitCode) {
                ++numTaskDone;
                LOG(info) << "Task Done notification received for task " << _taskID << " with exit code " << _exitCode;
                // TODO: In order to properly account finished tasks, use taskID to get task's name
                if (numTaskDone >= nInstances)
                    onTaskDoneCondition.notify_all();
            });

        // Subscribe on key update events
        // DDS garantees that this callback function will not be called in parallel from multiple threads.
        // It is safe to update global data without locks inside the callback.
        keyValue.subscribe([&keyCondition, &currentIteration, &keyValueCache, &nInstances, &numUpdateKeyValueCalls](
                               const string& _propertyName, const string& _value, uint64_t _senderTaskID) {
            numUpdateKeyValueCalls++;

            string key = _propertyName + "." + to_string(_senderTaskID);
            keyValueCache[key] = _value;

            // Check that all values in the key-value cache have a correct value
            size_t counter = 0;
            string currentValue = to_string(currentIteration);
            for (const auto& v : keyValueCache)
            {
                if (v.second == currentValue)
                    counter++;
            }

            if (counter == nInstances * 5)
            {
                currentIteration += 2;
                keyCondition.notify_all();
            }
        });

        // Start listening to events we have subscribed on
        service.start();

        for (size_t i = 0; i < nMaxValue; ++i)
        {
            LOG(info) << "Start iteration " << i << ". Current value: " << currentIteration;

            // For tasks with type 0 we start with writing the properties.
            if ((i % 2 == 0 && type == 0) || (i % 2 == 1 && type == 1))
            {
                LOG(info) << "Iteration " << i << " start sending values.";

                string writePropValue = to_string(i);
                for (const auto& prop : writePropertyNames)
                {
                    keyValue.putValue(prop, writePropValue);
                }

                LOG(info) << "Iteration " << i << " all values have been sent.";

                // Writing non existing and readonly properties to test the errors
                if (testErrors)
                {
                    LOG(info) << "Iteration " << i << " sending wrong properties.";
                    keyValue.putValue("non_existing_property", "non_existing_property_name");
                    for (const auto& prop : readPropertyNames)
                    {
                        keyValue.putValue(prop, writePropValue);
                    }
                }
            }
            // For tasks with type 1 we start with subscribtion to properties.
            else if ((i % 2 == 0 && type == 1) || (i % 2 == 1 && type == 0))
            {
                LOG(info) << "Iteration " << i << " subscribe on property updates. Current value: " << currentIteration;

                unique_lock<mutex> lock(keyMutex);
                bool waitStatus = keyCondition.wait_for(
                    lock, chrono::seconds(timeout), [&currentIteration, &i] { return currentIteration > i; });

                // Timeout waiting for property updates
                if (waitStatus == false)
                {
                    LOG(error) << "Iteration " << i << " timed out waiting for property updates.";
                    LOG(error) << "Number of key-value update calls: " << numUpdateKeyValueCalls
                               << "; currentIteration: " << currentIteration << "; numWaits: " << numWaits;

                    LOG(error) << "Key value cache.\n" << map_to_string(keyValueCache);

                    if (currentIteration == nMaxValue - 1)
                    {
                        LOG(warning) << "Some properties of the LAST iteration are missing.";
                    }
                    else
                    {
                        LOG(fatal) << "Task failed: timeout wait for property updates.";
                        return EXIT_FAILURE;
                    }
                }

                LOG(info) << "Iteration " << i << " got all properties. Current value: " << currentIteration;
            }
        }

        if ((nMaxValue % 2 == 0 && type == 0) || (nMaxValue % 2 == 1 && type == 1))
        {
            unique_lock<mutex> lock(keyMutex);
            bool waitStatus = onTaskDoneCondition.wait_for(
                lock, chrono::seconds(timeout), [&numTaskDone, &nInstances] { return numTaskDone >= nInstances; });
            if (waitStatus == false)
            {
                LOG(error) << "Task failed: Timed out on waiting Task Done.";
                LOG(error) << "Finished tasks: " << numTaskDone << " expected: " << nInstances;
                return EXIT_FAILURE;
            }
        }

        LOG(info) << "Key value cache.\n" << map_to_string(keyValueCache);
        LOG(info) << "Task successfully done";

        chrono::high_resolution_clock::time_point t2 = chrono::high_resolution_clock::now();
        auto duration = chrono::duration_cast<chrono::seconds>(t2 - t1).count();
        LOG(info) << "Calculation time: " << duration << " seconds";
    }
    catch (exception& _e)
    {
        LOG(fatal) << "USER TASK Error: " << _e.what() << endl;
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}
Пример #8
0
ALERROR CSystemMap::AddFixedTopology (CTopology &Topology, CString *retsError)

//	AddFixedTopology
//
//	Adds all the nodes in its fixed topology

	{
	ALERROR error;
	int i;

	//	If we already added this map, then we're done

	if (m_bAdded)
		return NOERROR;

	//	Mark this map as added so we don't recurse back here when we
	//	process all the Uses statments.

	m_bAdded = true;

	//	Load all the maps that this map requires

	for (i = 0; i < m_Uses.GetCount(); i++)
		{
		if (error = m_Uses[i]->AddFixedTopology(Topology, retsError))
			return error;
		}

	//	Iterate over all creators and execute them

	CTopologyNodeList NodesAdded;
	STopologyCreateCtx Ctx;
	Ctx.pMap = GetDisplayMap();
	Ctx.pNodesAdded = &NodesAdded;

	//	We need to include any maps that we use.

	Ctx.Tables.Insert(&m_FixedTopology);
	for (i = 0; i < m_Uses.GetCount(); i++)
		Ctx.Tables.Insert(&m_Uses[i]->m_FixedTopology);

	for (i = 0; i < m_Creators.GetCount(); i++)
		{
		if (error = ExecuteCreator(Ctx, Topology, m_Creators[i]))
			{
			*retsError = strPatternSubst(CONSTLIT("SystemMap (%x): %s"), GetUNID(), Ctx.sError);
			return error;
			}
		}

	//	Add any additional nodes marked as "root" (this is here only for backwards compatibility)
	//	NOTE: This call only worries about the first table (Ctx.Tables[0])

	if (error = Topology.AddTopology(Ctx))
		{
		*retsError = strPatternSubst(CONSTLIT("SystemMap (%x): %s"), GetUNID(), Ctx.sError);
		return error;
		}

	//	Apply any topology processors (in order) on all the newly added nodes

	for (i = 0; i < m_Processors.GetCount(); i++)
		{
		//	Make a copy of the node list because each call will destroy it

		CTopologyNodeList NodeList = NodesAdded;

		//	Process

		if (error = m_Processors[i]->Process(this, Topology, NodeList, retsError))
			{
			*retsError = strPatternSubst(CONSTLIT("SystemMap (%x): %s"), GetUNID(), *retsError);
			return error;
			}
		}

	//	Make sure every node added has a system UNID

	for (i = 0; i < NodesAdded.GetCount(); i++)
		if (NodesAdded[i]->GetSystemDescUNID() == 0)
			{
			*retsError = strPatternSubst(CONSTLIT("SystemMap (%x): NodeID %s: No system specified"), GetUNID(), NodesAdded[i]->GetID());
			return ERR_FAIL;
			}

	return NOERROR;
	}