Listing 2
class IDbEnvConfigPolicy
{
protected:
// Constructor is protected because this is a base-class for a singleton.
// Constructor takes the most important config data as arguments.
// All others parameters are changed via optional 'set' methods.
IDbEnvConfigPolicy( const std::string & sHomeDirectoryName, size_t
uSizeOfMemoryCache );
public:
virtual ~IDbEnvConfigPolicy();
// CDatabaseEnvironment calls these query methods at appropriate time.
inline std::string GetHomeDirectoryName() const;
inline size_t GetSizeOfMemoryCache() const;
// Derived classes can override all these to change defaults.
virtual std::string GetDatabaseDirectoryName() const;
virtual std::string GetTransactionLogsDirectoryName() const;
virtual std::string GetBackingFilesDirectoryName() const;
virtual u_int32_t GetDbEnvConstructionFlags() const;
// The base-class version of this method applies all of the parameters
// captured here.
// Derived classes may override if necessary; also call base-class version
// if desired.
virtual void ConfigureDbEnvBeforeOpen( DbEnv * pDbEnv );
virtual u_int32_t GetDbEnvOpenFlags() const;
virtual uint GetMaxNumLockObjects() const;
virtual uint GetMaxNumLocks() const;
virtual size_t GetMaxSizeOfTransactionLogFile() const;
virtual u_int32_t GetAutoDeadlockResolvePolicy() const;
virtual void SetLogOutput( ILogFunctor * pLogFunctor );
// ... add more config parameter accessors as neeeded
// The database wrapper uses this to log errors during operation.
virtual void Log( const std::string & sLog );
private:
std::string m_sHomeDirectoryName;
size_t m_uSizeOfMemoryCache;
ILogFunctor * m_pLogFunctor;
// Disable copying and assignment
IDbEnvConfigPolicy( const IDbEnvConfigPolicy & );
IDbEnvConfigPolicy & operator=( const IDbEnvConfigPolicy & );
};
typedef CThreadSafeCountedPtr< IDbEnvConfigPolicy > tsrcpDbEnvConfigPolicy_t;
// Base class for type-safe DbEnv wrapper singletons (declared immediately
// after). This enforces calling DbEnv::close() when the database is
// destroyed.
class IDatabaseEnvironment
{
public:
virtual ~IDatabaseEnvironment();
inline tsrcpDbEnvConfigPolicy_t GetConfigPolicy() const;
// Get a new Db handle in this environment.
inline std::auto_ptr< Db > NewDb();
protected:
// Constructor is protected as this is a base class for a singleton.
explicit IDatabaseEnvironment( tsrcpDbEnvConfigPolicy_t
tsrcpDbEnvConfigPolicy );
// Keep a reference open to the config-policy singleton (we need it to
// handle logging)
tsrcpDbEnvConfigPolicy_t m_tsrcpDbEnvConfigPolicy;
std::auto_ptr< CWin32Mutex > m_apRunRecoveryProcessMutex;
// Hold DbEnv object by a ptr so wrapper ctor can convert any DbException
// that the DbEnv ctor throws (on compilers without support for
// function-try blocks)
std::auto_ptr< DbEnv > m_apDbEnv;
private:
// Disable copying and assignment
IDatabaseEnvironment( const IDatabaseEnvironment & );
IDatabaseEnvironment & operator=( const IDatabaseEnvironment & );
};
typedef CThreadSafeCountedPtr< IDatabaseEnvironment > tsrcpDbEnvBase_t;
// Berkeley DbEnv wrapper (singleton).
template< class TConfigPolicy >
class CDatabaseEnvironment : public IDatabaseEnvironment
{
public:
// The individual databases may use the DbEnv::ConfigPolicy::Log() method.
typedef TConfigPolicy ConfigPolicy_t;
// Thread-safe reference counted ptr.
typedef CThreadSafeCountedPtr< CDatabaseEnvironment<TConfigPolicy> >
tsrcpDbEnv_t;
// Singleton accessor.
// This takes a command; whether to return a new reference (as expected)
// or actually relinquish the one we have. This is to allow the
// application to release all references (and so run the destructor)
// without closing down completely.
enum EInstanceCommand{ eReturnNewRef, eRelinquishInstance };
static tsrcpDbEnv_t Instance( EInstanceCommand eInstanceCommand =
eReturnNewRef );
private:
// Only access is via Instance()
CDatabaseEnvironment();
// Disable copying and assignment
CDatabaseEnvironment( const CDatabaseEnvironment & );
CDatabaseEnvironment & operator=( const CDatabaseEnvironment & );
};
// Berkeley DB wrapper (singleton).
// This enforces calling Db::close() when the database is destroyed.
template< class TSerializableKey, class TSerializableRecord, class
TConfigPolicy >
class CDatabase
{
public:
typedef TConfigPolicy ConfigPolicy_t;
typedef TSerializableKey SerializableKey_t;
typedef TSerializableRecord SerializableRecord_t;
// The TConfigPolicy class specifies the type of the DbEnv we must use.
typedef TConfigPolicy::DbEnv_t DbEnv_t;
typedef CTransaction< DbEnv_t > Transaction_t;
typedef DbEnv_t::tsrcpDbEnv_t tsrcpDbEnv_t;
typedef CThreadSafeCountedPtr< CDatabase<TSerializableKey,
TSerializableRecord,TConfigPolicy> > tsrcpDb_t;
// Singleton accessor.
enum EInstanceCommand{ eReturnNewRef, eRelinquishInstance };
static tsrcpDb_t Instance( EInstanceCommand eInstanceCommand =
eReturnNewRef );
~CDatabase();
// Access functions
enum EOverwriteMode{ eAllowOverwrites = 0, eDisallowOverwrites =
DB_NOOVERWRITE };
enum EGetLockMode{ eReadOnly = 0, eReadModifyWrite = DB_RMW ;
void SerializeAndStoreRecord
(
const TSerializableKey & Key,
const TSerializableRecord & Record,
EOverwriteMode eOverwriteMode,
Transaction_t * pOptionalTransaction = 0
);
TSerializableRecord GetRecordBelongingToKey
(
const TSerializableKey & Key,
Transaction_t * pOptionalTransaction = 0,
EGetLockMode eGetLockMode = eReadOnly
);
void DeleteRecordBelongingToKey
(
const TSerializableKey & Key,
Transaction_t * pOptionalTransaction = 0
);
private:
// Disallow public construction; access is via Instance() method (singleton).
CDatabase();
// We store a ref-counted ptr to the DB environment to hold it open while
// DB is open.
tsrcpDbEnv_t m_tsrcpDbEnv;
// This object owns the Berkeley API 'Db' object returned by
// DbEnvWrapper->NewDb().
std::auto_ptr< Db > m_apDb;
// Disable copying and assignment.
CDatabase( const CDatabase & );
CDatabase & operator=( const CDatabase & );
};
// Cursor wrapper
template< class TDatabase >
class CCursor
{
public:
typedef TDatabase::tsrcpDb_t tsrcpDb_t;
typedef TDatabase::Transaction_t Transaction_t;
typedef TDatabase::SerializableKey_t SerializableKey_t;
typedef TDatabase::SerializableRecord_t SerializableRecord_t;
// When constructed, the cursor has no defined position in the DB.
// Its position is determined by the access functions below.
inline explicit CCursor( Transaction_t * pOptionalTransaction = 0 );
inline void Close();
inline ~CCursor();
// Copy constructor uses dup() to get a duplicate cursor at the same
// position, sharing the same locks.
inline CCursor( const CCursor< TDatabase > & other );
// Database access methods (similar to Berkeley DBWrapper functions with
// same names). get/put via cursor have a lot of modes for managing
// multiple records with the same key. We have no need to support that yet.
void SerializeAndOverwriteCurrentRecord( const SerializableRecord_t & Record );
enum EGetLockMode{ eReadOnly = 0, eReadModifyWrite = DB_RMW };
SerializableRecord_t MoveToKeyAndGetRecord
(
const SerializableKey_t & Key,
EGetLockMode eGetLockMode = eReadOnly
);
enum ESetCursorPosition { eFirstRecord, eLastRecord, eCurrentRecord,
eNextRecord, ePreviousRecord };
SerializableRecord_t MoveToPositionAndGetKeyAndRecord
(
ESetCursorPosition eSetCursorPosition,
SerializableKey_t * pOptionalReceiveCurrentKey = 0,
EGetLockMode eGetLockMode = eReadOnly
);
void DeleteCurrentRecord();
private:
tsrcpDb_t m_tsrcpDb;
Transaction_t * m_pOptionalTransaction;
Dbc * m_pDbc;
// Disable assignment. Copying is allowed but assignment is not needed.
CCursor & operator=( const CCursor & );
// Disable array new and delete.
static void * operator new[]( size_t nSize );
static void operator delete[]( void *pArray );
};