Logo Search packages:      
Sourcecode: pcp-gui version File versions

qmc_indom.cpp

/*
 * 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 <assert.h>
#include <qvector.h>
#include <qstringlist.h>
#include <pcp/pmapi.h>

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)
{
    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;
}

Generated by  Doxygen 1.6.0   Back to index