#include "bdbenv.h"

bdbenv::bdbenv() : dbenvp(0)
{
  opened = 0;
  cachesz = 0;
  mydbs.clear();

  openflags = DB_CREATE | DB_THREAD | DB_INIT_LOG 
    | DB_INIT_MPOOL | DB_INIT_TXN;
}

bdbenv::~bdbenv()
{
  close();
}

int bdbenv::close()
{
  if(opened)
    {
      for( unsigned i = 0; i < mydbs.size(); i++ )
        mydbs[i]->close();
      dbenvp.close(0);
      mydbs.clear();
    }
  opened = 0;
  return 0;
}

int bdbenv::removedb( std::string dbname )
{
  dbenvp.dbremove(NULL, dbname.c_str(), NULL, 0 );
  return 0;
}

int bdbenv::adddb( dbtable *t )
{
  mydbs.push_back( t );
  return 0;
}

int bdbenv::cleanlog()
{
  char **p;
#ifdef __DEBUG__
  std::cout << "removing log files\n";
#endif
  try
    {
      dbenvp.txn_checkpoint( 0, 0, 0 );
      dbenvp.log_archive( &p, DB_ARCH_REMOVE );
    }
  catch (DbException &e)
    {
      std::cout << "ERROR: " << e.what() << "\n";
    }
  return 0;
}

int bdbenv::recover( std::string d)
{
  int ret;
  close();
  dbdir = d;
#ifdef __DEBUG__
  std::cout << "opening in recovery mode: "
            << d << "\n";
#endif
  dbenvp.set_cachesize( 0, 1024*1024*512, 0 );
  dbenvp.mutex_set_max( 250000 );
#ifdef __DEBUG__
  std::cout << "opening env\n";
#endif
  ret = dbenvp.open(d.c_str(), openflags | DB_RECOVER_FATAL, 0 );
#ifdef __DEBUG__
  std::cout << "env opened: " << ret << "\n";
#endif
  return ret;
}

int bdbenv::remove( std::string d )
{
  int ret;
  ret = dbenvp.remove( d.c_str(), DB_FORCE);
  std::cout << "removed " << ret << "\n";
  return 0;
}

int bdbenv::open(std::string d)
{
  int ret;
  close();
  dbdir = d;
  std::cout << "opening with flags\n";
  printflags(); 
  if( cachesz == 0 )
    {
      dbenvp.mutex_set_max( 250000 );
      dbenvp.set_cachesize( 0, 1024*1024*512, 0 );
    }
  else
    {
      dbenvp.mutex_set_max( 1200000 );
      dbenvp.set_cachesize( cachesz, cacheszmb*1024*1024, 0 );
    }
  dbenvp.set_lg_max( 32*1024*1024 );

  //  dbenvp.log_archive(NULL, DB_ARCH_REMOVE);
#ifdef __DEBUG__
  std::cout << "opening env\n";
#endif
  try
    {
      if( (openflags & DB_INIT_LOG) != 0 )
        {
          std::cout << "setting no sync\n";
          dbenvp.set_flags( DB_AUTO_COMMIT, 1 );
          dbenvp.set_flags( DB_TXN_NOSYNC, 1 );
        }
    }
  catch( DbException &e) 
    {   
      std::cout << "DB in set flag EXCEPTION: " << e.what() << "\n";
      exit(0);  
    }
  try
    {
      ret = dbenvp.open(d.c_str(), openflags, 0 );
    }
  catch( DbException &e) 
    {   
      std::cout << d.c_str() << "\n";
      std::cout << "DB in open env EXCEPTION: " << e.what() << "\n";
      exit(0);  
    }
  // check point every 64 megabytes of data
  if( (openflags & DB_INIT_LOG) != 0 )
    {
      dbenvp.txn_checkpoint( 1024*128, 0, 0);
      dbenvp.log_archive( NULL, DB_ARCH_REMOVE );
    }
#ifdef __DEBUG__
  printflags(); 
  std::cout << "env opened: " << ret << "\n";
  unsigned int i;
  dbenvp.mutex_get_max( &i );
  std::cout << "configured with " << i << " mutexes\n";
#endif
  std::cout << "database opened\n";
  return ret;
}

DbEnv *bdbenv::envptr()
{
  return &dbenvp;
}

int bdbenv::printflags()
{
  unsigned int flags;
  dbenvp.get_flags( &flags );
  if( (flags & DB_AUTO_COMMIT) != 0 )
    std::cout << "db opened with auto commit\n";
  if( (flags & DB_DIRECT_DB) != 0 )
    std::cout << "db opened with direct db\n";
  if( (flags & DB_TXN_NOSYNC) != 0 )
    std::cout << "db opened with async transactions\n";
  if( (flags &  DB_INIT_REP ) != 0 )
    std::cout << "db opened with replication\n";
  if( (flags & DB_INIT_LOG) != 0 )
    std::cout << "db opened with log\n";
  if( (flags & DB_INIT_TXN) != 0 )
    std::cout << "db opened with txn\n";

  return 0;
}
