[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