summaryrefslogtreecommitdiff
path: root/src/libpcp_qmc/src/qmc_indom.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libpcp_qmc/src/qmc_indom.cpp')
-rw-r--r--src/libpcp_qmc/src/qmc_indom.cpp481
1 files changed, 481 insertions, 0 deletions
diff --git a/src/libpcp_qmc/src/qmc_indom.cpp b/src/libpcp_qmc/src/qmc_indom.cpp
new file mode 100644
index 0000000..67dd260
--- /dev/null
+++ b/src/libpcp_qmc/src/qmc_indom.cpp
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 1997,2005 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2007 Aconex. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ */
+
+#include "qmc_indom.h"
+#include "qmc_desc.h"
+#include <ctype.h>
+#include <QVector>
+#include <QStringList>
+
+QmcInstance::QmcInstance()
+{
+ my.inst = PM_IN_NULL;
+ my.refCount = 0;
+ my.index = -1;
+ my.active = false;
+}
+
+QmcInstance::QmcInstance(int id, const char* name)
+{
+ my.inst = id;
+ my.name = name;
+ my.refCount = 0;
+ my.index = -1;
+ my.active = true;
+}
+
+void
+QmcInstance::deactivate(int nullIndex)
+{
+ my.inst = PM_IN_NULL;
+ my.name = "";
+ my.refCount = 0;
+ my.index = nullIndex;
+ my.active = false;
+}
+
+QmcInstance const&
+QmcInstance::operator=(QmcInstance const& rhs)
+{
+ if (this != &rhs) {
+ my.inst = rhs.inst();
+ my.name = rhs.name();
+ my.refCount = rhs.refCount();
+ my.index = rhs.index();
+ my.active = rhs.active();
+ }
+ return *this;
+}
+
+QmcIndom::QmcIndom(int type, QmcDesc &desc)
+{
+ int *instList;
+ char **nameList;
+
+ my.type = type;
+ my.id = desc.desc().indom;
+ my.profile = false;
+ my.changed = false;
+ my.updated = true;
+ my.count = 0;
+ my.nullCount = 0;
+ my.nullIndex = UINT_MAX;
+ my.numActive = 0;
+ my.numActiveRef = 0;
+
+ if (my.id == PM_INDOM_NULL)
+ my.status = PM_ERR_INDOM;
+ else if (my.type == PM_CONTEXT_HOST || my.type == PM_CONTEXT_LOCAL)
+ my.status = pmGetInDom(my.id, &instList, &nameList);
+ else if (my.type == PM_CONTEXT_ARCHIVE)
+ my.status = pmGetInDomArchive(my.id, &instList, &nameList);
+ else
+ my.status = PM_ERR_NOCONTEXT;
+
+ if (my.status > 0) {
+ for (int i = 0; i < my.status; i++)
+ my.instances.append(QmcInstance(instList[i], nameList[i]));
+ my.numActive = my.status;
+ free(instList);
+ free(nameList);
+
+ if (pmDebug & DBG_TRACE_INDOM) {
+ QTextStream cerr(stderr);
+ cerr << "QmcIndom::QmcIndom: indom ";
+ }
+ }
+ else if (my.status < 0 && pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ cerr << "QmcIndom::QmcIndom: unable to lookup "
+ << pmInDomStr(my.id) << " from "
+ << (my.type == PM_CONTEXT_ARCHIVE ? "archive" : "host/local")
+ << " source: " << pmErrStr(my.status) << endl;
+ }
+}
+
+int
+QmcIndom::lookup(QString const &name)
+{
+ int i;
+ bool ok;
+ QStringList list;
+
+ for (i = 0; i < my.instances.size(); i++) {
+ if (my.instances[i].null())
+ continue;
+ if (my.instances[i].name().compare(name) == 0) {
+ if (my.instances[i].refCount() == 0) {
+ my.profile = true;
+ my.count++;
+ if (my.instances[i].active())
+ my.numActiveRef++;
+ }
+ my.instances[i].refCountInc();
+ return i;
+ }
+ }
+
+ // Match up to the first space
+ // Need this for proc and similiar agents
+
+ for (i = 0; i < my.instances.size(); i++) {
+ if (my.instances[i].null())
+ continue;
+ list = my.instances[i].name().split(QChar(' '));
+ if (list.size() <= 1)
+ continue;
+ if (name.compare(list.at(0)) == 0) {
+ if (pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ cerr << "QmcIndom::lookup: inst \"" << name << "\"(" << i
+ << ") matched to \"" << my.instances[i].name() << "\"("
+ << i << ')' << endl;
+ }
+ if (my.instances[i].refCount() == 0) {
+ my.profile = true;
+ my.count++;
+ if (my.instances[i].active())
+ my.numActiveRef++;
+ }
+ my.instances[i].refCountInc();
+ return i;
+ }
+ }
+
+ // If the instance requested is numeric, then ignore leading
+ // zeros in the instance up to the first space
+ int nameNumber = name.toInt(&ok);
+
+ // The requested instance is numeric
+ if (ok) {
+ for (i = 0; i < my.instances.size(); i++) {
+ if (my.instances[i].null())
+ continue;
+
+ list = my.instances[i].name().split(QChar(' '));
+ if (list.size() <= 1)
+ continue;
+ int instNumber = list.at(0).toInt(&ok);
+ if (!ok)
+ continue;
+ if (instNumber == nameNumber) {
+ if (pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ cerr << "QmcIndom::lookup: numerical inst \""
+ << name << " matched to \"" << my.instances[i].name()
+ << "\"(" << i << ')' << endl;
+ }
+ if (my.instances[i].refCount() == 0) {
+ my.profile = true;
+ my.count++;
+ if (my.instances[i].active())
+ my.numActiveRef++;
+ }
+ my.instances[i].refCountInc();
+ return i;
+ }
+ }
+ }
+
+ return -1; // we don't know about that instance
+}
+
+void
+QmcIndom::refAll(bool active)
+{
+ my.numActiveRef = 0;
+
+ for (int i = 0; i < my.instances.size(); i++) {
+ if (my.instances[i].null() || (active && !my.instances[i].active()))
+ continue;
+
+ if (my.instances[i].refCount() == 0)
+ my.profile = true;
+ if (my.instances[i].active())
+ my.numActiveRef++;
+
+ my.instances[i].refCountInc();
+ }
+ my.count = my.instances.size() - my.nullCount;
+}
+
+void
+QmcIndom::removeRef(uint index)
+{
+ Q_ASSERT(my.instances[index].refCount());
+
+ my.instances[index].refCountDec();
+ if (my.instances[index].refCount() == 0) {
+ my.profile = true;
+ my.count--;
+ if (my.instances[index].active())
+ my.numActiveRef--;
+ }
+}
+
+int
+QmcIndom::genProfile()
+{
+ int i, j;
+ int sts = 0;
+ int *ptr = NULL;
+ QVector<int> list;
+ const char *action = NULL;
+
+ // If all instances are referenced or there are no instances
+ // then request all instances
+ if (my.numActiveRef == my.numActive || my.numActive == 0) {
+ sts = pmAddProfile(my.id, 0, NULL);
+ action = "ALL";
+ }
+ // If the number of referenced instances is less than the number
+ // of unreferenced active instances, then the smallest profile
+ // is to add all the referenced instances
+ else if (my.count < (my.numActive - my.numActiveRef)) {
+ action = "ADD";
+ sts = pmDelProfile(my.id, 0, NULL);
+ if (sts >= 0) {
+ list.resize(my.count);
+ for (i = 0, j = 0; i < my.instances.size(); i++)
+ if (!my.instances[i].null() && my.instances[i].refCount())
+ list[j++] = my.instances[i].inst();
+ ptr = list.data();
+ sts = pmAddProfile(my.id, list.size(), ptr);
+ }
+ }
+ // Delete those active instances that are not referenced
+ else {
+ action = "DELETE";
+ sts = pmAddProfile(my.id, 0, NULL);
+ if (sts >= 0) {
+ list.resize(my.instances.size() - my.count);
+ for (i = 0, j = 0; i < my.instances.size(); i++)
+ if (!my.instances[i].null() &&
+ my.instances[i].refCount() == 0 &&
+ my.instances[i].active())
+ list[j++] = my.instances[i].inst();
+ ptr = list.data();
+ sts = pmDelProfile(my.id, list.size(), ptr);
+ }
+ }
+
+ if (pmDebug & (DBG_TRACE_PMC | DBG_TRACE_INDOM | DBG_TRACE_PROFILE)) {
+ QTextStream cerr(stderr);
+ cerr << "QmcIndom::genProfile: id = " << my.id << ", count = "
+ << my.count << ", numInsts = " << numInsts() << ", active = "
+ << my.numActive << ", activeRef = " << my.numActiveRef
+ << ": " << action << " ptr = " << ptr;
+ if (sts < 0)
+ cerr << ", sts = " << sts << ": " << pmErrStr(sts);
+ cerr << endl;
+ }
+
+ if (sts >= 0)
+ my.profile = false;
+ return sts;
+}
+
+void
+QmcIndom::dump(QTextStream &os) const
+{
+ os << pmInDomStr(my.id) << ": " << numInsts() << " instances ("
+ << my.nullCount << " NULL)" << endl;
+ for (int i = 0; i < my.instances.size(); i++)
+ if (!my.instances[i].null())
+ os << " [" << my.instances[i].inst() << "] = \""
+ << my.instances[i].name() << "\" ("
+ << my.instances[i].refCount() << " refs) "
+ << (my.instances[i].active() ? "active" : "inactive") << endl;
+ else
+ os << " NULL -> " << my.instances[i].index() << endl;
+}
+
+int
+QmcIndom::update()
+{
+ int *instList;
+ char **nameList;
+ int i, j, count;
+ int oldLen = my.instances.size();
+ uint oldNullCount = my.nullCount;
+ int sts = 0;
+
+ // If the indom has already been updated, just check that all instances
+ // are referenced and remove any that have gone away.
+ if (!my.changed || my.updated) {
+ for (i = 0; i < oldLen; i++) {
+ QmcInstance &inst = my.instances[i];
+ if (inst.refCount() || inst.null() || inst.active())
+ continue;
+ inst.deactivate(my.nullIndex);
+ my.nullIndex = i;
+ my.nullCount++;
+ my.profile = true;
+ }
+ if (pmDebug & DBG_TRACE_INDOM && my.nullCount != oldNullCount) {
+ QTextStream cerr(stderr);
+ cerr << "QmcIndom::update: Cleaning indom " << pmInDomStr(my.id)
+ << ": Removed " << my.nullCount - oldNullCount
+ << " instances" << endl;
+ }
+ return 0;
+ }
+
+ my.updated = true;
+
+ if (my.type == PM_CONTEXT_ARCHIVE)
+ return 0;
+
+ if (my.type == PM_CONTEXT_HOST || my.type == PM_CONTEXT_LOCAL)
+ sts = pmGetInDom(my.id, &instList, &nameList);
+
+ my.numActive = 0;
+ my.numActiveRef = 0;
+
+ if (sts > 0) {
+ count = sts;
+ if (pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ cerr << "QmcIndom::update: Updating indom " << pmInDomStr(my.id)
+ << ": Got " << count << " instances (vs " << numInsts()
+ << ")" << endl;
+ }
+
+ // Any instances which are not in the new indom AND are not
+ // referenced can be removed
+ for (i = 0; i < oldLen; i++) {
+ QmcInstance &inst = my.instances[i];
+ inst.setActive(false);
+
+ if (inst.refCount() || inst.null())
+ continue;
+ j = 0;
+ if (i < count && inst.inst() == instList[i]) {
+ if (inst.name().compare(nameList[i]) == 0)
+ continue;
+ else
+ j = count;
+ }
+ for (; j < count; j++) {
+ if (inst.inst() == instList[j]) {
+ if (inst.name().compare(nameList[j]) == 0)
+ break;
+ else
+ j = count;
+ }
+ }
+
+ // If j >= count, then instance i has either changed or gone away
+ if (j >= count) {
+ inst.deactivate(my.nullIndex);
+ my.nullIndex = i;
+ my.nullCount++;
+ my.profile = true;
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ // Quick check to see if they are the same
+ if (i < my.instances.size() &&
+ my.instances[i].inst() == instList[i] &&
+ my.instances[i].name().compare(nameList[i]) == 0) {
+ if (pmDebug & DBG_TRACE_INDOM) {
+ QTextStream cerr(stderr);
+ cerr << "QmcIndom::update: Unchanged \"" << nameList[i]
+ << "\"(" << instList[i] << ')' << endl;
+ }
+ my.instances[i].setActive(true);
+ my.numActive++;
+ if (my.instances[i].refCount())
+ my.numActiveRef++;
+ continue;
+ }
+
+ for (j = 0; j < oldLen; j++) {
+ if (my.instances[j].null())
+ continue;
+
+ if (my.instances[j].inst() == instList[i]) {
+ // Same instance and same external name but different
+ // order, mark as active. If it has a different
+ // external name just ignore it
+ if (my.instances[j].name().compare(nameList[i]) == 0) {
+ my.instances[j].setActive(true);
+ my.numActive++;
+ if (my.instances[j].refCount())
+ my.numActiveRef++;
+ }
+ else if (pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ cerr << "QmcIndom::update: Ignoring \""
+ << nameList[i]
+ << "\" with identical internal identifier ("
+ << instList[i] << ")" << endl;
+ }
+ break;
+ }
+ }
+
+ if (j == oldLen) {
+ if (pmDebug & DBG_TRACE_INDOM) {
+ QTextStream cerr(stderr);
+ cerr << "QmcIndom::update: Adding \"" << nameList[i]
+ << "\"(" << instList[i] << ")" << endl;
+ }
+ if (my.nullCount) {
+ uint newindex = my.instances[my.nullIndex].index();
+ my.instances[my.nullIndex] = QmcInstance(instList[i],
+ nameList[i]);
+ my.nullIndex = newindex;
+ my.nullCount--;
+ }
+ else
+ my.instances.append(QmcInstance(instList[i], nameList[i]));
+ my.profile = true;
+ my.numActive++;
+ }
+ }
+
+ free(instList);
+ free(nameList);
+
+ if (pmDebug & DBG_TRACE_INDOM) {
+ QTextStream cerr(stderr);
+ if (my.instances.size() == oldLen && my.nullCount == oldNullCount)
+ cerr << "QmcIndom::update: indom size unchanged" << endl;
+ else {
+ cerr << "QmcIndom::update: indom changed from "
+ << oldLen - oldNullCount << " to " << numInsts() << endl;
+ dump(cerr);
+ }
+ }
+ }
+ else {
+ for (i = 0; i < my.instances.size(); i++)
+ my.instances[i].setActive(false);
+
+ if (pmDebug & DBG_TRACE_PMC) {
+ QTextStream cerr(stderr);
+ if (sts == 0)
+ cerr << "QmcIndom::update: indom empty!" << endl;
+ else
+ cerr << "QmcIndom::update: unable to lookup "
+ << pmInDomStr(my.id) << " from host/local source: "
+ << pmErrStr(sts) << endl;
+ }
+ }
+
+ return sts;
+}