[Fwd: RE: implementing a large table over a database]

Dave Barratt dbarratt____codimatech.com
Wed Apr 2 15:59:08 CEST 2003


Hi Martin
Thanks for your excellent posting on dynamic tables, its saving me alot of
headaches.  As a newbie to Agent development I was wondering if you could
expand on what the following methods you reference in your examples below
would actually do...

bool MyDatabaseTable::loadRow(const Oidx& indexOid)
{
 }

bool MyDatabaseTable::fillRow(int slot)
{
 }

bool MyDatabaseTable::checkSlotIndex(int slot, Oidx indexOid, int i)
{
}

Thanks in advance
Dave Barratt

----- Original Message -----
From: "Martin Janzen" <janzen____pixelmetrix.com>
To: "Frank Fock" <Frank.Fock____t-online.de>; "Gopi Krishna Bhavaraju"
<gopi at pspl.co.in>
Cc: <agentpp-dl____agentpp.com>
Sent: Thursday, March 27, 2003 9:44 AM
Subject: Re: [Fwd: RE: implementing a large table over a database]


>
> > Gopi Krishna Bhavaraju wrote:
> >> I came across this old posting which talks about adding sub-table rows
> >> dynamically. In this posting whenever a last row is hit in a table, it
> >> suggests to register rows for the next sub-table. But with this
> >> approach if the NMS directly queries (does  only sub-table walk) the
next
> >> sub-table, no
> >> rows corresponding to it will be shown. So, is this is correct way of
> >> registering sub-table rows dynamically?
>
> Frank Fock wrote:
>  > 1. What are sub-tables? How do you define a
>  >    "sub-table"?
>  > 2. Where in the original postings you quoted
>  >    is stated that a table should only be updated
>  >    when a search on a previous table has failed?
>  >    (The opposite is true, the MibTable::update
>  >    method has to be overridden for each table
>  >    with dynamic row allocation)
>
>
> I think that by "sub-tables", we're talking about the case in which an
> NMS doesn't walk the agent's entire MIB tree starting from the
> beginning, but instead begins at some arbitrary point -- at some
> arbitrary row in a table which is to be filled dynamically.  Is that
> about right, Gopi?
>
> If that's so, then the first request from the NMS to the agent will be a
> Get, not a GetNext, and so your MibTable's (overridden) update() method
> will be called.  For each subrequest, this method must load the
> requested row, extracting the index for the row from the OID, something
> like this:
>
> void
> MyMibTableSubclass::update(Agentpp::Request* pReq)
> {
>    // (Could check for changes to pReq and pReq->get_transaction_id(),
>    // returning if unchanged in order to avoid unnecessary work.)
>
>    // Throw away all previously loaded rows for this table.
>    clear();
>    mPreviousIndexOID.clear();  // see below
>
>    for (u_int sub = 0; sub < pReq->subrequests(); sub++)
>    {
>      // Extract the index value for this subrequest.
>      Agentpp::Oidx subrequestOID(pReq->get_oid(sub));
>      Agentpp::Oidx indexOID(index(subrequestOID));
>
>      switch (pReq->get_type())
>      {
>      case sNMP_PDU_GET:
>      case sNMP_PDU_SET:
>        // See whether the requested OID is in this table.
>        if (base(subrequestOID) != *key())
>          break;
>
>        // See whether we have a valid index OID.
>        if (!is_index_valid(indexOID))
>          break;
>
>        // Create a row for this index OID, if found in the database.
>        myDatabase.loadRow(indexOID);
>        break;
>
>      case sNMP_PDU_GETNEXT:
>      case sNMP_PDU_GETBULK:
>        // If this table's update() method was called in response
>        // to a GETNEXT request on the last object in a previous
>        // table, try to load the first row of the table, so that
>        // Agent++ knows it needs to descend into this subtree.
>        if (base(subrequestOID) < *key())
>        {
>          // As an optimization, see whether we just filled in
>          // the row corresponding to this index OID; see below.
>          if ((mPreviousIndexOID.len() == 0) ||
>              (indexOID != mPreviousIndexOID))
>          {
>            mPreviousIndexOID = indexOID;
>            loadFirstRow();
>          }
>        }
>
>        // Now the overridden MibTable::find_succ() method will call
>        // loadNextRow() as Agent++ traverses the table's subtree.
>        break;
>
>      default:
>        break;
>    }
> }
>
>
> Subsequent requests from the NMS will be GetNext requests, so your
> MibTable's (also overridden) find_succ() method will be called instead.
>   This method must make sure that the "next" row of the table is loaded
> (depending on what "next" means for that table).
>
> Also, there are a couple of special cases to watch out for.  First,
> because GetNext walks tables by column, if you hit the end of one column
> then you need to load the first row of the table again.  Second, because
> an SNMPv2 GetBulk request frequently asks for several columns of the
> same row, it'll save you a bunch of time if you check for this case as
well:
>
> Agentpp::Oidx
> MyMibTableSubclass::find_succ(
>    const Agentpp::Oidx& oid, Agentpp::Request* pReq)
> {
>    find_succ_impl(oid);
>    return MibTable::find_succ(oid, pReq);
> }
>
> bool
> MyMibTableSubclass::find_succ_impl(
>    const Agentpp::Oidx& oid, Agentpp::Request* pReq)
> {
>    // As an optimization, see whether we just filled in the row
>    // corresponding to this index OID.  (This will frequently be
>    // the case when processing GETBULK requests.)
>    Agentpp::Oidx indexOID(index(oid));
>    if ((mPreviousIndexOID.len() > 0) && (indexOID == mPreviousIndexOID))
>      return true;
>    mPreviousIndexOID = indexOID;
>
>    // If we are at the start of the table, load the first row.
>    if (indexOID.len() == 0)
>      return myDatabase.loadFirstRow();
>
>    // Find the row following the given index OID; returns true if found.
>    if (myDatabase.loadNextRow(indexOID))
>      return true;
>
>    // If we hit the end of the table, try again to load the first row,
>    // in case we need to wrap around to the top of the next column.
>    return myDatabase.loadFirstRow();
> }
>
>
> Note that when you hit the last row of the table, you do _not_ need to
> do anything special in order to load the first row of the next table in
> your MIB.  As it traverses back up the MIB tree and then down into the
> next table's subtree, Agent++ will call that table's update() method,
> giving it an OID whose index value is empty (ie. it will pass the OID of
> the next table itself, not of a specific columnar object within that
> table).  So, the loadRow() method should be trivial, and loadNextRow()
> is not much more difficult.  For example, assuming that the table has a
> key consisting of a single integer (here, a "slot number"), it might
> look like this:
>
> bool MyDatabaseTable::loadFirstRow() {return loadNextRow(1);}
>
> bool
> MyDatabaseTable::loadNextRow(const Agentpp::Oidx& indexOID)
> {
>    // If we're starting at the base of the table, find the first slot
>    // for which we have an entry.
>    if (indexOID.len() < 1)  // ie. < number of indices for this table
>        return loadFirstRow();
>
>    // Extract the slot number, which is the last indexOID subidentifier.
>    // If we want the row after this slot number, check it for errors.
>    // In case it's higher than the maximum allowed slot number, load the
>    // first row of the table, if any, so that Agent++ can wrap around to
>    // the top of the next column if necessary.
>    int slot;
>    if (!checkSlotIndex(slot, indexOID, 0))
>      return loadFirstRow();
>
>    // See whether there is an entry for a higher slot number.
>    // (If this fails, then our caller, onFindSucc(), will wrap around
>    // and call loadFirstRow() instead.)
>    return loadNextRow(slot + 1);
> }
>
> bool
> MyDatabaseTable::loadNextRow(int slot)
> {
>    // Create a row for the next higher slot number.
>    for (; slot <= MAX_NUM_OF_SLOTS; slot++)
>      if (fillRow(slot))
>        return true;
>    return false;
> }
>
> Of course, if you're using any sort of half-decent database, you'll
> probably have a more elegant way to find the "next" row than this ugly
> 'for' loop; and if your table has a key consisting of more than one
> part, your loadNextRow() becomes a bit more complicated; but you get the
> idea.
>
>
> HTH...
>
> --
> Martin Janzen
> janzen at pixelmetrix dot com
>
>





More information about the AGENTPP mailing list