Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

822 lines
20 KiB

/******************************************************************************
Copyright (c) 2000 Microsoft Corporation
Module Name:
Session.cpp
Abstract:
This file contains the implementation of the JetBlue::Session* classes.
Revision History:
Davide Massarenti (Dmassare) 05/17/2000
created
******************************************************************************/
#include <stdafx.h>
////////////////////////////////////////////////////////////////////////////////
JetBlue::Session::Session( /*[in]*/ SessionPool* parent ,
/*[in]*/ JET_INSTANCE inst )
{
m_parent = parent; // SessionPool* m_parent;
m_inst = inst; // JET_INSTANCE m_inst;
m_sesid = JET_sesidNil; // JET_SESID m_sesid;
// DbMap m_mapDBs;
m_dwTransactionNesting = 0; // DWORD m_dwTransactionNesting;
m_fAborted = false; // bool m_fAborted;
}
JetBlue::Session::~Session()
{
(void)Close( true );
}
////////////////////////////////////////
bool JetBlue::Session::LockDatabase ( /*[in]*/ const MPC::string& strDB, /*[in]*/ bool fReadOnly ) { return m_parent->LockDatabase ( this, strDB, fReadOnly ); }
void JetBlue::Session::UnlockDatabase ( /*[in]*/ const MPC::string& strDB ) { m_parent->UnlockDatabase ( this, strDB ); }
HRESULT JetBlue::Session::ReleaseDatabase( /*[in]*/ const MPC::string& strDB ) { return m_parent->ReleaseDatabase( strDB.c_str() ); }
////////////////////////////////////////
HRESULT JetBlue::Session::Init()
{
__HCP_FUNC_ENTRY( "JetBlue::Session::Init" );
HRESULT hr;
if(m_sesid == JET_sesidNil)
{
__MPC_EXIT_IF_JET_FAILS(hr, ::JetBeginSession( m_inst, &m_sesid, NULL, NULL ));
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
HRESULT JetBlue::Session::Close( /*[in]*/ bool fForce )
{
__HCP_FUNC_ENTRY( "JetBlue::Session::Close" );
HRESULT hr;
DbIter it;
for(it = m_mapDBs.begin(); it != m_mapDBs.end(); it++)
{
Database* db = it->second;
if(db)
{
HRESULT hr2 = db->Close( fForce ); if(!fForce) __MPC_EXIT_IF_METHOD_FAILS(hr, hr2);
delete db;
}
}
m_mapDBs.clear();
if(m_sesid != JET_sesidNil)
{
JET_ERR err = ::JetEndSession( m_sesid, 0 ); if(!fForce) __MPC_EXIT_IF_JET_FAILS(hr, err);
m_sesid = JET_sesidNil;
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
void JetBlue::Session::Release()
{
if(m_fAborted)
{
DbIter it;
for(it = m_mapDBs.begin(); it != m_mapDBs.end(); it++)
{
Database* db = it->second;
if(db)
{
db->Close( /*fForce*/true, /*fAll*/false );
}
}
__MPC_JET__MTSAFE_NORESULT(m_sesid, ::JetRollback( m_sesid, JET_bitRollbackAll ));
m_fAborted = false;
}
}
////////////////////////////////////////
HRESULT JetBlue::Session::GetDatabase( /*[in] */ LPCSTR szName ,
/*[out]*/ Database*& db ,
/*[in]*/ bool fReadOnly ,
/*[in]*/ bool fCreate ,
/*[in]*/ bool fRepair )
{
__HCP_FUNC_ENTRY( "JetBlue::Session::GetDatabase" );
HRESULT hr;
Database* dbNew = NULL;
DbIter it;
db = NULL;
it = m_mapDBs.find( szName );
if(it == m_mapDBs.end())
{
__MPC_EXIT_IF_ALLOC_FAILS(hr, dbNew, new Database( this, m_sesid, szName ));
m_mapDBs[szName] = dbNew;
db = dbNew; dbNew = NULL;
}
else
{
db = it->second;
}
__MPC_EXIT_IF_METHOD_FAILS(hr, db->Open( fReadOnly, fCreate, fRepair ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
if(dbNew) delete dbNew;
__HCP_FUNC_EXIT(hr);
}
////////////////////////////////////////
HRESULT JetBlue::Session::BeginTransaction()
{
__HCP_FUNC_ENTRY( "JetBlue::Session::BeginTransaction" );
HRESULT hr;
__MPC_EXIT_IF_JET_FAILS__MTSAFE(m_sesid, hr, ::JetBeginTransaction( m_sesid ));
m_dwTransactionNesting++;
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
HRESULT JetBlue::Session::CommitTransaction()
{
__HCP_FUNC_ENTRY( "JetBlue::Session::CommitTransaction" );
HRESULT hr;
if(m_dwTransactionNesting > 0)
{
__MPC_EXIT_IF_JET_FAILS__MTSAFE(m_sesid, hr, ::JetCommitTransaction( m_sesid, JET_bitCommitLazyFlush ));
m_dwTransactionNesting--;
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
HRESULT JetBlue::Session::RollbackTransaction()
{
__HCP_FUNC_ENTRY( "JetBlue::Session::RollbackTransaction" );
HRESULT hr;
if(m_dwTransactionNesting > 0)
{
m_fAborted = true;
__MPC_EXIT_IF_JET_FAILS__MTSAFE(m_sesid, hr, ::JetRollback( m_sesid, 0 ));
m_dwTransactionNesting--;
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
////////////////////////////////////////
JetBlue::Database* JetBlue::Session::GetDB( /*[in]*/ int iPos )
{
for(DbIter it = m_mapDBs.begin(); it != m_mapDBs.end(); it++)
{
if(iPos-- == 0) return it->second;
}
return NULL;
}
JetBlue::Database* JetBlue::Session::GetDB( LPCSTR szDB )
{
DbIter it = m_mapDBs.find( szDB );
return (it == m_mapDBs.end()) ? NULL : it->second;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
JetBlue::TransactionHandle::TransactionHandle()
{
m_sess = NULL; // Session* m_sess;
}
JetBlue::TransactionHandle::~TransactionHandle()
{
(void)Rollback();
}
HRESULT JetBlue::TransactionHandle::Begin( /*[in]*/ Session* sess )
{
__HCP_FUNC_ENTRY( "JetBlue::TransactionHandle::Begin" );
HRESULT hr;
__MPC_EXIT_IF_METHOD_FAILS(hr, Rollback());
if(sess)
{
__MPC_EXIT_IF_METHOD_FAILS(hr, sess->BeginTransaction());
m_sess = sess;
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
HRESULT JetBlue::TransactionHandle::Commit()
{
__HCP_FUNC_ENTRY( "JetBlue::TransactionHandle::Commit" );
HRESULT hr;
if(m_sess)
{
__MPC_EXIT_IF_METHOD_FAILS(hr, m_sess->CommitTransaction());
m_sess = NULL;
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
HRESULT JetBlue::TransactionHandle::Rollback()
{
__HCP_FUNC_ENTRY( "JetBlue::TransactionHandle::Rollback" );
HRESULT hr;
if(m_sess)
{
__MPC_EXIT_IF_METHOD_FAILS(hr, m_sess->RollbackTransaction());
m_sess = NULL;
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
JetBlue::SessionHandle::SessionHandle()
{
m_pool = NULL; // SessionPool* m_pool;
m_sess = NULL; // Session* m_sess;
}
JetBlue::SessionHandle::~SessionHandle()
{
Release();
}
////////////////////////////////////////
void JetBlue::SessionHandle::Release()
{
if(m_pool)
{
m_pool->ReleaseSession( m_sess );
m_pool = NULL;
}
m_sess = NULL;
}
void JetBlue::SessionHandle::Init( /*[in]*/ SessionPool* pool ,
/*[in]*/ Session* sess )
{
Release();
m_pool = pool; // SessionPool* m_pool;
m_sess = sess; // Session* m_sess;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
JetBlue::SessionPool::SessionPool()
{
m_fInitialized = false; // bool m_fInitialized;
m_inst = JET_instanceNil; // JET_INSTANCE m_inst;
// SessionList m_lstSessions;
// DbInUseList m_lstDbInUse;
m_iAllocated = 0; // int m_iAllocated;
m_iInUse = 0; // int m_iInUse;
(void)MPC::_MPC_Module.RegisterCallback( this, (void (JetBlue::SessionPool::*)())Shutdown );
}
JetBlue::SessionPool::~SessionPool()
{
MPC::_MPC_Module.UnregisterCallback( this );
Shutdown();
}
////////////////////
JetBlue::SessionPool* JetBlue::SessionPool::s_GLOBAL( NULL );
HRESULT JetBlue::SessionPool::InitializeSystem()
{
if(s_GLOBAL == NULL)
{
s_GLOBAL = new JetBlue::SessionPool;
}
return s_GLOBAL ? S_OK : E_OUTOFMEMORY;
}
void JetBlue::SessionPool::FinalizeSystem()
{
if(s_GLOBAL)
{
delete s_GLOBAL; s_GLOBAL = NULL;
}
}
////////////////////
void JetBlue::SessionPool::Shutdown()
{
(void)Close( true );
}
////////////////////////////////////////
void JetBlue::SessionPool::ReleaseSession( /*[in]*/ Session* sess )
{
MPC::SmartLock<_ThreadModel> lock( this );
SessionIter it;
for(it = m_lstSessions.begin(); it != m_lstSessions.end(); it++)
{
if(it->m_sess == sess)
{
sess->Release();
it->m_fInUse = false; m_iInUse--;
if(m_iAllocated - m_iInUse > l_MaxFreePoolSize)
{
m_lstSessions.erase( it ); m_iAllocated--;
}
break;
}
}
}
bool JetBlue::SessionPool::LockDatabase( /*[in]*/ Session* sess, /*[in]*/ const MPC::string& strDB, /*[in]*/ bool fReadOnly )
{
MPC::SmartLock<_ThreadModel> lock( this );
DbInUseIter it;
bool fLockedForRead = false;
bool fLockedForWrite = false;
for(it = m_lstDbInUse.begin(); it != m_lstDbInUse.end(); it++)
{
DatabaseInUse& db = *it;
if(db.m_strDB == strDB)
{
if(db.m_fReadOnly) fLockedForRead = true;
else fLockedForWrite = true;
}
}
if(fLockedForRead && !fReadOnly) return false; // Someone has the database opened in read-only mode...
if(fLockedForWrite ) fReadOnly = false; // The database is already opened for writing, so do the same.
for(it = m_lstDbInUse.begin(); it != m_lstDbInUse.end(); it++)
{
DatabaseInUse& db = *it;
if(db.m_sess == sess &&
db.m_strDB == strDB )
{
return true; // Already locked.
}
}
//
// Create new entry.
//
it = m_lstDbInUse.insert( m_lstDbInUse.end() );
it->m_sess = sess;
it->m_strDB = strDB;
it->m_fReadOnly = fReadOnly;
return true;
}
void JetBlue::SessionPool::UnlockDatabase( /*[in]*/ Session* sess, /*[in]*/ const MPC::string& strDB )
{
MPC::SmartLock<_ThreadModel> lock( this );
DbInUseIter it = m_lstDbInUse.begin();
bool fInUse = false;
bool fSeen = false;
while(it != m_lstDbInUse.end())
{
DbInUseIter it2 = it++; // Copy iterator and move to the next one. This protects us from node removal.
DatabaseInUse& db = *it2;
if(db.m_strDB == strDB)
{
fSeen = true;
if(db.m_sess == sess)
{
m_lstDbInUse.erase( it2 );
}
else
{
fInUse = true;
}
}
}
//
// Last session to release the database, detach from it.
//
if(fSeen && !fInUse)
{
(void)::JetDetachDatabase( sess->GetSESID(), strDB.c_str() );
}
}
HRESULT JetBlue::SessionPool::ReleaseDatabase( /*[in]*/ LPCSTR szDB )
{
__HCP_FUNC_ENTRY( "JetBlue::SessionPool::ReleaseDatabase" );
HRESULT hr;
MPC::SmartLock<_ThreadModel> lock ( this );
MPC::string strDB( szDB );
DbInUseIter it;
for(it = m_lstDbInUse.begin(); it != m_lstDbInUse.end();)
{
DatabaseInUse& db = *it;
if(db.m_strDB == strDB)
{
SessionIter it2;
for(it2 = m_lstSessions.begin(); it2 != m_lstSessions.end(); it2++)
{
if(it2->m_sess == db.m_sess) break;
}
if(it2 != m_lstSessions.end())
{
if(it2->m_fInUse)
{
__MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_BUSY);
}
m_lstSessions.erase( it2 ); m_iAllocated--;
//
// The list of databases in use has been changed by the delete operator.
//
it = m_lstDbInUse.begin(); continue;
}
}
it++;
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
////////////////////////////////////////
HRESULT JetBlue::SessionPool::Init( /*[in]*/ LPCWSTR szLogs )
{
__HCP_FUNC_ENTRY( "JetBlue::SessionPool::Init" );
USES_CONVERSION;
HRESULT hr;
MPC::SmartLock<_ThreadModel> lock( this );
if(m_fInitialized == false)
{
static const JET_SETSYSPARAM sConfig_Normal[] =
{
//unsigned long paramid , ULONG_PTR lParam, const char *sz, JET_ERR err
#ifdef DEBUG
{ JET_paramAssertAction , JET_AssertMsgBox, NULL , JET_errSuccess },
#endif
{ JET_paramSystemPath , 0 , (LPSTR)-1 , JET_errSuccess },
{ JET_paramTempPath , 0 , (LPSTR)-1 , JET_errSuccess },
{ JET_paramLogFilePath , 0 , (LPSTR)-1 , JET_errSuccess },
{ JET_paramBaseName , 0 , "edb" , JET_errSuccess },
{ JET_paramEventSource , 0 , "HelpSvc.exe" , JET_errSuccess },
{ JET_paramNoInformationEvent, 1 , NULL , JET_errSuccess },
{ JET_paramGlobalMinVerPages , 1 , NULL , JET_errSuccess },
{ JET_paramMaxVerPages , 1024 , NULL , JET_errSuccess },
{ JET_paramCacheSizeMax , 1024 , NULL , JET_errSuccess },
//// { JET_paramLogFileSize , 128 , NULL , JET_errSuccess },
//// { JET_paramCircularLog , 1 , NULL , JET_errSuccess },
{ -1 }
};
static const JET_SETSYSPARAM sConfig_LargeSet[] =
{
//unsigned long paramid , ULONG_PTR lParam, const char *sz, JET_ERR err
#ifdef DEBUG
{ JET_paramAssertAction , JET_AssertMsgBox, NULL , JET_errSuccess },
#endif
{ JET_paramSystemPath , 0 , (LPSTR)-1 , JET_errSuccess },
{ JET_paramTempPath , 0 , (LPSTR)-1 , JET_errSuccess },
{ JET_paramLogFilePath , 0 , (LPSTR)-1 , JET_errSuccess },
{ JET_paramBaseName , 0 , "edb" , JET_errSuccess },
{ JET_paramEventSource , 0 , "HelpSvc.exe" , JET_errSuccess },
{ JET_paramNoInformationEvent, 1 , NULL , JET_errSuccess },
{ JET_paramGlobalMinVerPages , 64 , NULL , JET_errSuccess },
{ JET_paramMaxVerPages , 2048 , NULL , JET_errSuccess },
{ JET_paramCacheSizeMax , 4096 , NULL , JET_errSuccess },
//// { JET_paramLogFileSize , 1024 , NULL , JET_errSuccess },
//// { JET_paramCircularLog , 0 , NULL , JET_errSuccess },
{ -1 }
};
////////////////////
MPC::wstring strDir;
LPCSTR szDirAnsi;
const JET_SETSYSPARAM* pParam;
JET_ERR err;
if(szLogs == NULL)
{
szLogs = HC_ROOT_HELPSVC_CONFIG L"\\CheckPoint\\";
pParam = sConfig_Normal;
}
else
{
pParam = sConfig_LargeSet;
}
MPC::SubstituteEnvVariables( strDir = szLogs ); szDirAnsi = W2A( strDir.c_str() );
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MakeDir( strDir ));
::JetSetSystemParameter( &m_inst, 0, JET_paramRecovery, 0, "off" );
while(pParam->paramid != -1)
{
JET_SETSYSPARAM param = *pParam++;
JET_ERR err;
if(param.sz == (LPSTR)-1)
{
param.sz = szDirAnsi;
}
err = ::JetSetSystemParameter( &m_inst, 0, param.paramid, param.lParam, param.sz );
if(err == JET_errInvalidParameter) continue; // Ignore version problems.
__MPC_EXIT_IF_JET_FAILS(hr, err);
}
err = ::JetInit( &m_inst );
//
// If it's a log problem, delete the log files and retry.
//
if(err >= JET_errSoftRecoveryOnSnapshot &&
err <= JET_errInvalidLoggedOperation )
{
MPC::FileSystemObject fso( strDir.c_str() );
__MPC_EXIT_IF_METHOD_FAILS(hr, fso.DeleteChildren( true, false ));
err = ::JetInit( &m_inst );
}
__MPC_EXIT_IF_JET_FAILS(hr, err);
m_fInitialized = true;
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
HRESULT JetBlue::SessionPool::Close( /*[in]*/ bool fForce )
{
__HCP_FUNC_ENTRY( "JetBlue::SessionPool::Close" );
HRESULT hr;
MPC::SmartLock<_ThreadModel> lock( this );
while(m_lstSessions.size() > 0)
{
SessionState& ss = m_lstSessions.front();
if(ss.m_sess)
{
HRESULT hr2 = ss.m_sess->Close( fForce ); if(!fForce) __MPC_EXIT_IF_JET_FAILS(hr, hr2);
}
m_lstSessions.pop_front();
}
if(m_fInitialized)
{
JET_ERR err = ::JetTerm2( m_inst, JET_bitTermComplete ); if(!fForce) __MPC_EXIT_IF_JET_FAILS(hr, err);
m_inst = JET_instanceNil;
m_fInitialized = false;
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
////////////////////////////////////////////////////////////////////////////////
HRESULT JetBlue::SessionPool::GetSession( /*[out]*/ SessionHandle& handle ,
/*[in]*/ DWORD dwTimeout )
{
__HCP_FUNC_ENTRY( "JetBlue::SessionPool::GetSession" );
HRESULT hr;
SessionIter it;
Session* sess = NULL;
MPC::SmartLock<_ThreadModel> lock( this );
handle.Release();
__MPC_EXIT_IF_METHOD_FAILS(hr, Init());
while(1)
{
if(m_iAllocated > m_iInUse)
{
//
// Look for free session.
//
for(it = m_lstSessions.begin(); it != m_lstSessions.end(); it++)
{
if(it->m_fInUse == false)
{
it->m_fInUse = true; m_iInUse++;
handle.Init( this, it->m_sess );
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
}
}
}
//
// No free session, but still below maximum number of sessions, so let's create a new one.
//
if(m_iAllocated < l_MaxPoolSize)
{
__MPC_EXIT_IF_ALLOC_FAILS(hr, sess, new Session( this, m_inst ));
__MPC_EXIT_IF_METHOD_FAILS(hr, sess->Init());
it = m_lstSessions.insert( m_lstSessions.end() ); m_iAllocated++;
it->m_sess = sess; sess = NULL;
it->m_fInUse = true; m_iInUse++;
handle.Init( this, it->m_sess );
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
}
//
// Out of resources, wait for other threads to release them...
//
if(dwTimeout == 0)
{
__MPC_SET_ERROR_AND_EXIT(hr, ERROR_NO_SYSTEM_RESOURCES);
}
lock = NULL;
::Sleep( 100 );
if(dwTimeout < 100) dwTimeout = 0;
else dwTimeout -= 100;
lock = this;
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
if(sess) delete sess;
__HCP_FUNC_EXIT(hr);
}