reSIProcate/repro  9694
Classes | Public Member Functions | Private Member Functions | Static Private Member Functions | Private Attributes
repro::BerkeleyDb Class Reference

#include <BerkeleyDb.hxx>

Inheritance diagram for repro::BerkeleyDb:
Inheritance graph
[legend]
Collaboration diagram for repro::BerkeleyDb:
Collaboration graph
[legend]

List of all members.

Classes

class  TableInfo

Public Member Functions

 BerkeleyDb ()
 BerkeleyDb (const resip::Data &dbPath, const resip::Data &dbName=resip::Data::Empty)
virtual ~BerkeleyDb ()
virtual bool isSane ()

Private Member Functions

void init (const resip::Data &dbPath, const resip::Data &dbName)
virtual bool dbWriteRecord (const Table table, const resip::Data &key, const resip::Data &data)
virtual bool dbReadRecord (const Table table, const resip::Data &key, resip::Data &data) const
 return false if not found
virtual void dbEraseRecord (const Table table, const resip::Data &key, bool isSecondaryKey=false)
virtual resip::Data dbNextKey (const Table table, bool first=true)
virtual bool dbNextRecord (const Table table, const resip::Data &key, resip::Data &data, bool forUpdate, bool first=false)
virtual bool dbBeginTransaction (const Table table)
virtual bool dbCommitTransaction (const Table table)
virtual bool dbRollbackTransaction (const Table table)

Static Private Member Functions

static int getSecondaryKeyCallback (Db *db, const Dbt *pkey, const Dbt *pdata, Dbt *skey)

Private Attributes

DbEnv * mEnv
TableInfo mTableInfo [MaxTable]
bool mSane

Detailed Description

Definition at line 26 of file BerkeleyDb.hxx.


Constructor & Destructor Documentation

BerkeleyDb::BerkeleyDb ( )

Definition at line 24 of file BerkeleyDb.cxx.

{
   init(Data::Empty, Data::Empty);
}
BerkeleyDb::BerkeleyDb ( const resip::Data dbPath,
const resip::Data dbName = resip::Data::Empty 
)

Definition at line 30 of file BerkeleyDb.cxx.

{
   init(dbPath, dbName);
}
BerkeleyDb::~BerkeleyDb ( ) [virtual]

Definition at line 224 of file BerkeleyDb.cxx.

{  
   for (int i=0;i<MaxTable;i++)
   {
      if(mTableInfo[i].mSecondaryCursor)
      {
         mTableInfo[i].mSecondaryCursor->close();
         mTableInfo[i].mSecondaryCursor = 0;
      }

      if(mTableInfo[i].mCursor)
      {
         mTableInfo[i].mCursor->close();
         mTableInfo[i].mCursor = 0;
      }
      
      if(mTableInfo[i].mTransaction)
      {
         dbRollbackTransaction((Table)i);
      }

      // Secondary DB should be closed before primary
      if(mTableInfo[i].mSecondaryDb)
      {
         mTableInfo[i].mSecondaryDb->close(0);
         delete mTableInfo[i].mSecondaryDb; 
         mTableInfo[i].mSecondaryDb = 0;
      }

      if(mTableInfo[i].mDb)
      {
         mTableInfo[i].mDb->close(0);
         delete mTableInfo[i].mDb; 
         mTableInfo[i].mDb = 0;
      }
   }
   if(mEnv)
   {
      mEnv->txn_checkpoint(0, 0, 0);  // Note:  a checkpoint is run when this last is created and when it is destroyed
      delete mEnv;
   }
}

Member Function Documentation

bool BerkeleyDb::dbBeginTransaction ( const Table  table) [private, virtual]

Implements repro::AbstractDb.

Definition at line 455 of file BerkeleyDb.cxx.

{
#ifdef USE_DBENV
   // For now - we support transactions on the primary table only
   assert(mDb);
   assert(mTableInfo[table].mTransaction == 0);
   int ret = mTableInfo[table].mDb->get_env()->txn_begin(0 /* parent trans*/, &mTableInfo[table].mTransaction, 0);
   if(ret != 0)
   {
      ErrLog( <<"Could not begin transaction: " << db_strerror(ret));
      return false;
   }

   // Open new Cursors - since cursors used in a transaction must be opened and closed within the transation
   if(mTableInfo[table].mCursor)
   {
      mTableInfo[table].mCursor->close();
      mTableInfo[table].mCursor = 0;
   }

   ret = mTableInfo[table].mDb->cursor(mTableInfo[table].mTransaction, &mTableInfo[table].mCursor, 0);
   if(ret != 0)
   {
      ErrLog( <<"Could not open cursor for transaction: " << db_strerror(ret));
   }
#endif

   return true;
}
bool BerkeleyDb::dbCommitTransaction ( const Table  table) [private, virtual]

Implements repro::AbstractDb.

Definition at line 486 of file BerkeleyDb.cxx.

{
   bool success = true;
#ifdef USE_DBENV
   assert(mDb);
   assert(mTableInfo[table].mTransaction);

   // Close the cursor - since cursors used in a transaction must be opened and closed within the transation
   if(mTableInfo[table].mCursor)
   {
      mTableInfo[table].mCursor->close();
      mTableInfo[table].mCursor = 0;
   }

   int ret = mTableInfo[table].mTransaction->commit(0);
   mTableInfo[table].mTransaction = 0;
   if(ret != 0)
   {
      ErrLog( <<"Could not commit transaction: " << db_strerror(ret));
      success = false;
   }

   // Reopen a cursor for general use
   mTableInfo[table].mDb->cursor(0, &mTableInfo[table].mCursor, 0);
#endif

   return success;
}
void BerkeleyDb::dbEraseRecord ( const Table  table,
const resip::Data key,
bool  isSecondaryKey = false 
) [private, virtual]

Implements repro::AbstractDb.

Definition at line 362 of file BerkeleyDb.cxx.

{ 
   Dbt key((void*) pKey.data(), (::u_int32_t)pKey.size());

   Db* db = mTableInfo[table].mDb;
   if(isSecondaryKey && mTableInfo[table].mSecondaryDb)
   {
      db = mTableInfo[table].mSecondaryDb;
   }
   assert(db);
   db->del(mTableInfo[table].mTransaction, &key, 0);
   if(mTableInfo[table].mTransaction == 0)
   {
      // If we are in a transaction, then it will sync on commit
      mTableInfo[table].mDb->sync(0);
      if(mTableInfo[table].mSecondaryDb)
      {
         mTableInfo[table].mSecondaryDb->sync(0);
      }
   }
}
resip::Data BerkeleyDb::dbNextKey ( const Table  table,
bool  first = true 
) [private, virtual]

Implements repro::AbstractDb.

Definition at line 388 of file BerkeleyDb.cxx.

{ 
   Dbt key, data;
   int ret;
   
   assert(mTableInfo[table].mDb);
   ret = mTableInfo[table].mCursor->get(&key, &data, first ? DB_FIRST : DB_NEXT);
   if (ret == DB_NOTFOUND)
   {
      return Data::Empty;
   }
   assert(ret == 0);
   
   Data d(Data::Share, reinterpret_cast<const char*>(key.get_data()), key.get_size());
   return d;
}
bool BerkeleyDb::dbNextRecord ( const Table  table,
const resip::Data key,
resip::Data data,
bool  forUpdate,
bool  first = false 
) [private, virtual]

Implements repro::AbstractDb.

Definition at line 408 of file BerkeleyDb.cxx.

{
   Dbt dbkey((void*) key.data(), (::u_int32_t)key.size());
   Dbt dbdata;
   int ret;

   assert(mTableInfo[table].mSecondaryCursor);
   if(mTableInfo[table].mSecondaryCursor == 0)
   {
      // Iterating across multiple records with a common key is only 
      // supported on Seconday databases where duplicate keys exist
      return false;
   }

   unsigned int flags = 0;
   if(key.empty())
   {
      flags = first ? DB_FIRST : DB_NEXT;
   }
   else
   {
      flags = first ? DB_SET : DB_NEXT_DUP;
   }

#ifdef USE_DBENV
   if(forUpdate)
   {
      flags |= DB_RMW;
   }
#endif

   ret = mTableInfo[table].mSecondaryCursor->get(&dbkey, &dbdata, flags);
   if (ret == DB_NOTFOUND)
   {
      return false;
   }
   assert(ret == 0);
   data.copy(reinterpret_cast<const char*>(dbdata.get_data()), dbdata.get_size());

   return true;
}
bool BerkeleyDb::dbReadRecord ( const Table  table,
const resip::Data key,
resip::Data data 
) const [private, virtual]

return false if not found

Implements repro::AbstractDb.

Definition at line 322 of file BerkeleyDb.cxx.

{ 
   Dbt key((void*)pKey.data(), (::u_int32_t)pKey.size());
   Dbt data;
   data.set_flags(DB_DBT_MALLOC);  // required for DB_THREAD flag use

   int ret;
   
   assert(mTableInfo[table].mDb);
   ret = mTableInfo[table].mDb->get(mTableInfo[table].mTransaction, &key, &data, 0);

   if (ret == DB_NOTFOUND)
   {
      // key not found 
      if (data.get_data())
      {
         free(data.get_data());
      }
      return false;
   }
   assert(ret != DB_KEYEMPTY);
   assert(ret == 0);
   pData.copy(reinterpret_cast<const char*>(data.get_data()), data.get_size());
   if (data.get_data())
   {
      free(data.get_data());
   }
   if(pData.empty())
   {
      // this should never happen
      return false;
   }

   return true;
}
bool BerkeleyDb::dbRollbackTransaction ( const Table  table) [private, virtual]

Implements repro::AbstractDb.

Definition at line 516 of file BerkeleyDb.cxx.

{
   bool success = true;
#ifdef USE_DBENV
   assert(mDb);
   assert(mTableInfo[table].mTransaction);

   // Close the cursor - since cursors used in a transaction must be opened and closed within the transation
   if(mTableInfo[table].mCursor)
   {
      mTableInfo[table].mCursor->close();
      mTableInfo[table].mCursor = 0;
   }

   int ret = mTableInfo[table].mTransaction->abort();
   mTableInfo[table].mTransaction = 0;
   if(ret != 0)
   {
      success = false;
   }

   // Reopen a cursor for general use
   mTableInfo[table].mDb->cursor(0, &mTableInfo[table].mCursor, 0);
#endif

   return success;
}
bool BerkeleyDb::dbWriteRecord ( const Table  table,
const resip::Data key,
const resip::Data data 
) [private, virtual]

Implements repro::AbstractDb.

Definition at line 297 of file BerkeleyDb.cxx.

{
   Dbt key((void*)pKey.data(), (::u_int32_t)pKey.size());
   Dbt data((void*)pData.data(), (::u_int32_t)pData.size());
   int ret;
   
   assert(mTableInfo[table].mDb);
   ret = mTableInfo[table].mDb->put(mTableInfo[table].mTransaction, &key, &data, 0);

   if(ret == 0 && mTableInfo[table].mTransaction == 0)
   {
      // If we are in a transaction, then it will sync on commit
      mTableInfo[table].mDb->sync(0);
      if(mTableInfo[table].mSecondaryDb)
      {
         mTableInfo[table].mSecondaryDb->sync(0);
      }
   }
   return ret == 0;
}
int BerkeleyDb::getSecondaryKeyCallback ( Db *  db,
const Dbt *  pkey,
const Dbt *  pdata,
Dbt *  skey 
) [static, private]

Definition at line 269 of file BerkeleyDb.cxx.

{
   BerkeleyDb* bdb = (BerkeleyDb*)db->get_app_private();

   // Find associated table using db pointer
   Table table = MaxTable;
   for (int i=MaxTable-1; i >= 0; i--)  // search backwards, since tables at the end have the secondary indexes
   {
      if(bdb->mTableInfo[i].mSecondaryDb == db)
      {
         table = (Table)i;
         break;
      }
   }
   assert(table != MaxTable);

   Data primaryKey(Data::Share, reinterpret_cast<const char*>(pkey->get_data()), pkey->get_size());
   Data primaryData(Data::Share, reinterpret_cast<const char*>(pdata->get_data()), pdata->get_size());
   void* secondaryKey;
   unsigned int secondaryKeyLen;
   int rc = bdb->getSecondaryKey(table, primaryKey, primaryData, &secondaryKey, &secondaryKeyLen);
   skey->set_data(secondaryKey);
   skey->set_size(secondaryKeyLen);
   return rc;
}
void BerkeleyDb::init ( const resip::Data dbPath,
const resip::Data dbName 
) [private]

Definition at line 37 of file BerkeleyDb.cxx.

{ 
   Data filePath(dbPath);

   // An empty path is how you specify the current working directory as a path
   if ( !filePath.empty() )
   {
#ifdef WIN32
      filePath += '\\';
#else
      filePath += '/';
#endif
   }

   if ( dbName.empty() )
   {
      DebugLog( << "No BerkeleyDb prefix specified - using default" );
      filePath += "repro";
   }
   else
   {
      filePath += dbName;
   }

   InfoLog( << "Using BerkeleyDb prefixed with " << filePath );

   mSane = true;

   // Create Environment
   int ret;
#ifdef USE_DBENV
   mEnv = new DbEnv(DB_CXX_NO_EXCEPTIONS);
   assert(mEnv);
   ret = mEnv->open(0, DB_CREATE |     // If the env does not exist, then create it
                       DB_INIT_LOCK |  // Initialize Locking (needed for transactions)
                       DB_INIT_LOG |   // Initialize Logging (needed for transactions)
                       DB_INIT_MPOOL | // Initialize the cache (needed for transactions)
                       DB_INIT_TXN |   // Initialize transactions
                       DB_RECOVER |    // Run normal recovery
                       DB_THREAD,      // Free-thread the env handle
                       0 /* mode */);
   if(ret != 0)
   {
      ErrLog( <<"Could not open environment: " << db_strerror(ret));
      mSane = false;
      return;
   }
   mEnv->txn_checkpoint(0, 0, 0);  // Note:  a checkpoint is run when this last is created and when it is destroyed
#else
   mEnv = 0;
#endif

   bool enableTransactions = false;
   bool secondaryIndex = false;
   Data secondaryFileName;
   for (int i=0;i<MaxTable;i++)
   {
      enableTransactions = false;
      // if the line bellow seems wrong, you need to check which version 
      // of db you have - it is likely an very out of date version 
      // still trying to figure this out so email fluffy if you have 
      // problems and include your version the DB_VERSION_STRING found 
      // in your db4/db.h file. 
      Data fileName( filePath );
      switch (i)
      {
         case UserTable:
            fileName += "_user"; break;
         case RouteTable:
            fileName += "_route"; break;
         case AclTable:
            fileName += "_acl"; break;
         case ConfigTable:
            fileName += "_config"; break;
         case StaticRegTable:
            fileName += "_staticreg"; break;
         case FilterTable:
            fileName += "_filter"; break;
         case SiloTable:
            fileName += "_silo"; 
            enableTransactions = true;
            secondaryIndex = true;
            break;
         default:
            assert(0);
      }

      if(!secondaryIndex)
      {
         fileName += ".db";
      }
      else
      {
         secondaryFileName = fileName;
         fileName += ".db";
         secondaryFileName += "_idx1.db";
      }

      mTableInfo[i].mDb = new Db(mEnv, DB_CXX_NO_EXCEPTIONS);
      assert(mTableInfo[i].mDb);
      
      DebugLog( << "About to open Berkeley DB: " << fileName );
      ret = mTableInfo[i].mDb->open(0,
                         fileName.c_str(),
                         0,
                         DB_BTREE,
#ifdef USE_DBENV
                         DB_CREATE | DB_THREAD | (enableTransactions ? DB_AUTO_COMMIT : 0),
#else
                         DB_CREATE | DB_THREAD,
#endif
                         0);
      if(ret != 0)
      {
         ErrLog( <<"Could not open database " << fileName << ": " << db_strerror(ret));
         mSane = false;
         return;
      }

      // Open a cursor on the database
      ret = mTableInfo[i].mDb->cursor(0, &mTableInfo[i].mCursor, 0);
      if(ret != 0)
      {
         ErrLog( <<"Could not cursor on database " << fileName << ": " << db_strerror(ret));
         mSane = false;
         return;
      }
      assert(mTableInfo[i].mCursor);

      DebugLog( << "Opened Berkeley DB: " << fileName );


      if(secondaryIndex)
      {
         mTableInfo[i].mSecondaryDb = new Db(mEnv, DB_CXX_NO_EXCEPTIONS);
         assert(mTableInfo[i].mSecondaryDb);

         ret = mTableInfo[i].mSecondaryDb->set_flags(DB_DUP);
         if(ret!=0)
         {
            ErrLog( <<"Could not set database " << secondaryFileName << " to allow duplicates: " << db_strerror(ret));
            mSane = false;
            return;
         }
      
         DebugLog( << "About to open secondary Berkeley DB: " << secondaryFileName );
         ret = mTableInfo[i].mSecondaryDb->open(0,
                            secondaryFileName.c_str(),
                            0,
                            DB_BTREE,
#ifdef USE_DBENV
                            DB_CREATE | DB_THREAD | (enableTransactions ? DB_AUTO_COMMIT : 0),
#else
                            DB_CREATE | DB_THREAD,
#endif
                            0);
         if(ret != 0)
         {
            ErrLog( <<"Could not open secondary database " << secondaryFileName << ": " << db_strerror(ret));
            mSane = false;
            return;
         }

         // Associate Secondary Database with Primary
         mTableInfo[i].mSecondaryDb->set_app_private(this);  // retrievable from callback so we can have access to this BerkeleyDb instance
         ret = mTableInfo[i].mDb->associate(0, mTableInfo[i].mSecondaryDb, &getSecondaryKeyCallback, 0 /* flags */);
         if(ret != 0)
         {
            ErrLog( <<"Could not associate secondary database " << secondaryFileName << ": " << db_strerror(ret));
            mSane = false;
            return;
         }
         DebugLog( << "Opened secondary Berkeley DB: " << secondaryFileName );

         ret = mTableInfo[i].mSecondaryDb->cursor(0, &mTableInfo[i].mSecondaryCursor, 0);
         if(ret != 0)
         {
            ErrLog( <<"Could not secondary cursor on database " << secondaryFileName << ": " << db_strerror(ret));
            mSane = false;
            return;
         }
         assert(mTableInfo[i].mSecondaryCursor);
      }
   }
}
virtual bool repro::BerkeleyDb::isSane ( ) [inline, virtual]

Implements repro::AbstractDb.

Definition at line 34 of file BerkeleyDb.hxx.

{return mSane; }

Member Data Documentation

DbEnv* repro::BerkeleyDb::mEnv [private]

Definition at line 51 of file BerkeleyDb.hxx.

bool repro::BerkeleyDb::mSane [private]

Definition at line 54 of file BerkeleyDb.hxx.

Definition at line 52 of file BerkeleyDb.hxx.


The documentation for this class was generated from the following files: