mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 04:43:03 +01:00
Shared page cache implementation
This commit is contained in:
parent
62a80a1aa6
commit
fef1f49c94
@ -660,11 +660,11 @@
|
||||
# The value is taken from a bit map in which each bit represents a CPU.
|
||||
# Thus, to use only the first processor, the value is 1. To use both
|
||||
# CPU 1 and CPU 2, the value is 3. To use CPU 2 and CPU 3, the value
|
||||
# is 6. The default value is 1.
|
||||
# is 6. The default value is 0 - no affinity will be set.
|
||||
#
|
||||
# Type: integer
|
||||
#
|
||||
#CpuAffinityMask = 1
|
||||
#CpuAffinityMask = 0
|
||||
|
||||
|
||||
# ----------------------------
|
||||
@ -838,3 +838,16 @@
|
||||
# 16 16777216 320 335544320 896 939524096
|
||||
# 32 33554432 384 402653184 1024 1073741824
|
||||
#
|
||||
|
||||
# Type: boolean
|
||||
#SharedCache = true
|
||||
|
||||
# Type: boolean
|
||||
#SharedDatabase = false
|
||||
|
||||
|
||||
# SharedCache SharedDatabase Mode
|
||||
# false false Classic with exlusive access // single attachment only ?
|
||||
# false true Classic with shared access // traditional CS\SC
|
||||
# true false Super with exlusive access // traditional SS
|
||||
# true true Super with shared access //
|
||||
|
@ -173,6 +173,11 @@ public:
|
||||
syncObject = obj;
|
||||
}
|
||||
|
||||
SyncType getState() const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
protected:
|
||||
SyncType state;
|
||||
SyncType request;
|
||||
@ -199,27 +204,28 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class SyncUnlockGuard : public Sync
|
||||
class SyncUnlockGuard
|
||||
{
|
||||
public:
|
||||
SyncUnlockGuard(SyncObject* obj, const char* fromWhere)
|
||||
: Sync(obj, fromWhere)
|
||||
SyncUnlockGuard(Sync& _sync) :
|
||||
sync(_sync)
|
||||
{
|
||||
oldState = state;
|
||||
oldState = sync.getState();
|
||||
|
||||
fb_assert(oldState != SYNC_NONE);
|
||||
if (oldState != SYNC_NONE)
|
||||
unlock();
|
||||
sync.unlock();
|
||||
}
|
||||
|
||||
~SyncUnlockGuard()
|
||||
{
|
||||
if (oldState != SYNC_NONE)
|
||||
lock(oldState);
|
||||
sync.lock(oldState);
|
||||
}
|
||||
|
||||
private:
|
||||
SyncType oldState;
|
||||
Sync& sync;
|
||||
};
|
||||
|
||||
} // namespace Firebird
|
||||
|
@ -378,6 +378,49 @@ private:
|
||||
Mutex* lock;
|
||||
};
|
||||
|
||||
class MutexUnlockGuard
|
||||
{
|
||||
public:
|
||||
explicit MutexUnlockGuard(Mutex &aLock)
|
||||
: lock(&aLock)
|
||||
{
|
||||
try {
|
||||
lock->leave();
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
DtorException::devHalt();
|
||||
}
|
||||
}
|
||||
|
||||
~MutexUnlockGuard()
|
||||
{
|
||||
lock->enter();
|
||||
}
|
||||
|
||||
private:
|
||||
// Forbid copying
|
||||
MutexUnlockGuard(const MutexUnlockGuard&);
|
||||
MutexUnlockGuard& operator=(const MutexUnlockGuard&);
|
||||
|
||||
Mutex* lock;
|
||||
};
|
||||
|
||||
|
||||
class MutexCheckoutGuard
|
||||
{
|
||||
public:
|
||||
MutexCheckoutGuard(Mutex& mtxCout, Mutex& mtxLock) :
|
||||
unlock(mtxCout),
|
||||
lock(mtxLock)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
MutexUnlockGuard unlock;
|
||||
MutexLockGuard lock;
|
||||
};
|
||||
|
||||
} //namespace Firebird
|
||||
|
||||
#endif // CLASSES_LOCKS_H
|
||||
|
@ -115,7 +115,7 @@ const Config::ConfigEntry Config::entries[MAX_CONFIG_KEY] =
|
||||
{TYPE_INTEGER, "TempCacheLimit", (ConfigValue) -1}, // bytes
|
||||
{TYPE_BOOLEAN, "RemoteFileOpenAbility", (ConfigValue) false},
|
||||
{TYPE_INTEGER, "GuardianOption", (ConfigValue) 1},
|
||||
{TYPE_INTEGER, "CpuAffinityMask", (ConfigValue) 1},
|
||||
{TYPE_INTEGER, "CpuAffinityMask", (ConfigValue) 0},
|
||||
{TYPE_INTEGER, "TcpRemoteBufferSize", (ConfigValue) 8192}, // bytes
|
||||
{TYPE_BOOLEAN, "TcpNoNagle", (ConfigValue) true},
|
||||
{TYPE_INTEGER, "DefaultDbCachePages", (ConfigValue) -1}, // pages
|
||||
@ -171,7 +171,9 @@ const Config::ConfigEntry Config::entries[MAX_CONFIG_KEY] =
|
||||
{TYPE_STRING, "AuthClient", (ConfigValue) "Legacy_Auth, Win_Sspi"},
|
||||
{TYPE_STRING, "UserManager", (ConfigValue) "Legacy_Auth"},
|
||||
{TYPE_STRING, "TracePlugin", (ConfigValue) "fbtrace"},
|
||||
{TYPE_STRING, "SecurityDatabase", (ConfigValue) "$(root)/security3.fdb"} // security database name
|
||||
{TYPE_STRING, "SecurityDatabase", (ConfigValue) "$(root)/security3.fdb"}, // security database name
|
||||
{TYPE_BOOLEAN, "SharedCache", (ConfigValue) true},
|
||||
{TYPE_BOOLEAN, "SharedDatabase", (ConfigValue) false}
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
@ -668,20 +670,12 @@ int Config::getMaxUserTraceLogSize()
|
||||
|
||||
bool Config::getSharedCache()
|
||||
{
|
||||
#ifdef SUPERSERVER
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
return (bool) getDefaultConfig()->values[KEY_SHARED_CACHE];
|
||||
}
|
||||
|
||||
bool Config::getSharedDatabase()
|
||||
{
|
||||
#ifdef SUPERSERVER
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
return (bool) getDefaultConfig()->values[KEY_SHARED_DATABASE];
|
||||
}
|
||||
|
||||
bool Config::getMultiClientServer()
|
||||
|
@ -135,6 +135,8 @@ public:
|
||||
KEY_PLUG_AUTH_MANAGE,
|
||||
KEY_PLUG_TRACE,
|
||||
KEY_SECURITY_DATABASE,
|
||||
KEY_SHARED_CACHE,
|
||||
KEY_SHARED_DATABASE,
|
||||
MAX_CONFIG_KEY // keep it last
|
||||
};
|
||||
|
||||
|
@ -1334,13 +1334,9 @@ int ISC_event_init(event_t* event)
|
||||
*
|
||||
**************************************/
|
||||
|
||||
#ifdef SUPERSERVER
|
||||
event->event_id = 0;
|
||||
#else
|
||||
static int idCounter = 0; // Should it be AtomicCounter? AP-2008
|
||||
static AtomicCounter idCounter;
|
||||
|
||||
event->event_id = ++idCounter;
|
||||
#endif
|
||||
|
||||
event->event_pid = process_id = getpid();
|
||||
event->event_count = 0;
|
||||
@ -2745,16 +2741,12 @@ static inline BOOL switchToThread()
|
||||
BOOL res = FALSE;
|
||||
if (fnSwitchToThread)
|
||||
{
|
||||
#if !defined SUPERSERVER
|
||||
const HANDLE hThread = GetCurrentThread();
|
||||
SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
|
||||
#endif
|
||||
|
||||
res = (*fnSwitchToThread)();
|
||||
|
||||
#if !defined SUPERSERVER
|
||||
SetThreadPriority(hThread, THREAD_PRIORITY_NORMAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -322,7 +322,7 @@ void AggNode::aggInit(thread_db* /*tdbb*/, jrd_req* request) const
|
||||
asbImpure->iasb_sort = NULL;
|
||||
|
||||
asbImpure->iasb_sort = FB_NEW(request->req_sorts.getPool()) Sort(
|
||||
database, &request->req_sorts, asb->length,
|
||||
request->req_attachment, &request->req_sorts, asb->length,
|
||||
asb->keyItems.getCount(), 1, asb->keyItems.begin(),
|
||||
RecordSource::rejectDuplicate, 0);
|
||||
}
|
||||
|
@ -1381,10 +1381,9 @@ static dsql_dbb* init(thread_db* tdbb, Jrd::Attachment* attachment)
|
||||
if (attachment->att_dsql_instance)
|
||||
return attachment->att_dsql_instance;
|
||||
|
||||
MemoryPool& pool = *attachment->att_database->createPool();
|
||||
MemoryPool& pool = *attachment->createPool();
|
||||
dsql_dbb* const database = FB_NEW(pool) dsql_dbb(pool);
|
||||
database->dbb_attachment = attachment;
|
||||
database->dbb_database = attachment->att_database;
|
||||
attachment->att_dsql_instance = database;
|
||||
|
||||
INI_init_dsql(tdbb, database);
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include "../common/common.h"
|
||||
#include "../jrd/RuntimeStatistics.h"
|
||||
#include "../jrd/val.h" // Get rid of duplicated FUN_T enum.
|
||||
#include "../jrd/Database.h"
|
||||
#include "../jrd/Attachment.h"
|
||||
#include "../dsql/BlrWriter.h"
|
||||
#include "../common/classes/array.h"
|
||||
#include "../common/classes/GenericMap.h"
|
||||
@ -146,7 +146,6 @@ public:
|
||||
Firebird::string, class dsql_req*> > > dbb_cursors; // known cursors in database
|
||||
|
||||
MemoryPool& dbb_pool; // The current pool for the dbb
|
||||
Database* dbb_database;
|
||||
Attachment* dbb_attachment;
|
||||
dsql_str* dbb_dfl_charset;
|
||||
bool dbb_no_charset;
|
||||
@ -170,12 +169,12 @@ public:
|
||||
|
||||
MemoryPool* createPool()
|
||||
{
|
||||
return dbb_database->createPool();
|
||||
return dbb_attachment->createPool();
|
||||
}
|
||||
|
||||
void deletePool(MemoryPool* pool)
|
||||
{
|
||||
dbb_database->deletePool(pool);
|
||||
dbb_attachment->deletePool(pool);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "firebird.h"
|
||||
#include "../jrd/Attachment.h"
|
||||
#include "../jrd/Database.h"
|
||||
#include "../jrd/Function.h"
|
||||
#include "../jrd/nbak.h"
|
||||
#include "../jrd/trace/TraceManager.h"
|
||||
#include "../jrd/PreparedStatement.h"
|
||||
@ -95,6 +96,29 @@ void Jrd::Attachment::destroy(Attachment* const attachment)
|
||||
}
|
||||
|
||||
|
||||
MemoryPool* Jrd::Attachment::createPool()
|
||||
{
|
||||
MemoryPool* const pool = MemoryPool::createPool(att_pool, att_memory_stats);
|
||||
att_pools.add(pool);
|
||||
return pool;
|
||||
}
|
||||
|
||||
|
||||
void Jrd::Attachment::deletePool(MemoryPool* pool)
|
||||
{
|
||||
if (pool)
|
||||
{
|
||||
size_t pos;
|
||||
if (att_pools.find(pool, pos))
|
||||
{
|
||||
att_pools.remove(pos);
|
||||
}
|
||||
|
||||
MemoryPool::deletePool(pool);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Jrd::Attachment::backupStateWriteLock(thread_db* tdbb, SSHORT wait)
|
||||
{
|
||||
if (att_backup_state_counter++)
|
||||
@ -157,15 +181,29 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb)
|
||||
att_ext_call_depth(0),
|
||||
att_trace_manager(FB_NEW(*att_pool) TraceManager(this)),
|
||||
att_interface(NULL),
|
||||
att_public_interface(NULL)
|
||||
att_public_interface(NULL),
|
||||
att_functions(*pool),
|
||||
att_internal(*pool),
|
||||
att_dyn_req(*pool),
|
||||
att_charsets(*pool),
|
||||
att_charset_ids(*pool),
|
||||
att_pools(*pool)
|
||||
{
|
||||
att_internal.grow(irq_MAX);
|
||||
att_dyn_req.grow(drq_MAX);
|
||||
}
|
||||
|
||||
|
||||
Jrd::Attachment::~Attachment()
|
||||
{
|
||||
destroyIntlObjects();
|
||||
delete att_trace_manager;
|
||||
|
||||
while (att_pools.getCount())
|
||||
{
|
||||
deletePool(att_pools.pop());
|
||||
}
|
||||
|
||||
// For normal attachments that happens in release_attachment(),
|
||||
// but for special ones like GC should be done also in dtor -
|
||||
// they do not (and should not) call release_attachment().
|
||||
@ -326,6 +364,12 @@ void Jrd::Attachment::detachLocksFromAttachment()
|
||||
* block doesn't get dereferenced after it is released
|
||||
*
|
||||
**************************************/
|
||||
if (!att_long_locks)
|
||||
return;
|
||||
|
||||
Sync lckSync(&att_database->dbb_lck_sync, "Attachment::detachLocksFromAttachment");
|
||||
lckSync.lock(SYNC_EXCLUSIVE);
|
||||
|
||||
Lock* long_lock = att_long_locks;
|
||||
while (long_lock)
|
||||
{
|
||||
@ -337,3 +381,134 @@ void Jrd::Attachment::detachLocksFromAttachment()
|
||||
}
|
||||
att_long_locks = NULL;
|
||||
}
|
||||
|
||||
// Find an inactive incarnation of a system request. If necessary, clone it.
|
||||
jrd_req* Jrd::Attachment::findSystemRequest(thread_db* tdbb, USHORT id, USHORT which)
|
||||
{
|
||||
static const int MAX_RECURSION = 100;
|
||||
|
||||
// If the request hasn't been compiled or isn't active, there're nothing to do.
|
||||
|
||||
//Database::CheckoutLockGuard guard(this, dbb_cmp_clone_mutex);
|
||||
|
||||
fb_assert(which == IRQ_REQUESTS || which == DYN_REQUESTS);
|
||||
|
||||
JrdStatement* statement = (which == IRQ_REQUESTS ? att_internal[id] : att_dyn_req[id]);
|
||||
|
||||
if (!statement)
|
||||
return NULL;
|
||||
|
||||
// Look for requests until we find one that is available.
|
||||
|
||||
for (int n = 0;; ++n)
|
||||
{
|
||||
if (n > MAX_RECURSION)
|
||||
{
|
||||
ERR_post(Arg::Gds(isc_no_meta_update) <<
|
||||
Arg::Gds(isc_req_depth_exceeded) << Arg::Num(MAX_RECURSION));
|
||||
// Msg363 "request depth exceeded. (Recursive definition?)"
|
||||
}
|
||||
|
||||
jrd_req* clone = statement->getRequest(tdbb, n);
|
||||
|
||||
if (!(clone->req_flags & (req_active | req_reserved)))
|
||||
{
|
||||
clone->req_flags |= req_reserved;
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Jrd::Attachment::shutdown(thread_db* tdbb)
|
||||
{
|
||||
// go through relations and indices and release
|
||||
// all existence locks that might have been taken
|
||||
|
||||
vec<jrd_rel*>* rvector = att_relations;
|
||||
if (rvector)
|
||||
{
|
||||
vec<jrd_rel*>::iterator ptr, end;
|
||||
for (ptr = rvector->begin(), end = rvector->end(); ptr < end; ++ptr)
|
||||
{
|
||||
jrd_rel* relation = *ptr;
|
||||
if (relation)
|
||||
{
|
||||
if (relation->rel_existence_lock)
|
||||
{
|
||||
LCK_release(tdbb, relation->rel_existence_lock);
|
||||
relation->rel_flags |= REL_check_existence;
|
||||
relation->rel_use_count = 0;
|
||||
}
|
||||
if (relation->rel_partners_lock)
|
||||
{
|
||||
LCK_release(tdbb, relation->rel_partners_lock);
|
||||
relation->rel_flags |= REL_check_partners;
|
||||
}
|
||||
if (relation->rel_rescan_lock)
|
||||
{
|
||||
LCK_release(tdbb, relation->rel_rescan_lock);
|
||||
relation->rel_flags &= ~REL_scanned;
|
||||
}
|
||||
for (IndexLock* index = relation->rel_index_locks; index; index = index->idl_next)
|
||||
{
|
||||
if (index->idl_lock)
|
||||
{
|
||||
index->idl_count = 0;
|
||||
LCK_release(tdbb, index->idl_lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// release all procedure existence locks that might have been taken
|
||||
|
||||
vec<jrd_prc*>* pvector = att_procedures;
|
||||
if (pvector)
|
||||
{
|
||||
vec<jrd_prc*>::iterator pptr, pend;
|
||||
for (pptr = pvector->begin(), pend = pvector->end(); pptr < pend; ++pptr)
|
||||
{
|
||||
jrd_prc* procedure = *pptr;
|
||||
if (procedure)
|
||||
{
|
||||
if (procedure->prc_existence_lock)
|
||||
{
|
||||
LCK_release(tdbb, procedure->prc_existence_lock);
|
||||
procedure->prc_flags |= PRC_check_existence;
|
||||
procedure->prc_use_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// release all function existence locks that might have been taken
|
||||
|
||||
for (Function** iter = att_functions.begin(); iter < att_functions.end(); ++iter)
|
||||
{
|
||||
Function* const function = *iter;
|
||||
|
||||
if (function)
|
||||
{
|
||||
function->releaseLocks(tdbb);
|
||||
}
|
||||
}
|
||||
|
||||
// release collation existence locks
|
||||
|
||||
releaseIntlObjects();
|
||||
|
||||
// And release the system requests.
|
||||
|
||||
for (JrdStatement** itr = att_internal.begin(); itr != att_internal.end(); ++itr)
|
||||
{
|
||||
if (*itr)
|
||||
(*itr)->release(tdbb);
|
||||
}
|
||||
|
||||
for (JrdStatement** itr = att_dyn_req.begin(); itr != att_dyn_req.end(); ++itr)
|
||||
{
|
||||
if (*itr)
|
||||
(*itr)->release(tdbb);
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,8 @@ namespace EDS {
|
||||
class Connection;
|
||||
}
|
||||
|
||||
class CharSetContainer;
|
||||
|
||||
namespace Jrd
|
||||
{
|
||||
class thread_db;
|
||||
@ -71,6 +73,12 @@ namespace Jrd
|
||||
class PreparedStatement;
|
||||
class TraceManager;
|
||||
template <typename T> class vec;
|
||||
class jrd_rel;
|
||||
class jrd_prc;
|
||||
class Trigger;
|
||||
typedef Firebird::ObjectsArray<Trigger> trig_vec;
|
||||
class Function;
|
||||
class JrdStatement;
|
||||
|
||||
struct DSqlCacheItem
|
||||
{
|
||||
@ -120,6 +128,95 @@ struct bid;
|
||||
//
|
||||
class Attachment : public pool_alloc<type_att>
|
||||
{
|
||||
public:
|
||||
class SyncGuard
|
||||
{
|
||||
public:
|
||||
SyncGuard(Attachment* att, bool optional = false) :
|
||||
m_mutex(NULL)
|
||||
{
|
||||
if (att && att->att_interface)
|
||||
m_mutex = att->att_interface->getMutex();
|
||||
|
||||
fb_assert(optional || m_mutex);
|
||||
|
||||
if (m_mutex)
|
||||
m_mutex->enter();
|
||||
}
|
||||
|
||||
~SyncGuard()
|
||||
{
|
||||
if (m_mutex)
|
||||
m_mutex->leave();
|
||||
}
|
||||
|
||||
private:
|
||||
// copying is prohibited
|
||||
SyncGuard(const SyncGuard&);
|
||||
SyncGuard& operator=(const SyncGuard&);
|
||||
|
||||
Firebird::Mutex* m_mutex;
|
||||
};
|
||||
|
||||
class Checkout
|
||||
{
|
||||
public:
|
||||
Checkout(Attachment* att, bool optional = false) :
|
||||
m_mutex(NULL)
|
||||
{
|
||||
if (att && att->att_interface)
|
||||
{
|
||||
m_ref = att->att_interface;
|
||||
m_mutex = att->att_interface->getMutex();
|
||||
}
|
||||
|
||||
fb_assert(optional || m_mutex);
|
||||
|
||||
if (m_mutex)
|
||||
m_mutex->leave();
|
||||
}
|
||||
|
||||
~Checkout()
|
||||
{
|
||||
if (m_mutex)
|
||||
m_mutex->enter();
|
||||
}
|
||||
|
||||
private:
|
||||
// copying is prohibited
|
||||
Checkout(const Checkout&);
|
||||
Checkout& operator=(const Checkout&);
|
||||
|
||||
Firebird::Mutex* m_mutex;
|
||||
Firebird::RefPtr<JAttachment> m_ref;
|
||||
};
|
||||
|
||||
class CheckoutLockGuard
|
||||
{
|
||||
public:
|
||||
CheckoutLockGuard(Attachment* att, Firebird::Mutex& mutex, bool optional = false) :
|
||||
m_mutex(mutex)
|
||||
{
|
||||
if (!m_mutex.tryEnter())
|
||||
{
|
||||
Checkout attCout(att, optional);
|
||||
m_mutex.enter();
|
||||
}
|
||||
}
|
||||
|
||||
~CheckoutLockGuard()
|
||||
{
|
||||
m_mutex.leave();
|
||||
}
|
||||
|
||||
private:
|
||||
// copying is prohibited
|
||||
CheckoutLockGuard(const CheckoutLockGuard&);
|
||||
CheckoutLockGuard& operator=(const CheckoutLockGuard&);
|
||||
|
||||
Firebird::Mutex& m_mutex;
|
||||
};
|
||||
|
||||
public:
|
||||
static Attachment* create(Database* dbb);
|
||||
static void destroy(Attachment* const attachment);
|
||||
@ -170,6 +267,7 @@ public:
|
||||
Firebird::SortedArray<void*> att_udf_pointers;
|
||||
dsql_dbb* att_dsql_instance;
|
||||
bool att_in_use; // attachment in use (can't be detached or dropped)
|
||||
int att_use_count; // number of API calls running except of asyncronous ones
|
||||
|
||||
EDS::Connection* att_ext_connection; // external connection executed by this attachment
|
||||
ULONG att_ext_call_depth; // external connection call depth, 0 for user attachment
|
||||
@ -178,6 +276,35 @@ public:
|
||||
JAttachment* att_interface;
|
||||
Firebird::IAttachment* att_public_interface;
|
||||
|
||||
/// former Database members
|
||||
vec<jrd_rel*>* att_relations; // relation vector
|
||||
vec<jrd_prc*>* att_procedures; // scanned procedures
|
||||
trig_vec* att_triggers[DB_TRIGGER_MAX];
|
||||
trig_vec* att_ddl_triggers;
|
||||
Firebird::Array<Function*> att_functions; // User defined functions
|
||||
|
||||
Firebird::Array<JrdStatement*> att_internal; // internal statements
|
||||
Firebird::Array<JrdStatement*> att_dyn_req; // internal dyn statements
|
||||
|
||||
jrd_req* findSystemRequest(thread_db* tdbb, USHORT id, USHORT which);
|
||||
|
||||
Firebird::Array<CharSetContainer*> att_charsets; // intl character set descriptions
|
||||
Firebird::GenericMap<Firebird::Pair<Firebird::Left<
|
||||
Firebird::MetaName, USHORT> > > att_charset_ids; // Character set ids
|
||||
|
||||
void releaseIntlObjects(); // defined in intl.cpp
|
||||
void destroyIntlObjects(); // defined in intl.cpp
|
||||
|
||||
// from CMP_shutdown_database and CMP_fini
|
||||
void shutdown(thread_db* tdbb);
|
||||
|
||||
Firebird::Array<MemoryPool*> att_pools; // pools
|
||||
|
||||
MemoryPool* createPool();
|
||||
void deletePool(MemoryPool* pool);
|
||||
|
||||
/// former Database members
|
||||
|
||||
bool locksmith() const;
|
||||
jrd_tra* getSysTransaction();
|
||||
void setSysTransaction(jrd_tra* trans); // used only by TRA_init
|
||||
|
@ -77,20 +77,23 @@ namespace Jrd
|
||||
|
||||
Database::~Database()
|
||||
{
|
||||
destroyIntlObjects();
|
||||
{
|
||||
Firebird::SyncLockGuard guard(&dbb_pools_sync, SYNC_EXCLUSIVE, "Database::~Database");
|
||||
|
||||
fb_assert(dbb_pools[0] == dbb_permanent);
|
||||
for (size_t i = 1; i < dbb_pools.getCount(); ++i)
|
||||
{
|
||||
MemoryPool::deletePool(dbb_pools[i]);
|
||||
}
|
||||
}
|
||||
|
||||
delete dbb_monitoring_data;
|
||||
delete dbb_backup_manager;
|
||||
|
||||
dbb_flags |= DBB_destroying;
|
||||
|
||||
Checkout dcoHolder(this);
|
||||
// Checkout dcoHolder(this);
|
||||
|
||||
// This line decrements the usage counter and may cause the destructor to be called.
|
||||
// It should happen with the dbb_sync unlocked.
|
||||
LockManager::destroy(dbb_lock_mgr);
|
||||
@ -101,57 +104,19 @@ namespace Jrd
|
||||
{
|
||||
if (pool)
|
||||
{
|
||||
{
|
||||
Firebird::SyncLockGuard guard(&dbb_pools_sync, SYNC_EXCLUSIVE, "Database::deletePool");
|
||||
size_t pos;
|
||||
if (dbb_pools.find(pool, pos))
|
||||
{
|
||||
dbb_pools.remove(pos);
|
||||
}
|
||||
}
|
||||
|
||||
MemoryPool::deletePool(pool);
|
||||
}
|
||||
}
|
||||
|
||||
// Find an inactive incarnation of a system request. If necessary, clone it.
|
||||
jrd_req* Database::findSystemRequest(thread_db* tdbb, USHORT id, USHORT which)
|
||||
{
|
||||
static const int MAX_RECURSION = 100;
|
||||
|
||||
// If the request hasn't been compiled or isn't active, there're nothing to do.
|
||||
|
||||
Database::CheckoutLockGuard guard(this, dbb_cmp_clone_mutex);
|
||||
|
||||
fb_assert(which == IRQ_REQUESTS || which == DYN_REQUESTS);
|
||||
|
||||
JrdStatement* statement = (which == IRQ_REQUESTS ? dbb_internal[id] : dbb_dyn_req[id]);
|
||||
|
||||
if (!statement)
|
||||
return NULL;
|
||||
|
||||
// Look for requests until we find one that is available.
|
||||
|
||||
for (int n = 0;; ++n)
|
||||
{
|
||||
if (n > MAX_RECURSION)
|
||||
{
|
||||
ERR_post(Arg::Gds(isc_no_meta_update) <<
|
||||
Arg::Gds(isc_req_depth_exceeded) << Arg::Num(MAX_RECURSION));
|
||||
// Msg363 "request depth exceeded. (Recursive definition?)"
|
||||
}
|
||||
|
||||
jrd_req* clone = statement->getRequest(tdbb, n);
|
||||
|
||||
if (!(clone->req_flags & (req_active | req_reserved)))
|
||||
{
|
||||
clone->req_flags |= req_reserved;
|
||||
clone->setAttachment(tdbb->getAttachment());
|
||||
fb_assert(clone->req_attachment);
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Database::SharedCounter implementation
|
||||
|
||||
Database::SharedCounter::SharedCounter()
|
||||
{
|
||||
memset(m_counters, 0, sizeof(m_counters));
|
||||
@ -180,6 +145,8 @@ namespace Jrd
|
||||
ValueCache* const counter = &m_counters[space];
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
|
||||
SyncLockGuard guard(&dbb->dbb_sh_counter_sync, SYNC_EXCLUSIVE, "Database::SharedCounter::generate");
|
||||
|
||||
if (!counter->lock)
|
||||
{
|
||||
Lock* const lock = FB_NEW_RPT(*dbb->dbb_permanent, sizeof(SLONG)) Lock();
|
||||
@ -225,11 +192,13 @@ namespace Jrd
|
||||
|
||||
try
|
||||
{
|
||||
Database::SyncGuard dsGuard(dbb, true);
|
||||
if (dbb->dbb_flags & DBB_not_in_use)
|
||||
return 0;
|
||||
|
||||
SyncLockGuard guard(&dbb->dbb_sh_counter_sync, SYNC_EXCLUSIVE, "Database::blockingAstSharedCounter");
|
||||
|
||||
ThreadContextHolder tdbb;
|
||||
tdbb->setDatabase(dbb);
|
||||
// tdbb->setAttachment(counter->lock->lck_attachment);
|
||||
|
||||
Jrd::ContextPoolHolder context(tdbb, dbb->dbb_permanent);
|
||||
|
||||
|
@ -62,23 +62,19 @@
|
||||
#include "../jrd/event_proto.h"
|
||||
#include "../lock/lock_proto.h"
|
||||
#include "../common/config/config.h"
|
||||
|
||||
class CharSetContainer;
|
||||
#include "../common/classes/SyncObject.h"
|
||||
#include "../common/classes/Synchronize.h"
|
||||
|
||||
namespace Jrd
|
||||
{
|
||||
class Trigger;
|
||||
template <typename T> class vec;
|
||||
class jrd_prc;
|
||||
class jrd_rel;
|
||||
class Shadow;
|
||||
class BlobFilter;
|
||||
class TxPageCache;
|
||||
class BackupManager;
|
||||
class ExternalFileDirectoryList;
|
||||
class MonitoringData;
|
||||
|
||||
typedef Firebird::ObjectsArray<Trigger> trig_vec;
|
||||
template <typename T> class vec;
|
||||
class jrd_rel;
|
||||
class Shadow;
|
||||
class BlobFilter;
|
||||
class TipCache;
|
||||
class BackupManager;
|
||||
class ExternalFileDirectoryList;
|
||||
class MonitoringData;
|
||||
|
||||
|
||||
// general purpose vector
|
||||
@ -238,150 +234,7 @@ const ULONG DBB_monitor_off = 0x400L; // Database has the monitoring lock rele
|
||||
|
||||
class Database : public pool_alloc<type_dbb>
|
||||
{
|
||||
class Sync : public Firebird::RefCounted
|
||||
{
|
||||
public:
|
||||
Sync() : threadId(0)
|
||||
{}
|
||||
|
||||
void lock()
|
||||
{
|
||||
ThreadPriorityScheduler::enter();
|
||||
++waiters;
|
||||
syncMutex.enter();
|
||||
--waiters;
|
||||
threadId = getThreadId();
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
ThreadPriorityScheduler::exit();
|
||||
threadId = 0;
|
||||
syncMutex.leave();
|
||||
}
|
||||
|
||||
bool hasContention() const
|
||||
{
|
||||
return (waiters.value() > 0);
|
||||
}
|
||||
|
||||
private:
|
||||
~Sync()
|
||||
{
|
||||
if (threadId)
|
||||
{
|
||||
syncMutex.leave();
|
||||
}
|
||||
}
|
||||
|
||||
// copying is prohibited
|
||||
Sync(const Sync&);
|
||||
Sync& operator=(const Sync&);
|
||||
|
||||
Firebird::Mutex syncMutex;
|
||||
Firebird::AtomicCounter waiters;
|
||||
FB_THREAD_ID threadId;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
class SyncGuard
|
||||
{
|
||||
public:
|
||||
explicit SyncGuard(Database* dbb, bool ast = false)
|
||||
: sync(*dbb->dbb_sync)
|
||||
{
|
||||
if (!dbb)
|
||||
{
|
||||
Firebird::status_exception::raise(Firebird::Arg::Gds(isc_bad_db_handle));
|
||||
}
|
||||
|
||||
sync.addRef();
|
||||
sync.lock();
|
||||
|
||||
if (ast && dbb->dbb_flags & DBB_destroying)
|
||||
{
|
||||
sync.unlock();
|
||||
sync.release();
|
||||
Firebird::LongJump::raise();
|
||||
}
|
||||
}
|
||||
|
||||
~SyncGuard()
|
||||
{
|
||||
try
|
||||
{
|
||||
sync.unlock();
|
||||
}
|
||||
catch (const Firebird::Exception&)
|
||||
{
|
||||
DtorException::devHalt();
|
||||
}
|
||||
sync.release();
|
||||
}
|
||||
|
||||
private:
|
||||
// copying is prohibited
|
||||
SyncGuard(const SyncGuard&);
|
||||
SyncGuard& operator=(const SyncGuard&);
|
||||
|
||||
Sync& sync;
|
||||
};
|
||||
|
||||
class Checkout
|
||||
{
|
||||
public:
|
||||
explicit Checkout(Database* dbb)
|
||||
: sync(*dbb->dbb_sync)
|
||||
{
|
||||
sync.unlock();
|
||||
}
|
||||
|
||||
~Checkout()
|
||||
{
|
||||
sync.lock();
|
||||
}
|
||||
|
||||
private:
|
||||
// copying is prohibited
|
||||
Checkout(const Checkout&);
|
||||
Checkout& operator=(const Checkout&);
|
||||
|
||||
Sync& sync;
|
||||
};
|
||||
|
||||
class CheckoutLockGuard
|
||||
{
|
||||
public:
|
||||
CheckoutLockGuard(Database* dbb, Firebird::Mutex& m)
|
||||
: mutex(m)
|
||||
{
|
||||
if (!mutex.tryEnter())
|
||||
{
|
||||
Checkout dcoHolder(dbb);
|
||||
mutex.enter();
|
||||
}
|
||||
}
|
||||
|
||||
~CheckoutLockGuard()
|
||||
{
|
||||
try {
|
||||
mutex.leave();
|
||||
}
|
||||
catch (const Firebird::Exception&)
|
||||
{
|
||||
DtorException::devHalt();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// copying is prohibited
|
||||
CheckoutLockGuard(const CheckoutLockGuard&);
|
||||
CheckoutLockGuard& operator=(const CheckoutLockGuard&);
|
||||
|
||||
Firebird::Mutex& mutex;
|
||||
};
|
||||
|
||||
class SharedCounter
|
||||
{
|
||||
static const ULONG DEFAULT_CACHE_SIZE = 16;
|
||||
@ -452,7 +305,9 @@ public:
|
||||
return fb_utils::genUniqueId();
|
||||
}
|
||||
|
||||
mutable Firebird::RefPtr<Sync> dbb_sync; // Database sync primitive
|
||||
Firebird::SyncObject dbb_sync;
|
||||
Firebird::SyncObject dbb_lck_sync; // syncronize operations with att_long_locks at different attachments
|
||||
|
||||
|
||||
LockManager* dbb_lock_mgr;
|
||||
EventManager* dbb_event_mgr;
|
||||
@ -460,36 +315,32 @@ public:
|
||||
Database* dbb_next; // Next database block in system
|
||||
Attachment* dbb_attachments; // Active attachments
|
||||
BufferControl* dbb_bcb; // Buffer control block
|
||||
vec<jrd_rel*>* dbb_relations; // relation vector
|
||||
vec<jrd_prc*>* dbb_procedures; // scanned procedures
|
||||
int dbb_monitoring_id; // dbb monitoring identifier
|
||||
Lock* dbb_lock; // granddaddy lock
|
||||
|
||||
Firebird::SyncObject dbb_sh_counter_sync;
|
||||
|
||||
Firebird::SyncObject dbb_shadow_sync;
|
||||
Shadow* dbb_shadow; // shadow control block
|
||||
Lock* dbb_shadow_lock; // lock for synchronizing addition of shadows
|
||||
|
||||
Lock* dbb_retaining_lock; // lock for preserving commit retaining snapshot
|
||||
Lock* dbb_monitor_lock; // lock for monitoring purposes
|
||||
PageManager dbb_page_manager;
|
||||
vcl* dbb_t_pages; // pages number for transactions
|
||||
vcl* dbb_gen_id_pages; // known pages for gen_id
|
||||
BlobFilter* dbb_blob_filters; // known blob filters
|
||||
trig_vec* dbb_triggers[DB_TRIGGER_MAX];
|
||||
trig_vec* dbb_ddl_triggers;
|
||||
|
||||
Firebird::SyncObject dbb_mon_sync; // syncronize operations with dbb_monitor_lock
|
||||
MonitoringData* dbb_monitoring_data; // monitoring data
|
||||
|
||||
DatabaseModules dbb_modules; // external function/filter modules
|
||||
ExtEngineManager dbb_extManager; // external engine manager
|
||||
|
||||
Firebird::Mutex dbb_meta_mutex; // Mutex to protect metadata changes while dbb_sync is unlocked
|
||||
Firebird::Mutex dbb_cmp_clone_mutex;
|
||||
Firebird::Mutex dbb_exe_clone_mutex;
|
||||
Firebird::Mutex dbb_flush_count_mutex;
|
||||
Firebird::Mutex dbb_dyn_mutex;
|
||||
Firebird::SyncObject dbb_flush_count_mutex;
|
||||
|
||||
//SLONG dbb_sort_size; // Size of sort space per sort, unused for now
|
||||
|
||||
ULONG dbb_ast_flags; // flags modified at AST level
|
||||
ULONG dbb_flags;
|
||||
Firebird::AtomicCounter dbb_ast_flags; // flags modified at AST level
|
||||
Firebird::AtomicCounter dbb_flags;
|
||||
USHORT dbb_ods_version; // major ODS version number
|
||||
USHORT dbb_minor_version; // minor ODS version number
|
||||
USHORT dbb_page_size; // page size
|
||||
@ -508,30 +359,17 @@ public:
|
||||
Firebird::string dbb_encrypt_key; // encryption key
|
||||
|
||||
MemoryPool* dbb_permanent;
|
||||
MemoryPool* dbb_bufferpool;
|
||||
|
||||
Firebird::SyncObject dbb_pools_sync;
|
||||
Firebird::Array<MemoryPool*> dbb_pools; // pools
|
||||
|
||||
Firebird::Array<JrdStatement*> dbb_internal; // internal statements
|
||||
Firebird::Array<JrdStatement*> dbb_dyn_req; // internal dyn statements
|
||||
|
||||
SLONG dbb_oldest_active; // Cached "oldest active" transaction
|
||||
SLONG dbb_oldest_transaction; // Cached "oldest interesting" transaction
|
||||
SLONG dbb_oldest_snapshot; // Cached "oldest snapshot" of all active transactions
|
||||
SLONG dbb_next_transaction; // Next transaction id used by NETWARE
|
||||
SLONG dbb_attachment_id; // Next attachment id for ReadOnly DB's
|
||||
SLONG dbb_page_incarnation; // Cache page incarnation counter
|
||||
ULONG dbb_page_buffers; // Page buffers from header page
|
||||
|
||||
Firebird::Semaphore dbb_writer_sem; // Wake up cache writer
|
||||
Firebird::Semaphore dbb_writer_init;// Cache writer initialization
|
||||
Firebird::Semaphore dbb_writer_fini;// Cache writer finalization
|
||||
#ifdef SUPERSERVER_V2
|
||||
// the code in cch.cpp is not tested for semaphore instead event !!!
|
||||
Firebird::Semaphore dbb_reader_sem; // Wake up cache reader
|
||||
Firebird::Semaphore dbb_reader_init;// Cache reader initialization
|
||||
Firebird::Semaphore dbb_reader_fini;// Cache reader finalization
|
||||
#endif
|
||||
|
||||
#ifdef GARBAGE_THREAD
|
||||
Firebird::Semaphore dbb_gc_sem; // Event to wake up garbage collector
|
||||
@ -554,14 +392,10 @@ public:
|
||||
crypt_routine dbb_encrypt; // External encryption routine
|
||||
crypt_routine dbb_decrypt; // External decryption routine
|
||||
|
||||
Firebird::Array<CharSetContainer*> dbb_charsets; // intl character set descriptions
|
||||
TxPageCache* dbb_tip_cache; // cache of latest known state of all transactions in system
|
||||
TipCache* dbb_tip_cache; // cache of latest known state of all transactions in system
|
||||
TransactionsVector* dbb_pc_transactions; // active precommitted transactions
|
||||
BackupManager* dbb_backup_manager; // physical backup manager
|
||||
Firebird::TimeStamp dbb_creation_date; // creation date
|
||||
Firebird::Array<Function*> dbb_functions; // User defined functions
|
||||
Firebird::GenericMap<Firebird::Pair<Firebird::Left<
|
||||
Firebird::MetaName, USHORT> > > dbb_charset_ids; // Character set ids
|
||||
ExternalFileDirectoryList* dbb_external_file_directory_list;
|
||||
Firebird::RefPtr<Config> dbb_config;
|
||||
|
||||
@ -576,6 +410,8 @@ public:
|
||||
MemoryPool* createPool()
|
||||
{
|
||||
MemoryPool* const pool = MemoryPool::createPool(dbb_permanent, dbb_memory_stats);
|
||||
|
||||
Firebird::SyncLockGuard guard(&dbb_pools_sync, Firebird::SYNC_EXCLUSIVE, "Database::createPool");
|
||||
dbb_pools.add(pool);
|
||||
return pool;
|
||||
}
|
||||
@ -584,8 +420,7 @@ public:
|
||||
|
||||
private:
|
||||
explicit Database(MemoryPool* p)
|
||||
: dbb_sync(FB_NEW(*getDefaultMemoryPool()) Sync),
|
||||
dbb_page_manager(this, *p),
|
||||
: dbb_page_manager(this, *p),
|
||||
dbb_modules(*p),
|
||||
dbb_extManager(*p),
|
||||
dbb_filename(*p),
|
||||
@ -593,31 +428,18 @@ private:
|
||||
dbb_encrypt_key(*p),
|
||||
dbb_permanent(p),
|
||||
dbb_pools(*p, 4),
|
||||
dbb_internal(*p),
|
||||
dbb_dyn_req(*p),
|
||||
dbb_stats(*p),
|
||||
dbb_lock_owner_id(getLockOwnerId()),
|
||||
dbb_charsets(*p),
|
||||
dbb_creation_date(Firebird::TimeStamp::getCurrentTimeStamp()),
|
||||
dbb_functions(*p),
|
||||
dbb_charset_ids(*p),
|
||||
dbb_tip_cache(NULL),
|
||||
dbb_external_file_directory_list(NULL)
|
||||
{
|
||||
dbb_pools.add(p);
|
||||
dbb_internal.grow(irq_MAX);
|
||||
dbb_dyn_req.grow(drq_MAX);
|
||||
}
|
||||
|
||||
~Database();
|
||||
|
||||
public:
|
||||
// temporary measure to avoid unstable state of lock file -
|
||||
// this is anyway called in ~Database(), and in theory should be private
|
||||
void releaseIntlObjects(); // defined in intl.cpp
|
||||
void destroyIntlObjects(); // defined in intl.cpp
|
||||
|
||||
jrd_req* findSystemRequest(thread_db* tdbb, USHORT id, USHORT which);
|
||||
|
||||
SLONG generateAttachmentId(thread_db* tdbb)
|
||||
{
|
||||
return dbb_shared_counter.generate(tdbb, SharedCounter::ATTACHMENT_ID_SPACE, 1);
|
||||
|
@ -350,19 +350,19 @@ int DatabaseSnapshot::blockingAst(void* ast_object)
|
||||
{
|
||||
Lock* const lock = dbb->dbb_monitor_lock;
|
||||
|
||||
Database::SyncGuard dsGuard(dbb, true);
|
||||
|
||||
ThreadContextHolder tdbb;
|
||||
tdbb->setDatabase(lock->lck_dbb);
|
||||
tdbb->setAttachment(lock->lck_attachment);
|
||||
|
||||
ContextPoolHolder context(tdbb, dbb->dbb_permanent);
|
||||
if (!(dbb->dbb_ast_flags & DBB_monitor_off))
|
||||
{
|
||||
SyncLockGuard monGuard(&dbb->dbb_mon_sync, SYNC_EXCLUSIVE, "DatabaseSnapshot::blockingAst");
|
||||
|
||||
if (!(dbb->dbb_ast_flags & DBB_monitor_off))
|
||||
{
|
||||
// Write the data to the shared memory
|
||||
if (!(dbb->dbb_flags & DBB_not_in_use))
|
||||
{
|
||||
ContextPoolHolder context(tdbb, dbb->dbb_permanent);
|
||||
try
|
||||
{
|
||||
dumpData(tdbb);
|
||||
@ -378,6 +378,7 @@ int DatabaseSnapshot::blockingAst(void* ast_object)
|
||||
dbb->dbb_ast_flags |= DBB_monitor_off;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const Exception&)
|
||||
{} // no-op
|
||||
|
||||
@ -406,6 +407,9 @@ DatabaseSnapshot::DatabaseSnapshot(thread_db* tdbb, MemoryPool& pool)
|
||||
RecordBuffer* const ctx_var_buffer = allocBuffer(tdbb, pool, rel_mon_ctx_vars);
|
||||
RecordBuffer* const mem_usage_buffer = allocBuffer(tdbb, pool, rel_mon_mem_usage);
|
||||
|
||||
{
|
||||
SyncLockGuard monGuard(&dbb->dbb_mon_sync, SYNC_EXCLUSIVE, "DatabaseSnapshot::DatabaseSnapshot");
|
||||
|
||||
// Release our own lock
|
||||
LCK_release(tdbb, dbb->dbb_monitor_lock);
|
||||
dbb->dbb_ast_flags &= ~DBB_monitor_off;
|
||||
@ -418,6 +422,7 @@ DatabaseSnapshot::DatabaseSnapshot(thread_db* tdbb, MemoryPool& pool)
|
||||
// Dump our own data
|
||||
dumpData(tdbb);
|
||||
}
|
||||
}
|
||||
|
||||
// Signal other processes to dump their data
|
||||
Lock temp_lock, *lock = &temp_lock;
|
||||
@ -771,8 +776,14 @@ void DatabaseSnapshot::dumpData(thread_db* tdbb)
|
||||
|
||||
// Attachment information
|
||||
|
||||
Attachment* old_attachment = tdbb->getAttachment();
|
||||
Attachment::Checkout attCout(old_attachment, true);
|
||||
|
||||
for (Attachment* attachment = dbb->dbb_attachments; attachment; attachment = attachment->att_next)
|
||||
{
|
||||
Attachment::SyncGuard attGuard(attachment);
|
||||
tdbb->setAttachment(attachment);
|
||||
|
||||
if (!putAttachment(tdbb, attachment, writer, fb_utils::genUniqueId()))
|
||||
continue;
|
||||
|
||||
@ -823,6 +834,8 @@ void DatabaseSnapshot::dumpData(thread_db* tdbb)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tdbb->setAttachment(old_attachment);
|
||||
}
|
||||
|
||||
|
||||
|
@ -134,7 +134,7 @@ private:
|
||||
Utf8 charSetName[MAX_SQL_IDENTIFIER_SIZE];
|
||||
|
||||
{ // scope
|
||||
Database::Checkout dcoHolder(tdbb->getDatabase());
|
||||
Attachment::Checkout attCout(attachment);
|
||||
|
||||
obj->getCharSet(RaiseError(), attInfo->context, charSetName, MAX_SQL_IDENTIFIER_LEN);
|
||||
charSetName[MAX_SQL_IDENTIFIER_LEN] = '\0';
|
||||
@ -299,7 +299,7 @@ ExtEngineManager::Function::Function(thread_db* tdbb, ExtEngineManager* aExtMana
|
||||
|
||||
ExtEngineManager::Function::~Function()
|
||||
{
|
||||
Database::Checkout dcoHolder(database);
|
||||
// Database::Checkout dcoHolder(database);
|
||||
function->dispose(LogError());
|
||||
}
|
||||
|
||||
@ -358,7 +358,7 @@ void ExtEngineManager::Function::execute(thread_db* tdbb, const NestValueArray&
|
||||
}
|
||||
|
||||
{ // scope
|
||||
Database::Checkout dcoHolder(tdbb->getDatabase());
|
||||
Attachment::Checkout attCout(tdbb->getAttachment());
|
||||
function->execute(RaiseError(), attInfo->context, ¶ms, &result);
|
||||
}
|
||||
}
|
||||
@ -397,7 +397,7 @@ ExtEngineManager::Procedure::Procedure(thread_db* tdbb, ExtEngineManager* aExtMa
|
||||
|
||||
ExtEngineManager::Procedure::~Procedure()
|
||||
{
|
||||
Database::Checkout dcoHolder(database);
|
||||
//Database::Checkout dcoHolder(database);
|
||||
procedure->dispose(LogError());
|
||||
}
|
||||
|
||||
@ -415,7 +415,7 @@ ExtEngineManager::ResultSet* ExtEngineManager::Procedure::open(thread_db* tdbb,
|
||||
ExtEngineManager::ResultSet::ResultSet(thread_db* tdbb, ValuesImpl* inputParams,
|
||||
ValuesImpl* outputParams, const ExtEngineManager::Procedure* aProcedure)
|
||||
: procedure(aProcedure),
|
||||
database(tdbb->getDatabase()),
|
||||
attachment(tdbb->getAttachment()),
|
||||
firstFetch(true)
|
||||
{
|
||||
attInfo = procedure->extManager->getEngineAttachment(tdbb, procedure->engine);
|
||||
@ -423,11 +423,10 @@ ExtEngineManager::ResultSet::ResultSet(thread_db* tdbb, ValuesImpl* inputParams,
|
||||
(procedure->prc->getName().package.isEmpty() ?
|
||||
CallerName(obj_procedure, procedure->prc->getName().identifier) :
|
||||
CallerName(obj_package_header, procedure->prc->getName().package)));
|
||||
Attachment* attachment = tdbb->getAttachment();
|
||||
|
||||
charSet = attachment->att_charset;
|
||||
|
||||
Database::Checkout dcoHolder(tdbb->getDatabase());
|
||||
Attachment::Checkout attCout(attachment);
|
||||
|
||||
resultSet = procedure->procedure->open(RaiseError(), attInfo->context, inputParams,
|
||||
outputParams);
|
||||
@ -438,7 +437,8 @@ ExtEngineManager::ResultSet::~ResultSet()
|
||||
{
|
||||
if (resultSet)
|
||||
{
|
||||
Database::Checkout dcoHolder(database);
|
||||
fb_assert(attachment == JRD_get_thread_data()->getAttachment());
|
||||
Attachment::Checkout attCout(attachment);
|
||||
resultSet->dispose(LogError());
|
||||
}
|
||||
}
|
||||
@ -457,7 +457,8 @@ bool ExtEngineManager::ResultSet::fetch(thread_db* tdbb)
|
||||
CallerName(obj_procedure, procedure->prc->getName().identifier) :
|
||||
CallerName(obj_package_header, procedure->prc->getName().package)));
|
||||
|
||||
Database::Checkout dcoHolder(tdbb->getDatabase());
|
||||
fb_assert(attachment == tdbb->getAttachment());
|
||||
Attachment::Checkout attCout(attachment);
|
||||
return resultSet->fetch(RaiseError());
|
||||
}
|
||||
|
||||
@ -479,6 +480,7 @@ ExtEngineManager::Trigger::Trigger(thread_db* tdbb, ExtEngineManager* aExtManage
|
||||
|
||||
ExtEngineManager::Trigger::~Trigger()
|
||||
{
|
||||
// hvlad: shouldn't we call trigger->dispose() here ?
|
||||
}
|
||||
|
||||
|
||||
@ -504,7 +506,7 @@ void ExtEngineManager::Trigger::execute(thread_db* tdbb, ExternalTrigger::Action
|
||||
valueNewCount = setValues(tdbb, pool, newValues, descs, newRpb);
|
||||
|
||||
{ // scope
|
||||
Database::Checkout dcoHolder(tdbb->getDatabase());
|
||||
Attachment::Checkout attCout(tdbb->getAttachment());
|
||||
|
||||
trigger->execute(RaiseError(), attInfo->context, action, oldValues, newValues);
|
||||
|
||||
@ -605,7 +607,7 @@ void ExtEngineManager::initialize()
|
||||
}
|
||||
|
||||
|
||||
void ExtEngineManager::closeAttachment(thread_db* tdbb, Attachment* /*attachment*/)
|
||||
void ExtEngineManager::closeAttachment(thread_db* tdbb, Attachment* attachment)
|
||||
{
|
||||
Array<ExternalEngine*> enginesCopy;
|
||||
|
||||
@ -617,7 +619,7 @@ void ExtEngineManager::closeAttachment(thread_db* tdbb, Attachment* /*attachment
|
||||
enginesCopy.add(accessor.current()->second);
|
||||
}
|
||||
|
||||
Database::Checkout dcoHolder(tdbb->getDatabase());
|
||||
Attachment::Checkout attCout(attachment, true);
|
||||
|
||||
for (Array<ExternalEngine*>::iterator i = enginesCopy.begin(); i != enginesCopy.end(); ++i)
|
||||
{
|
||||
@ -652,7 +654,7 @@ ExtEngineManager::Function* ExtEngineManager::makeFunction(thread_db* tdbb, cons
|
||||
ExternalFunction* externalFunction;
|
||||
|
||||
{ // scope
|
||||
Database::Checkout dcoHolder(tdbb->getDatabase());
|
||||
Attachment::Checkout attCout(tdbb->getAttachment());
|
||||
|
||||
externalFunction = attInfo->engine->makeFunction(RaiseError(),
|
||||
attInfo->context, udf->getName().package.nullStr(), udf->getName().identifier.c_str(),
|
||||
@ -672,7 +674,7 @@ ExtEngineManager::Function* ExtEngineManager::makeFunction(thread_db* tdbb, cons
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Database::Checkout dcoHolder(tdbb->getDatabase());
|
||||
Attachment::Checkout attCout(tdbb->getAttachment());
|
||||
externalFunction->dispose(LogError());
|
||||
throw;
|
||||
}
|
||||
@ -694,7 +696,7 @@ ExtEngineManager::Procedure* ExtEngineManager::makeProcedure(thread_db* tdbb, co
|
||||
ExternalProcedure* externalProcedure;
|
||||
|
||||
{ // scope
|
||||
Database::Checkout dcoHolder(tdbb->getDatabase());
|
||||
Attachment::Checkout attCout(tdbb->getAttachment());
|
||||
|
||||
externalProcedure = attInfo->engine->makeProcedure(RaiseError(),
|
||||
attInfo->context, prc->getName().package.nullStr(), prc->getName().identifier.c_str(),
|
||||
@ -714,7 +716,7 @@ ExtEngineManager::Procedure* ExtEngineManager::makeProcedure(thread_db* tdbb, co
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Database::Checkout dcoHolder(tdbb->getDatabase());
|
||||
Attachment::Checkout attCout(tdbb->getAttachment());
|
||||
externalProcedure->dispose(LogError());
|
||||
throw;
|
||||
}
|
||||
@ -738,7 +740,7 @@ ExtEngineManager::Trigger* ExtEngineManager::makeTrigger(thread_db* tdbb, const
|
||||
ExternalTrigger* externalTrigger;
|
||||
|
||||
{ // scope
|
||||
Database::Checkout dcoHolder(tdbb->getDatabase());
|
||||
Attachment::Checkout attCout(tdbb->getAttachment());
|
||||
|
||||
externalTrigger = attInfo->engine->makeTrigger(RaiseError(), attInfo->context,
|
||||
trg->name.c_str(), entryPointTrimmed.nullStr(), body.nullStr(),
|
||||
@ -757,7 +759,7 @@ ExtEngineManager::Trigger* ExtEngineManager::makeTrigger(thread_db* tdbb, const
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Database::Checkout dcoHolder(tdbb->getDatabase());
|
||||
Attachment::Checkout attCout(tdbb->getAttachment());
|
||||
externalTrigger->dispose(LogError());
|
||||
throw;
|
||||
}
|
||||
@ -786,7 +788,7 @@ ExternalEngine* ExtEngineManager::getEngine(thread_db* tdbb, const MetaName& nam
|
||||
|
||||
try
|
||||
{
|
||||
Database::Checkout dcoHolder(tdbb->getDatabase());
|
||||
Attachment::Checkout attCout(tdbb->getAttachment());
|
||||
|
||||
engine = engineControl.plugin();
|
||||
if (engine)
|
||||
@ -799,7 +801,7 @@ ExternalEngine* ExtEngineManager::getEngine(thread_db* tdbb, const MetaName& nam
|
||||
Arg::Num(version) << name);
|
||||
}
|
||||
|
||||
Database::SyncGuard dsGuard(tdbb->getDatabase());
|
||||
Attachment::SyncGuard attGuard(tdbb->getAttachment());
|
||||
|
||||
key = EngineAttachment(engine, tdbb->getAttachment());
|
||||
attInfo = FB_NEW(getPool()) EngineAttachmentInfo();
|
||||
@ -874,7 +876,7 @@ ExtEngineManager::EngineAttachmentInfo* ExtEngineManager::getEngineAttachment(
|
||||
enginesAttachments.put(key, attInfo);
|
||||
|
||||
ContextManager<ExternalFunction> ctxManager(tdbb, attInfo, attInfo->adminCharSet);
|
||||
Database::Checkout dcoHolder(tdbb->getDatabase());
|
||||
Attachment::Checkout attCout(tdbb->getAttachment());
|
||||
engine->openAttachment(LogError(), attInfo->context);
|
||||
}
|
||||
|
||||
|
@ -179,7 +179,7 @@ public:
|
||||
|
||||
private:
|
||||
const Procedure* procedure;
|
||||
Database* database;
|
||||
Attachment* attachment;
|
||||
bool firstFetch;
|
||||
EngineAttachmentInfo* attInfo;
|
||||
Firebird::ExternalResultSet* resultSet;
|
||||
|
@ -65,7 +65,7 @@ Function* Function::lookup(thread_db* tdbb, USHORT id, bool return_deleted, bool
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
Function* check_function = NULL;
|
||||
|
||||
Function* function = (id < dbb->dbb_functions.getCount()) ? dbb->dbb_functions[id] : NULL;
|
||||
Function* function = (id < attachment->att_functions.getCount()) ? attachment->att_functions[id] : NULL;
|
||||
|
||||
if (function && function->getId() == id &&
|
||||
!(function->fun_flags & FUN_being_scanned) &&
|
||||
@ -117,7 +117,7 @@ Function* Function::lookup(thread_db* tdbb, const QualifiedName& name, bool nosc
|
||||
|
||||
// See if we already know the function by name
|
||||
|
||||
for (Function** iter = dbb->dbb_functions.begin(); iter < dbb->dbb_functions.end(); ++iter)
|
||||
for (Function** iter = attachment->att_functions.begin(); iter < attachment->att_functions.end(); ++iter)
|
||||
{
|
||||
Function* const function = *iter;
|
||||
|
||||
@ -174,14 +174,12 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
|
||||
jrd_tra* sysTransaction = attachment->getSysTransaction();
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
|
||||
if (id >= dbb->dbb_functions.getCount())
|
||||
if (id >= attachment->att_functions.getCount())
|
||||
{
|
||||
dbb->dbb_functions.grow(id + 1);
|
||||
attachment->att_functions.grow(id + 1);
|
||||
}
|
||||
|
||||
Database::CheckoutLockGuard guard(dbb, dbb->dbb_meta_mutex);
|
||||
|
||||
Function* function = dbb->dbb_functions[id];
|
||||
Function* function = attachment->att_functions[id];
|
||||
|
||||
if (function && !(function->fun_flags & FUN_obsolete))
|
||||
{
|
||||
@ -196,7 +194,7 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
|
||||
|
||||
if (!function)
|
||||
{
|
||||
function = FB_NEW(*dbb->dbb_permanent) Function(*dbb->dbb_permanent);
|
||||
function = FB_NEW(*attachment->att_pool) Function(*attachment->att_pool);
|
||||
}
|
||||
|
||||
try
|
||||
@ -205,11 +203,11 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
|
||||
function->fun_flags &= ~FUN_obsolete;
|
||||
|
||||
function->setId(id);
|
||||
dbb->dbb_functions[id] = function;
|
||||
attachment->att_functions[id] = function;
|
||||
|
||||
if (!function->fun_existence_lock)
|
||||
{
|
||||
Lock* const lock = FB_NEW_RPT(*dbb->dbb_permanent, 0) Lock;
|
||||
Lock* const lock = FB_NEW_RPT(*attachment->att_pool, 0) Lock;
|
||||
function->fun_existence_lock = lock;
|
||||
lock->lck_parent = dbb->dbb_lock;
|
||||
lock->lck_dbb = dbb;
|
||||
@ -328,7 +326,7 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
|
||||
{
|
||||
function->fun_defaults++;
|
||||
|
||||
MemoryPool* const csb_pool = dbb->createPool();
|
||||
MemoryPool* const csb_pool = attachment->createPool();
|
||||
Jrd::ContextPoolHolder context(tdbb, csb_pool);
|
||||
|
||||
try
|
||||
@ -338,7 +336,7 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
dbb->deletePool(csb_pool);
|
||||
attachment->deletePool(csb_pool);
|
||||
throw; // an explicit error message would be better
|
||||
}
|
||||
}
|
||||
@ -403,7 +401,7 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
|
||||
}
|
||||
else if (!X.RDB$FUNCTION_BLR.NULL)
|
||||
{
|
||||
MemoryPool* const csb_pool = dbb->createPool();
|
||||
MemoryPool* const csb_pool = attachment->createPool();
|
||||
Jrd::ContextPoolHolder context(tdbb, csb_pool);
|
||||
|
||||
try
|
||||
@ -427,7 +425,7 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
dbb->deletePool(csb_pool);
|
||||
attachment->deletePool(csb_pool);
|
||||
throw;
|
||||
}
|
||||
|
||||
@ -513,8 +511,9 @@ int Function::blockingAst(void* ast_object)
|
||||
try
|
||||
{
|
||||
Database* const dbb = function->fun_existence_lock->lck_dbb;
|
||||
Jrd::Attachment* att = function->fun_existence_lock->lck_attachment;
|
||||
|
||||
Database::SyncGuard dsGuard(dbb, true);
|
||||
Jrd::Attachment::SyncGuard guard(att);
|
||||
|
||||
ThreadContextHolder tdbb;
|
||||
tdbb->setDatabase(dbb);
|
||||
@ -624,8 +623,8 @@ void Function::release(thread_db* tdbb)
|
||||
{
|
||||
fun_use_count--;
|
||||
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
if (fun_use_count == 0 && dbb->dbb_functions[getId()] != this)
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
if (fun_use_count == 0 && attachment->att_functions[getId()] != this)
|
||||
{
|
||||
if (getStatement())
|
||||
{
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "jrd.h"
|
||||
#include "lck_proto.h"
|
||||
#include "err_proto.h"
|
||||
#include "Attachment.h"
|
||||
#include "../common/classes/rwlock.h"
|
||||
#include "../common/classes/condition.h"
|
||||
|
||||
@ -43,6 +44,7 @@
|
||||
IMPLEMENT_TRACE_ROUTINE(cos_trace, "COS")
|
||||
#endif
|
||||
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
int GlobalRWLock::blocking_ast_cached_lock(void* ast_object)
|
||||
@ -56,8 +58,6 @@ int GlobalRWLock::blocking_ast_cached_lock(void* ast_object)
|
||||
return 0;
|
||||
|
||||
Database* dbb = globalRWLock->cachedLock->lck_dbb;
|
||||
Database::SyncGuard dsGuard(dbb, true);
|
||||
|
||||
ThreadContextHolder tdbb;
|
||||
tdbb->setDatabase(dbb);
|
||||
|
||||
@ -101,7 +101,7 @@ void GlobalRWLock::shutdownLock()
|
||||
{
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
|
||||
Database::CheckoutLockGuard counterGuard(tdbb->getDatabase(), counterMutex);
|
||||
Attachment::CheckoutLockGuard counterGuard(tdbb->getAttachment(), counterMutex, true);
|
||||
|
||||
COS_TRACE(("(%p)->shutdownLock readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
|
||||
this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));
|
||||
@ -119,11 +119,10 @@ bool GlobalRWLock::lockWrite(thread_db* tdbb, SSHORT wait)
|
||||
{
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Attachment* att = tdbb->getAttachment();
|
||||
|
||||
{ // scope 1
|
||||
|
||||
Database::CheckoutLockGuard counterGuard(dbb, counterMutex);
|
||||
Attachment::CheckoutLockGuard counterGuard(att, counterMutex, true);
|
||||
|
||||
COS_TRACE(("(%p)->lockWrite stage 1 readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
|
||||
this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));
|
||||
@ -131,7 +130,7 @@ bool GlobalRWLock::lockWrite(thread_db* tdbb, SSHORT wait)
|
||||
|
||||
while (readers > 0 )
|
||||
{
|
||||
Database::Checkout checkoutDbb(dbb);
|
||||
Attachment::Checkout attCout(att, true);
|
||||
noReaders.wait(counterMutex);
|
||||
}
|
||||
|
||||
@ -140,7 +139,7 @@ bool GlobalRWLock::lockWrite(thread_db* tdbb, SSHORT wait)
|
||||
|
||||
while (currentWriter || pendingLock)
|
||||
{
|
||||
Database::Checkout checkoutDbb(dbb);
|
||||
Attachment::Checkout attCout(att, true);
|
||||
writerFinished.wait(counterMutex);
|
||||
}
|
||||
|
||||
@ -164,7 +163,7 @@ bool GlobalRWLock::lockWrite(thread_db* tdbb, SSHORT wait)
|
||||
|
||||
if (!LCK_lock(tdbb, cachedLock, LCK_write, wait))
|
||||
{
|
||||
Database::CheckoutLockGuard counterGuard(dbb, counterMutex);
|
||||
Attachment::CheckoutLockGuard counterGuard(att, counterMutex, true);
|
||||
--pendingLock;
|
||||
if (--pendingWriters)
|
||||
{
|
||||
@ -175,8 +174,7 @@ bool GlobalRWLock::lockWrite(thread_db* tdbb, SSHORT wait)
|
||||
}
|
||||
|
||||
{ // scope 2
|
||||
|
||||
Database::CheckoutLockGuard counterGuard(dbb, counterMutex);
|
||||
Attachment::CheckoutLockGuard counterGuard(att, counterMutex, true);
|
||||
|
||||
--pendingLock;
|
||||
--pendingWriters;
|
||||
@ -196,9 +194,8 @@ void GlobalRWLock::unlockWrite(thread_db* tdbb)
|
||||
{
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
|
||||
Database::CheckoutLockGuard counterGuard(dbb, counterMutex);
|
||||
Attachment* att = tdbb->getAttachment();
|
||||
Attachment::CheckoutLockGuard counterGuard(att, counterMutex, true);
|
||||
|
||||
COS_TRACE(("(%p)->unlockWrite readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
|
||||
this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));
|
||||
@ -225,12 +222,12 @@ bool GlobalRWLock::lockRead(thread_db* tdbb, SSHORT wait, const bool queueJump)
|
||||
{
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Attachment* att = tdbb->getAttachment();
|
||||
|
||||
bool needFetch;
|
||||
|
||||
{ // scope 1
|
||||
Database::CheckoutLockGuard counterGuard(dbb, counterMutex);
|
||||
Attachment::CheckoutLockGuard counterGuard(att, counterMutex, true);
|
||||
|
||||
COS_TRACE(("(%p)->lockRead stage 1 readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
|
||||
this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));
|
||||
@ -246,7 +243,7 @@ bool GlobalRWLock::lockRead(thread_db* tdbb, SSHORT wait, const bool queueJump)
|
||||
|
||||
while (pendingWriters > 0 || currentWriter)
|
||||
{
|
||||
Database::Checkout checkoutDbb(dbb);
|
||||
Attachment::Checkout attCout(att, true);
|
||||
writerFinished.wait(counterMutex);
|
||||
}
|
||||
|
||||
@ -256,9 +253,9 @@ bool GlobalRWLock::lockRead(thread_db* tdbb, SSHORT wait, const bool queueJump)
|
||||
if (!pendingLock)
|
||||
break;
|
||||
|
||||
counterMutex.leave();
|
||||
Database::Checkout checkoutDbb(dbb);
|
||||
counterMutex.enter();
|
||||
Firebird::MutexUnlockGuard cout(counterMutex);
|
||||
Attachment::Checkout attCout(att, true);
|
||||
THD_yield();
|
||||
}
|
||||
|
||||
needFetch = cachedLock->lck_physical < LCK_read;
|
||||
@ -275,14 +272,13 @@ bool GlobalRWLock::lockRead(thread_db* tdbb, SSHORT wait, const bool queueJump)
|
||||
|
||||
if (!LCK_lock(tdbb, cachedLock, LCK_read, wait))
|
||||
{
|
||||
Database::CheckoutLockGuard counterGuard(dbb, counterMutex);
|
||||
Attachment::CheckoutLockGuard counterGuard(att, counterMutex, true);
|
||||
--pendingLock;
|
||||
return false;
|
||||
}
|
||||
|
||||
{ // scope 2
|
||||
Database::CheckoutLockGuard counterGuard(dbb, counterMutex);
|
||||
|
||||
Attachment::CheckoutLockGuard counterGuard(att, counterMutex, true);
|
||||
--pendingLock;
|
||||
++readers;
|
||||
|
||||
@ -297,9 +293,8 @@ void GlobalRWLock::unlockRead(thread_db* tdbb)
|
||||
{
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
|
||||
Database::CheckoutLockGuard counterGuard(dbb, counterMutex);
|
||||
Attachment* att = tdbb->getAttachment();
|
||||
Attachment::CheckoutLockGuard counterGuard(att, counterMutex, true);
|
||||
|
||||
COS_TRACE(("(%p)->unlockRead readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
|
||||
this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));
|
||||
@ -321,7 +316,8 @@ void GlobalRWLock::unlockRead(thread_db* tdbb)
|
||||
|
||||
bool GlobalRWLock::tryReleaseLock(thread_db* tdbb)
|
||||
{
|
||||
Database::CheckoutLockGuard counterGuard(tdbb->getDatabase(), counterMutex);
|
||||
Attachment* att = tdbb->getAttachment();
|
||||
Attachment::CheckoutLockGuard counterGuard(att, counterMutex, true);
|
||||
|
||||
COS_TRACE(("(%p)->tryReleaseLock readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
|
||||
this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));
|
||||
|
@ -87,8 +87,9 @@ protected:
|
||||
|
||||
virtual void blockingAstHandler(thread_db* tdbb);
|
||||
|
||||
private:
|
||||
Firebird::Mutex counterMutex; // Protects counter and blocking flag
|
||||
|
||||
private:
|
||||
ULONG pendingLock;
|
||||
|
||||
ULONG readers;
|
||||
|
@ -288,8 +288,6 @@ jrd_req* JrdStatement::findRequest(thread_db* tdbb)
|
||||
if (!this)
|
||||
BUGCHECK(167); /* msg 167 invalid SEND request */
|
||||
|
||||
Database::CheckoutLockGuard guard(dbb, dbb->dbb_exe_clone_mutex);
|
||||
|
||||
// Search clones for one request in use by this attachment.
|
||||
// If not found, return first inactive request.
|
||||
|
||||
@ -539,7 +537,8 @@ void JrdStatement::release(thread_db* tdbb)
|
||||
|
||||
sqlText = NULL;
|
||||
|
||||
dbb->deletePool(pool);
|
||||
Jrd::Attachment* const att = tdbb->getAttachment();
|
||||
att->deletePool(pool);
|
||||
}
|
||||
|
||||
// Check that we have enough rights to access all resources this list of triggers touches.
|
||||
|
@ -137,10 +137,8 @@ RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, SLONG tran, bool alloc
|
||||
else
|
||||
inst_id = PAG_attachment_id(tdbb);
|
||||
|
||||
if (!rel_pages_inst)
|
||||
{
|
||||
MemoryPool& pool = *dbb->dbb_permanent;
|
||||
rel_pages_inst = FB_NEW(pool) RelationPagesInstances(pool);
|
||||
if (!rel_pages_inst) {
|
||||
rel_pages_inst = FB_NEW(*rel_pool) RelationPagesInstances(*rel_pool);
|
||||
}
|
||||
|
||||
size_t pos;
|
||||
@ -155,7 +153,7 @@ RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, SLONG tran, bool alloc
|
||||
const size_t BULK_ALLOC = 8;
|
||||
|
||||
RelationPages* allocatedPages = newPages =
|
||||
FB_NEW(*dbb->dbb_permanent) RelationPages[BULK_ALLOC];
|
||||
FB_NEW(*rel_pool) RelationPages[BULK_ALLOC];
|
||||
|
||||
rel_pages_free = ++allocatedPages;
|
||||
for (size_t i = 1; i < BULK_ALLOC - 1; i++, allocatedPages++)
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "../jrd/jrd.h"
|
||||
#include "../jrd/pag.h"
|
||||
#include "../jrd/val.h"
|
||||
#include "../jrd/Attachment.h"
|
||||
|
||||
namespace Jrd
|
||||
{
|
||||
@ -179,6 +180,7 @@ struct frgn
|
||||
class jrd_rel : public pool_alloc<type_rel>
|
||||
{
|
||||
public:
|
||||
MemoryPool* rel_pool;
|
||||
USHORT rel_id;
|
||||
USHORT rel_current_fmt; // Current format number
|
||||
ULONG rel_flags;
|
||||
@ -278,7 +280,7 @@ private:
|
||||
|
||||
public:
|
||||
explicit jrd_rel(MemoryPool& p)
|
||||
: rel_name(p), rel_owner_name(p), rel_view_contexts(p), rel_security_name(p)
|
||||
: rel_pool(&p), rel_name(p), rel_owner_name(p), rel_view_contexts(p), rel_security_name(p)
|
||||
{ }
|
||||
|
||||
bool hasTriggers() const;
|
||||
|
@ -226,7 +226,7 @@ void RuntimeStatistics::addRelCounts(const RelCounters& other, bool add)
|
||||
}
|
||||
}
|
||||
|
||||
PerformanceInfo* RuntimeStatistics::computeDifference(Database* dbb,
|
||||
PerformanceInfo* RuntimeStatistics::computeDifference(Attachment* att,
|
||||
const RuntimeStatistics& new_stat,
|
||||
PerformanceInfo& dest,
|
||||
TraceCountsArray& temp)
|
||||
@ -262,8 +262,8 @@ PerformanceInfo* RuntimeStatistics::computeDifference(Database* dbb,
|
||||
// Point TraceCounts to counts array from baseline object
|
||||
if (!all_zeros)
|
||||
{
|
||||
jrd_rel* relation = size_t(new_cnts->rlc_relation_id) < dbb->dbb_relations->count() ?
|
||||
(*dbb->dbb_relations)[new_cnts->rlc_relation_id] : NULL;
|
||||
jrd_rel* relation = size_t(new_cnts->rlc_relation_id) < att->att_relations->count() ?
|
||||
(*att->att_relations)[new_cnts->rlc_relation_id] : NULL;
|
||||
TraceCounts traceCounts;
|
||||
traceCounts.trc_relation_id = new_cnts->rlc_relation_id;
|
||||
traceCounts.trc_counters = base_cnts->rlc_counter;
|
||||
@ -276,8 +276,8 @@ PerformanceInfo* RuntimeStatistics::computeDifference(Database* dbb,
|
||||
}
|
||||
else
|
||||
{
|
||||
jrd_rel* relation = size_t(new_cnts->rlc_relation_id) < dbb->dbb_relations->count() ?
|
||||
(*dbb->dbb_relations)[new_cnts->rlc_relation_id] : NULL;
|
||||
jrd_rel* relation = size_t(new_cnts->rlc_relation_id) < att->att_relations->count() ?
|
||||
(*att->att_relations)[new_cnts->rlc_relation_id] : NULL;
|
||||
|
||||
// Point TraceCounts to counts array from object with updated counters
|
||||
TraceCounts traceCounts;
|
||||
|
@ -35,6 +35,7 @@ namespace Jrd {
|
||||
// #define REL_COUNTS_TREE
|
||||
// #define REL_COUNTS_PTR
|
||||
|
||||
class Attachment;
|
||||
class Database;
|
||||
|
||||
// Performance counters for individual table
|
||||
@ -135,7 +136,7 @@ public:
|
||||
|
||||
// Calculate difference between counts stored in this object and current
|
||||
// counts of given request. Counts stored in object are destroyed.
|
||||
PerformanceInfo* computeDifference(Database* dbb, const RuntimeStatistics& new_stat,
|
||||
PerformanceInfo* computeDifference(Attachment* att, const RuntimeStatistics& new_stat,
|
||||
PerformanceInfo& dest, TraceCountsArray& temp);
|
||||
|
||||
// bool operator==(const RuntimeStatistics& other) const;
|
||||
|
@ -45,7 +45,7 @@ USHORT ValueMover::getClientCharSet() const
|
||||
void ValueMover::getClientCharSetName(Firebird::MetaName& name) const
|
||||
{
|
||||
thread_db* tdbb = getThreadData();
|
||||
Database::SyncGuard dsGuard(tdbb->getDatabase());
|
||||
Attachment::SyncGuard attGuard(tdbb->getAttachment());
|
||||
|
||||
CharSet* cs = INTL_charset_lookup(tdbb, tdbb->getAttachment()->att_charset);
|
||||
name = cs->getName();
|
||||
@ -55,7 +55,7 @@ void ValueMover::getClientCharSetName(Firebird::MetaName& name) const
|
||||
int ValueMover::getMaxBytesPerChar(USHORT charSet) const
|
||||
{
|
||||
thread_db* tdbb = getThreadData();
|
||||
Database::SyncGuard dsGuard(tdbb->getDatabase());
|
||||
Attachment::SyncGuard attGuard(tdbb->getAttachment());
|
||||
|
||||
return DataTypeUtil(tdbb).maxBytesPerChar(charSet);
|
||||
}
|
||||
@ -76,7 +76,7 @@ const char* ValueMover::getString(const ValueImpl* value, const dsc* desc, MoveB
|
||||
*isNull = false;
|
||||
|
||||
thread_db* tdbb = getThreadData();
|
||||
Database::SyncGuard dsGuard(tdbb->getDatabase());
|
||||
Attachment::SyncGuard attGuard(tdbb->getAttachment());
|
||||
USHORT charSet = tdbb->getAttachment()->att_charset;
|
||||
|
||||
UCHAR* temp = NULL;
|
||||
@ -111,7 +111,7 @@ void ValueMover::getValue(const ValueImpl* value, const dsc* desc, dsc* target,
|
||||
*isNull = false;
|
||||
|
||||
thread_db* tdbb = getThreadData();
|
||||
Database::SyncGuard dsGuard(tdbb->getDatabase());
|
||||
Attachment::SyncGuard attGuard(tdbb->getAttachment());
|
||||
|
||||
MOV_move(tdbb, const_cast<dsc*>(desc), target);
|
||||
}
|
||||
@ -121,7 +121,7 @@ void ValueMover::getValue(const ValueImpl* value, const dsc* desc, dsc* target,
|
||||
void ValueMover::setValue(dsc* desc, USHORT* nullFlag, dsc* from) const
|
||||
{
|
||||
thread_db* tdbb = getThreadData();
|
||||
Database::SyncGuard dsGuard(tdbb->getDatabase());
|
||||
Attachment::SyncGuard attGuard(tdbb->getAttachment());
|
||||
|
||||
MOV_move(tdbb, from, desc);
|
||||
*nullFlag &= ~DSC_null;
|
||||
|
@ -1350,7 +1350,7 @@ blb* BLB_open2(thread_db* tdbb,
|
||||
// know about the relation, the blob id has got to be invalid
|
||||
// anyway.
|
||||
|
||||
vec<jrd_rel*>* vector = dbb->dbb_relations;
|
||||
vec<jrd_rel*>* vector = tdbb->getAttachment()->att_relations;
|
||||
|
||||
if (blob_id->bid_internal.bid_relation_id >= vector->count() ||
|
||||
!(blob->blb_relation = (*vector)[blob_id->bid_internal.bid_relation_id] ) )
|
||||
|
2224
src/jrd/cch.cpp
2224
src/jrd/cch.cpp
File diff suppressed because it is too large
Load Diff
206
src/jrd/cch.h
206
src/jrd/cch.h
@ -25,8 +25,10 @@
|
||||
#define JRD_CCH_H
|
||||
|
||||
#include "../include/fb_blk.h"
|
||||
#include "../jrd/os/pio.h"
|
||||
#include "../common/classes/alloc.h"
|
||||
#include "../common/classes/RefCounted.h"
|
||||
#include "../common/classes/semaphore.h"
|
||||
#include "../common/classes/SyncObject.h"
|
||||
#ifdef SUPERSERVER_V2
|
||||
#include "../jrd/sbm.h"
|
||||
#include "../jrd/pag.h"
|
||||
@ -78,27 +80,86 @@ struct bcb_repeat
|
||||
que bcb_page_mod; // Que of buffers with page mod n
|
||||
};
|
||||
|
||||
class BufferControl : public pool_alloc_rpt<bcb_repeat, type_bcb>
|
||||
class BufferControl : public pool_alloc<type_bcb>
|
||||
{
|
||||
explicit BufferControl(MemoryPool& p) :
|
||||
bcb_bufferpool(&p),
|
||||
bcb_memory(p)
|
||||
{
|
||||
bcb_database = NULL;
|
||||
QUE_INIT(bcb_in_use);
|
||||
QUE_INIT(bcb_pending);
|
||||
QUE_INIT(bcb_empty);
|
||||
QUE_INIT(bcb_dirty);
|
||||
bcb_dirty_count = 0;
|
||||
bcb_free = NULL;
|
||||
bcb_flags = 0;
|
||||
bcb_free_minimum = 0;
|
||||
bcb_count = 0;
|
||||
bcb_inuse = 0;
|
||||
bcb_checkpoint = 0;
|
||||
bcb_prec_walk_mark = 0;
|
||||
bcb_page_size = 0;
|
||||
bcb_page_incarnation = 0;
|
||||
#ifdef SUPERSERVER_V2
|
||||
bcb_prefetch = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
explicit BufferControl(MemoryPool& p) : bcb_memory(p) { }
|
||||
|
||||
static BufferControl* create();
|
||||
static void destroy(BufferControl*);
|
||||
|
||||
Firebird::MemoryPool* bcb_bufferpool;
|
||||
Firebird::MemoryStats bcb_memory_stats;
|
||||
|
||||
// To be deleted when PAG will be not coupled with Database.
|
||||
// Used only in CS mode when each BufferControl have one Database .
|
||||
Database* bcb_database;
|
||||
|
||||
UCharStack bcb_memory; // Large block partitioned into buffers
|
||||
que bcb_in_use; // Que of buffers in use
|
||||
que bcb_in_use; // Que of buffers in use, main LRU que
|
||||
que bcb_pending; // Que of buffers which are going to be freed and reassigned
|
||||
que bcb_empty; // Que of empty buffers
|
||||
|
||||
// Recently used buffer put there without locking common LRU que (bcb_in_use).
|
||||
// When bcb_syncLRU is locked this chain is merged into bcb_in_use. See also
|
||||
// requeueRecentlyUsed() and recentlyUsed()
|
||||
Firebird::AtomicPointer<BufferDesc> bcb_lru_chain;
|
||||
|
||||
que bcb_dirty; // que of dirty buffers
|
||||
SLONG bcb_dirty_count; // count of pages in dirty page btree
|
||||
|
||||
Precedence* bcb_free; // Free precedence blocks
|
||||
que bcb_free_lwt; // Free latch wait blocks
|
||||
que bcb_free_slt; // Free shared latch blocks
|
||||
SSHORT bcb_flags; // see below
|
||||
SSHORT bcb_free_minimum; // Threshold to activate cache writer
|
||||
ULONG bcb_count; // Number of buffers allocated
|
||||
ULONG bcb_inuse; // Number of buffers in use
|
||||
ULONG bcb_checkpoint; // Count of buffers to checkpoint
|
||||
ULONG bcb_prec_walk_mark; // mark value used in precedence graph walk
|
||||
ULONG bcb_page_size; // Database page size in bytes
|
||||
ULONG bcb_page_incarnation; // Cache page incarnation counter
|
||||
|
||||
Firebird::SyncObject bcb_syncObject;
|
||||
Firebird::SyncObject bcb_syncDirtyBdbs;
|
||||
Firebird::SyncObject bcb_syncPrecedence;
|
||||
Firebird::SyncObject bcb_syncLRU;
|
||||
//Firebird::SyncObject bcb_syncPageWrite;
|
||||
|
||||
Firebird::Semaphore bcb_writer_sem; // Wake up cache writer
|
||||
Firebird::Semaphore bcb_writer_init;// Cache writer initialization
|
||||
Firebird::Semaphore bcb_writer_fini;// Cache writer finalization
|
||||
#ifdef SUPERSERVER_V2
|
||||
// the code in cch.cpp is not tested for semaphore instead event !!!
|
||||
Firebird::Semaphore bcb_reader_sem; // Wake up cache reader
|
||||
Firebird::Semaphore bcb_reader_init;// Cache reader initialization
|
||||
Firebird::Semaphore bcb_reader_fini;// Cache reader finalization
|
||||
|
||||
PageBitmap* bcb_prefetch; // Bitmap of pages to prefetch
|
||||
#endif
|
||||
bcb_repeat bcb_rpt[1];
|
||||
|
||||
bcb_repeat* bcb_rpt;
|
||||
};
|
||||
|
||||
const int BCB_keep_pages = 1; // set during btc_flush(), pages not removed from dirty binary tree
|
||||
@ -110,66 +171,115 @@ const int BCB_cache_reader = 16; // cache reader thread has been started
|
||||
const int BCB_reader_active = 32; // cache reader not blocked on event
|
||||
#endif
|
||||
const int BCB_free_pending = 64; // request cache writer to free pages
|
||||
const int BCB_exclusive = 128; // there is only BCB in whole system
|
||||
|
||||
|
||||
// BufferDesc -- Buffer descriptor block
|
||||
|
||||
const int BDB_max_shared = 20; // maximum number of shared latch owners per BufferDesc
|
||||
|
||||
class BufferDesc : public pool_alloc<type_bdb>
|
||||
{
|
||||
public:
|
||||
BufferDesc() : bdb_page(0, 0) {}
|
||||
BufferDesc(BufferControl* bcb) :
|
||||
bdb_bcb(bcb),
|
||||
bdb_page(0, 0),
|
||||
bdb_pending_page(0, 0)
|
||||
{
|
||||
bdb_lock = NULL;
|
||||
QUE_INIT(bdb_que);
|
||||
QUE_INIT(bdb_in_use);
|
||||
QUE_INIT(bdb_dirty);
|
||||
bdb_buffer = NULL;
|
||||
bdb_incarnation = 0;
|
||||
bdb_transactions = 0;
|
||||
bdb_mark_transaction = 0;
|
||||
QUE_INIT(bdb_lower);
|
||||
QUE_INIT(bdb_higher);
|
||||
bdb_exclusive = NULL;
|
||||
bdb_io = NULL;
|
||||
bdb_writers = 0;
|
||||
bdb_scan_count = 0;
|
||||
bdb_difference_page = 0;
|
||||
bdb_prec_walk_mark = 0;
|
||||
}
|
||||
|
||||
Database* bdb_dbb; // Database block (for ASTs)
|
||||
void addRef(thread_db* tdbb, Firebird::SyncType syncType);
|
||||
bool addRefConditional(thread_db* tdbb, Firebird::SyncType syncType);
|
||||
void downgrade(Firebird::SyncType syncType);
|
||||
void release(thread_db* tdbb);
|
||||
|
||||
void lockIO(thread_db*);
|
||||
void unLockIO(thread_db*);
|
||||
|
||||
bool isLocked() const
|
||||
{
|
||||
return bdb_syncPage.isLocked();
|
||||
}
|
||||
|
||||
bool ourExclusiveLock() const
|
||||
{
|
||||
return bdb_syncPage.ourExclusiveLock();
|
||||
}
|
||||
|
||||
bool ourIOLock() const
|
||||
{
|
||||
return bdb_syncIO.ourExclusiveLock();
|
||||
}
|
||||
|
||||
BufferControl* bdb_bcb;
|
||||
Firebird::SyncObject bdb_syncPage;
|
||||
Lock* bdb_lock; // Lock block for buffer
|
||||
que bdb_que; // Buffer que
|
||||
que bdb_que; // Either mod que in hash table or bcb_pending que if BDB_free_pending flag is set
|
||||
que bdb_in_use; // queue of buffers in use
|
||||
que bdb_dirty; // dirty pages LRU queue
|
||||
BufferDesc* bdb_lru_chain; // pending LRU chain
|
||||
Ods::pag* bdb_buffer; // Actual buffer
|
||||
PageNumber bdb_page; // Database page number in buffer
|
||||
SLONG bdb_incarnation;
|
||||
PageNumber bdb_pending_page; // Database page number to be
|
||||
ULONG bdb_incarnation;
|
||||
ULONG bdb_transactions; // vector of dirty flags to reduce commit overhead
|
||||
SLONG bdb_mark_transaction; // hi-water mark transaction to defer header page I/O
|
||||
que bdb_lower; // lower precedence que
|
||||
que bdb_higher; // higher precedence que
|
||||
que bdb_waiters; // latch wait que
|
||||
thread_db* bdb_exclusive; // thread holding exclusive latch
|
||||
private:
|
||||
thread_db* bdb_io; // thread holding io latch
|
||||
ULONG bdb_ast_flags; // flags manipulated at AST level
|
||||
USHORT bdb_flags;
|
||||
SSHORT bdb_use_count; // Number of active users
|
||||
Firebird::SyncObject bdb_syncIO;
|
||||
public:
|
||||
Firebird::AtomicCounter bdb_ast_flags; // flags manipulated at AST level
|
||||
Firebird::AtomicCounter bdb_flags;
|
||||
Firebird::AtomicCounter bdb_use_count; // Number of active users
|
||||
SSHORT bdb_writers; // Number of recursively taken exclusive locks
|
||||
SSHORT bdb_io_locks; // Number of recursively taken IO locks
|
||||
SSHORT bdb_scan_count; // concurrent sequential scans
|
||||
ULONG bdb_difference_page; // Number of page in difference file, NBAK
|
||||
ULONG bdb_prec_walk_mark; // mark value used in precedence graph walk
|
||||
que bdb_shared; // shared latches queue
|
||||
};
|
||||
|
||||
// bdb_flags
|
||||
|
||||
// to set/clear BDB_dirty use set_dirty_flag()/clear_dirty_flag()
|
||||
// These constants should really be of type USHORT.
|
||||
const int BDB_dirty = 1; // page has been updated but not written yet
|
||||
const int BDB_garbage_collect = 2; // left by scan for garbage collector
|
||||
const int BDB_writer = 4; // someone is updating the page
|
||||
const int BDB_marked = 8; // page has been updated
|
||||
const int BDB_must_write = 16; // forces a write as soon as the page is released
|
||||
const int BDB_faked = 32; // page was just allocated
|
||||
//const int BDB_merge = 64;
|
||||
const int BDB_system_dirty = 128; // system transaction has marked dirty
|
||||
const int BDB_io_error = 256; // page i/o error
|
||||
const int BDB_read_pending = 512; // read is pending
|
||||
const int BDB_free_pending = 1024; // buffer being freed for reuse
|
||||
const int BDB_not_valid = 2048; // i/o error invalidated buffer
|
||||
const int BDB_db_dirty = 4096; // page must be written to database
|
||||
const int BDB_checkpoint = 8192; // page must be written by next checkpoint
|
||||
const int BDB_prefetch = 16384; // page has been prefetched but not yet referenced
|
||||
const int BDB_no_blocking_ast = 32768; // No blocking AST registered with page lock
|
||||
// CVC: There's no more room for flags unless you change bdb_flags from USHORT to ULONG.
|
||||
const int BDB_dirty = 0x0001; // page has been updated but not written yet
|
||||
const int BDB_garbage_collect = 0x0002; // left by scan for garbage collector
|
||||
const int BDB_writer = 0x0004; // someone is updating the page
|
||||
const int BDB_marked = 0x0008; // page has been updated
|
||||
const int BDB_must_write = 0x0010; // forces a write as soon as the page is released
|
||||
const int BDB_faked = 0x0020; // page was just allocated
|
||||
//const int BDB_merge = 0x0040;
|
||||
const int BDB_system_dirty = 0x0080; // system transaction has marked dirty
|
||||
const int BDB_io_error = 0x0100; // page i/o error
|
||||
const int BDB_read_pending = 0x0200; // read is pending
|
||||
const int BDB_free_pending = 0x0400; // buffer being freed for reuse
|
||||
const int BDB_not_valid = 0x0800; // i/o error invalidated buffer
|
||||
const int BDB_db_dirty = 0x1000; // page must be written to database
|
||||
const int BDB_checkpoint = 0x2000; // page must be written by next checkpoint
|
||||
const int BDB_prefetch = 0x4000; // page has been prefetched but not yet referenced
|
||||
const int BDB_no_blocking_ast = 0x8000; // No blocking AST registered with page lock
|
||||
const int BDB_lru_chained = 0x10000; // buffer is in pending LRU chain
|
||||
|
||||
// bdb_ast_flags
|
||||
|
||||
const ULONG BDB_blocking = 1; // a blocking ast was sent while page locked
|
||||
const int BDB_blocking = 0x01; // a blocking ast was sent while page locked
|
||||
|
||||
|
||||
// PRE -- Precedence block
|
||||
@ -221,29 +331,6 @@ enum LATCH
|
||||
LATCH_mark
|
||||
};
|
||||
|
||||
// LWT -- Latch wait block
|
||||
|
||||
class LatchWait : public pool_alloc<type_lwt>
|
||||
{
|
||||
public:
|
||||
thread_db* lwt_tdbb;
|
||||
LATCH lwt_latch; // latch type requested
|
||||
que lwt_waiters; // latch queue
|
||||
Firebird::Semaphore lwt_sem; // grant event to wait on
|
||||
USHORT lwt_flags;
|
||||
};
|
||||
|
||||
const int LWT_pending = 1; // latch request is pending
|
||||
|
||||
// Shared Latch
|
||||
class SharedLatch
|
||||
{
|
||||
public:
|
||||
thread_db* slt_tdbb; // thread holding latch
|
||||
BufferDesc* slt_bdb; // buffer for which is this latch
|
||||
que slt_tdbb_que; // thread's latches queue
|
||||
que slt_bdb_que; // buffer's latches queue
|
||||
};
|
||||
|
||||
|
||||
#ifdef SUPERSERVER_V2
|
||||
@ -277,6 +364,7 @@ const int PRF_active = 1; // prefetch block currently in use
|
||||
|
||||
typedef Firebird::SortedArray<SLONG, Firebird::InlineStorage<SLONG, 256>, SLONG> PagesArray;
|
||||
|
||||
|
||||
} //namespace Jrd
|
||||
|
||||
#endif // JRD_CCH_H
|
||||
|
@ -28,29 +28,37 @@ namespace Ods {
|
||||
struct pag;
|
||||
}
|
||||
|
||||
enum LockState {
|
||||
lsLatchTimeout = -2, // was -2 *** now unused ***
|
||||
lsLockTimeout, // was -1
|
||||
lsLockedHavePage, // was 0
|
||||
lsLocked, // was 1
|
||||
lsError
|
||||
};
|
||||
|
||||
void CCH_shutdown_database(Jrd::Database*);
|
||||
|
||||
int CCH_down_grade_dbb(void*);
|
||||
bool CCH_exclusive(Jrd::thread_db*, USHORT, SSHORT);
|
||||
bool CCH_exclusive_attachment(Jrd::thread_db*, USHORT, SSHORT);
|
||||
void CCH_expand(Jrd::thread_db*, ULONG);
|
||||
Ods::pag* CCH_fake(Jrd::thread_db*, Jrd::win*, SSHORT);
|
||||
Ods::pag* CCH_fetch(Jrd::thread_db*, Jrd::win*, USHORT, SCHAR, SSHORT, const bool);
|
||||
SSHORT CCH_fetch_lock(Jrd::thread_db*, Jrd::win*, USHORT, SSHORT, SCHAR);
|
||||
Ods::pag* CCH_fake(Jrd::thread_db*, Jrd::win*, int);
|
||||
Ods::pag* CCH_fetch(Jrd::thread_db*, Jrd::win*, int, SCHAR, int, const bool);
|
||||
LockState CCH_fetch_lock(Jrd::thread_db*, Jrd::win*, int, int, SCHAR);
|
||||
void CCH_fetch_page(Jrd::thread_db*, Jrd::win*, const bool);
|
||||
void CCH_forget_page(Jrd::thread_db*, Jrd::win*);
|
||||
void CCH_fini(Jrd::thread_db*);
|
||||
void CCH_forget_page(Jrd::thread_db*, Jrd::win*);
|
||||
void CCH_flush(Jrd::thread_db*, USHORT, SLONG);
|
||||
bool CCH_free_page(Jrd::thread_db*);
|
||||
SLONG CCH_get_incarnation(Jrd::win*);
|
||||
void CCH_get_related(Jrd::thread_db*, Jrd::PageNumber, Jrd::PagesArray&);
|
||||
Ods::pag* CCH_handoff(Jrd::thread_db*, Jrd::win*, ULONG, SSHORT, SCHAR, SSHORT, const bool);
|
||||
void CCH_init(Jrd::thread_db*, ULONG);
|
||||
void CCH_mark(Jrd::thread_db*, Jrd::win*, USHORT, USHORT);
|
||||
void CCH_must_write(Jrd::win*);
|
||||
Ods::pag* CCH_handoff(Jrd::thread_db*, Jrd::win*, ULONG, int, SCHAR, int, const bool);
|
||||
void CCH_init(Jrd::thread_db*, ULONG, bool);
|
||||
void CCH_mark(Jrd::thread_db*, Jrd::win*, bool, bool);
|
||||
void CCH_must_write(Jrd::thread_db*, Jrd::win*);
|
||||
void CCH_precedence(Jrd::thread_db*, Jrd::win*, ULONG);
|
||||
void CCH_tra_precedence(Jrd::thread_db*, Jrd::win*, SLONG);
|
||||
void CCH_precedence(Jrd::thread_db*, Jrd::win*, Jrd::PageNumber);
|
||||
void CCH_tra_precedence(Jrd::thread_db*, Jrd::win*, SLONG);
|
||||
#ifdef SUPERSERVER_V2
|
||||
void CCH_prefetch(Jrd::thread_db*, SLONG*, SSHORT);
|
||||
bool CCH_prefetch_pages(Jrd::thread_db*);
|
||||
@ -81,16 +89,6 @@ inline Ods::pag* CCH_FETCH_TIMEOUT(Jrd::thread_db* tdbb, Jrd::win* window, USHOR
|
||||
return CCH_fetch (tdbb, window, lock_type, page_type, latch_wait, true);
|
||||
}
|
||||
|
||||
inline SSHORT CCH_FETCH_LOCK(Jrd::thread_db* tdbb, Jrd::win* window, USHORT lock_type, SSHORT wait, SCHAR page_type)
|
||||
{
|
||||
return CCH_fetch_lock(tdbb, window, lock_type, wait, page_type);
|
||||
}
|
||||
|
||||
inline void CCH_FETCH_PAGE(Jrd::thread_db* tdbb, Jrd::win* window, bool read_shadow)
|
||||
{
|
||||
CCH_fetch_page(tdbb, window, read_shadow);
|
||||
}
|
||||
|
||||
inline void CCH_RELEASE(Jrd::thread_db* tdbb, Jrd::win* window)
|
||||
{
|
||||
CCH_release(tdbb, window, false);
|
||||
|
104
src/jrd/cmp.cpp
104
src/jrd/cmp.cpp
@ -163,10 +163,11 @@ jrd_req* CMP_compile2(thread_db* tdbb, const UCHAR* blr, ULONG blr_length, bool
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* const att = tdbb->getAttachment();
|
||||
|
||||
// 26.09.2002 Nickolay Samofatov: default memory pool will become statement pool
|
||||
// and will be freed by CMP_release
|
||||
MemoryPool* const new_pool = dbb->createPool();
|
||||
MemoryPool* const new_pool = att->createPool();
|
||||
|
||||
try
|
||||
{
|
||||
@ -208,7 +209,7 @@ jrd_req* CMP_compile2(thread_db* tdbb, const UCHAR* blr, ULONG blr_length, bool
|
||||
if (request)
|
||||
CMP_release(tdbb, request);
|
||||
else
|
||||
dbb->deletePool(new_pool);
|
||||
att->deletePool(new_pool);
|
||||
ERR_punt();
|
||||
}
|
||||
|
||||
@ -254,22 +255,6 @@ void CMP_fini(thread_db* tdbb)
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
|
||||
CMP_shutdown_database(tdbb); // Shutdown shared database locks.
|
||||
|
||||
// And release the system requests.
|
||||
|
||||
fb_assert(tdbb->getAttachment() == NULL);
|
||||
|
||||
for (JrdStatement** itr = dbb->dbb_internal.begin(); itr != dbb->dbb_internal.end(); ++itr)
|
||||
{
|
||||
if (*itr)
|
||||
(*itr)->release(tdbb);
|
||||
}
|
||||
|
||||
for (JrdStatement** itr = dbb->dbb_dyn_req.begin(); itr != dbb->dbb_dyn_req.end(); ++itr)
|
||||
{
|
||||
if (*itr)
|
||||
(*itr)->release(tdbb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -343,14 +328,14 @@ IndexLock* CMP_get_index_lock(thread_db* tdbb, jrd_rel* relation, USHORT id)
|
||||
}
|
||||
}
|
||||
|
||||
IndexLock* index = FB_NEW(*dbb->dbb_permanent) IndexLock();
|
||||
IndexLock* index = FB_NEW(*relation->rel_pool) IndexLock();
|
||||
index->idl_next = relation->rel_index_locks;
|
||||
relation->rel_index_locks = index;
|
||||
index->idl_relation = relation;
|
||||
index->idl_id = id;
|
||||
index->idl_count = 0;
|
||||
|
||||
Lock* lock = FB_NEW_RPT(*dbb->dbb_permanent, 0) Lock;
|
||||
Lock* lock = FB_NEW_RPT(*relation->rel_pool, 0) Lock;
|
||||
index->idl_lock = lock;
|
||||
lock->lck_parent = dbb->dbb_lock;
|
||||
lock->lck_dbb = dbb;
|
||||
@ -519,7 +504,7 @@ void CMP_decrement_prc_use_count(thread_db* tdbb, jrd_prc* procedure)
|
||||
// The procedure will be different than in dbb_procedures only if it is a
|
||||
// floating copy, i.e. an old copy or a deleted procedure.
|
||||
if ((procedure->prc_use_count == 0) &&
|
||||
( (*tdbb->getDatabase()->dbb_procedures)[procedure->getId()] != procedure))
|
||||
( (*tdbb->getAttachment()->att_procedures)[procedure->getId()] != procedure))
|
||||
{
|
||||
if (procedure->getStatement())
|
||||
{
|
||||
@ -568,83 +553,6 @@ void CMP_shutdown_database(thread_db* tdbb)
|
||||
CHECK_DBB(dbb);
|
||||
|
||||
DEV_BLKCHK(dbb, type_dbb);
|
||||
|
||||
// go through relations and indices and release
|
||||
// all existence locks that might have been taken
|
||||
|
||||
vec<jrd_rel*>* rvector = dbb->dbb_relations;
|
||||
if (rvector)
|
||||
{
|
||||
vec<jrd_rel*>::iterator ptr, end;
|
||||
for (ptr = rvector->begin(), end = rvector->end(); ptr < end; ++ptr)
|
||||
{
|
||||
jrd_rel* relation = *ptr;
|
||||
if (relation)
|
||||
{
|
||||
if (relation->rel_existence_lock)
|
||||
{
|
||||
LCK_release(tdbb, relation->rel_existence_lock);
|
||||
relation->rel_flags |= REL_check_existence;
|
||||
relation->rel_use_count = 0;
|
||||
}
|
||||
if (relation->rel_partners_lock)
|
||||
{
|
||||
LCK_release(tdbb, relation->rel_partners_lock);
|
||||
relation->rel_flags |= REL_check_partners;
|
||||
}
|
||||
if (relation->rel_rescan_lock)
|
||||
{
|
||||
LCK_release(tdbb, relation->rel_rescan_lock);
|
||||
relation->rel_flags &= ~REL_scanned;
|
||||
}
|
||||
for (IndexLock* index = relation->rel_index_locks; index; index = index->idl_next)
|
||||
{
|
||||
if (index->idl_lock)
|
||||
{
|
||||
index->idl_count = 0;
|
||||
LCK_release(tdbb, index->idl_lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// release all procedure existence locks that might have been taken
|
||||
|
||||
vec<jrd_prc*>* pvector = dbb->dbb_procedures;
|
||||
if (pvector)
|
||||
{
|
||||
vec<jrd_prc*>::iterator pptr, pend;
|
||||
for (pptr = pvector->begin(), pend = pvector->end(); pptr < pend; ++pptr)
|
||||
{
|
||||
jrd_prc* procedure = *pptr;
|
||||
if (procedure)
|
||||
{
|
||||
if (procedure->prc_existence_lock)
|
||||
{
|
||||
LCK_release(tdbb, procedure->prc_existence_lock);
|
||||
procedure->prc_flags |= PRC_check_existence;
|
||||
procedure->prc_use_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// release all function existence locks that might have been taken
|
||||
|
||||
for (Function** iter = dbb->dbb_functions.begin(); iter < dbb->dbb_functions.end(); ++iter)
|
||||
{
|
||||
Function* const function = *iter;
|
||||
|
||||
if (function)
|
||||
{
|
||||
function->releaseLocks(tdbb);
|
||||
}
|
||||
}
|
||||
|
||||
// release collation existence locks
|
||||
|
||||
dbb->releaseIntlObjects();
|
||||
}
|
||||
|
||||
|
||||
|
@ -2934,12 +2934,12 @@ static bool create_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr
|
||||
if ((arg->dfw_id & TRIGGER_TYPE_MASK) == TRIGGER_TYPE_DB)
|
||||
{
|
||||
MET_load_trigger(tdbb, NULL, work->dfw_name,
|
||||
&tdbb->getDatabase()->dbb_triggers[arg->dfw_id & ~TRIGGER_TYPE_DB]);
|
||||
&tdbb->getAttachment()->att_triggers[arg->dfw_id & ~TRIGGER_TYPE_DB]);
|
||||
}
|
||||
else if ((arg->dfw_id & TRIGGER_TYPE_MASK) == TRIGGER_TYPE_DDL)
|
||||
{
|
||||
MET_load_trigger(tdbb, NULL, work->dfw_name,
|
||||
&tdbb->getDatabase()->dbb_ddl_triggers);
|
||||
&tdbb->getAttachment()->att_ddl_triggers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3264,13 +3264,13 @@ static bool create_field(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_
|
||||
|
||||
if (!validation.isEmpty())
|
||||
{
|
||||
MemoryPool* new_pool = dbb->createPool();
|
||||
MemoryPool* new_pool = attachment->createPool();
|
||||
Jrd::ContextPoolHolder context(tdbb, new_pool);
|
||||
|
||||
MET_get_dependencies(tdbb, NULL, NULL, 0, NULL, &validation,
|
||||
NULL, NULL, depName, obj_validation, 0, transaction, depName);
|
||||
|
||||
dbb->deletePool(new_pool);
|
||||
attachment->deletePool(new_pool);
|
||||
}
|
||||
}
|
||||
// fall through
|
||||
@ -3428,13 +3428,13 @@ static bool modify_field(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_
|
||||
|
||||
if (!validation.isEmpty())
|
||||
{
|
||||
MemoryPool* new_pool = dbb->createPool();
|
||||
MemoryPool* new_pool = attachment->createPool();
|
||||
Jrd::ContextPoolHolder context(tdbb, new_pool);
|
||||
|
||||
MET_get_dependencies(tdbb, NULL, NULL, 0, NULL, &validation,
|
||||
NULL, NULL, depName, obj_validation, 0, transaction, depName);
|
||||
|
||||
dbb->deletePool(new_pool);
|
||||
attachment->deletePool(new_pool);
|
||||
}
|
||||
}
|
||||
// fall through
|
||||
@ -3510,8 +3510,8 @@ static void check_partners(thread_db* tdbb, const USHORT rel_id)
|
||||
* Used when FK index was dropped
|
||||
*
|
||||
**************************************/
|
||||
const Database* dbb = tdbb->getDatabase();
|
||||
vec<jrd_rel*>* relations = dbb->dbb_relations;
|
||||
const Jrd::Attachment* att = tdbb->getAttachment();
|
||||
vec<jrd_rel*>* relations = att->att_relations;
|
||||
|
||||
fb_assert(relations);
|
||||
fb_assert(rel_id < relations->count());
|
||||
@ -3619,7 +3619,8 @@ static bool delete_function(thread_db* tdbb, SSHORT phase, DeferredWork* work, j
|
||||
LCK_release(tdbb, function->fun_existence_lock);
|
||||
}
|
||||
|
||||
dbb->dbb_functions[function->getId()] = NULL;
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
attachment->att_functions[function->getId()] = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -3978,7 +3979,7 @@ static bool delete_procedure(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
if (procedure->prc_existence_lock) {
|
||||
LCK_release(tdbb, procedure->prc_existence_lock);
|
||||
}
|
||||
(*tdbb->getDatabase()->dbb_procedures)[procedure->getId()] = NULL;
|
||||
(*tdbb->getAttachment()->att_procedures)[procedure->getId()] = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -4127,9 +4128,8 @@ static bool delete_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, j
|
||||
// garbage collector threads working on relation can skip over it
|
||||
|
||||
relation->rel_flags |= REL_deleting;
|
||||
|
||||
{ // scope
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
Jrd::Attachment::Checkout attCout(attachment);
|
||||
relation->rel_drop_mutex.enter();
|
||||
}
|
||||
|
||||
@ -4156,7 +4156,7 @@ static bool delete_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, j
|
||||
break;
|
||||
}
|
||||
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
Jrd::Attachment::Checkout attCout(attachment);
|
||||
THREAD_SLEEP(1 * 1000);
|
||||
}
|
||||
|
||||
@ -4440,7 +4440,7 @@ static bool delete_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr
|
||||
if (arg && (arg->dfw_id & TRIGGER_TYPE_MASK) == TRIGGER_TYPE_DB)
|
||||
{
|
||||
MET_release_trigger(tdbb,
|
||||
&tdbb->getDatabase()->dbb_triggers[arg->dfw_id & ~TRIGGER_TYPE_DB],
|
||||
&tdbb->getAttachment()->att_triggers[arg->dfw_id & ~TRIGGER_TYPE_DB],
|
||||
work->dfw_name);
|
||||
}
|
||||
}
|
||||
@ -4689,7 +4689,7 @@ static void get_function_dependencies(DeferredWork* work, bool compile, jrd_tra*
|
||||
{
|
||||
JrdStatement* statement = NULL;
|
||||
|
||||
MemoryPool* const new_pool = dbb->createPool();
|
||||
MemoryPool* const new_pool = attachment->createPool();
|
||||
Jrd::ContextPoolHolder context(tdbb, new_pool);
|
||||
|
||||
const Firebird::MetaName depName(work->dfw_package.isEmpty() ?
|
||||
@ -4703,7 +4703,7 @@ static void get_function_dependencies(DeferredWork* work, bool compile, jrd_tra*
|
||||
if (statement)
|
||||
statement->release(tdbb);
|
||||
else
|
||||
dbb->deletePool(new_pool);
|
||||
attachment->deletePool(new_pool);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4756,7 +4756,7 @@ static void get_procedure_dependencies(DeferredWork* work, bool compile, jrd_tra
|
||||
{
|
||||
JrdStatement* statement = NULL;
|
||||
// Nickolay Samofatov: allocate statement memory pool...
|
||||
MemoryPool* new_pool = dbb->createPool();
|
||||
MemoryPool* new_pool = attachment->createPool();
|
||||
// block is used to ensure MET_verify_cache
|
||||
// works in not deleted context
|
||||
{
|
||||
@ -4772,7 +4772,7 @@ static void get_procedure_dependencies(DeferredWork* work, bool compile, jrd_tra
|
||||
if (statement)
|
||||
statement->release(tdbb);
|
||||
else
|
||||
dbb->deletePool(new_pool);
|
||||
attachment->deletePool(new_pool);
|
||||
}
|
||||
|
||||
#ifdef DEV_BUILD
|
||||
@ -4827,7 +4827,7 @@ static void get_trigger_dependencies(DeferredWork* work, bool compile, jrd_tra*
|
||||
{
|
||||
JrdStatement* statement = NULL;
|
||||
// Nickolay Samofatov: allocate statement memory pool...
|
||||
MemoryPool* new_pool = dbb->createPool();
|
||||
MemoryPool* new_pool = attachment->createPool();
|
||||
const USHORT par_flags = (USHORT) (type & 1) ? csb_pre_trigger : csb_post_trigger;
|
||||
|
||||
Jrd::ContextPoolHolder context(tdbb, new_pool);
|
||||
@ -4838,7 +4838,7 @@ static void get_trigger_dependencies(DeferredWork* work, bool compile, jrd_tra*
|
||||
if (statement)
|
||||
statement->release(tdbb);
|
||||
else
|
||||
dbb->deletePool(new_pool);
|
||||
attachment->deletePool(new_pool);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4994,7 +4994,7 @@ static Format* make_format(thread_db* tdbb, jrd_rel* relation, USHORT* version,
|
||||
// Link the format block into the world
|
||||
|
||||
vec<Format*>* vector = relation->rel_formats =
|
||||
vec<Format*>::newVector(*dbb->dbb_permanent, relation->rel_formats, format->fmt_version + 1);
|
||||
vec<Format*>::newVector(*relation->rel_pool, relation->rel_formats, format->fmt_version + 1);
|
||||
(*vector)[format->fmt_version] = format;
|
||||
|
||||
// Store format in system relation
|
||||
@ -5282,7 +5282,7 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_
|
||||
|
||||
if (notNull && !defaultValue->isEmpty())
|
||||
{
|
||||
Jrd::ContextPoolHolder context(tdbb, dbb->createPool());
|
||||
Jrd::ContextPoolHolder context(tdbb, attachment->createPool());
|
||||
JrdStatement* defaultStatement = NULL;
|
||||
try
|
||||
{
|
||||
@ -5502,6 +5502,7 @@ static bool modify_function(thread_db* tdbb, SSHORT phase, DeferredWork* work, j
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
|
||||
const QualifiedName name(work->dfw_name, work->dfw_package);
|
||||
|
||||
@ -5561,7 +5562,6 @@ static bool modify_function(thread_db* tdbb, SSHORT phase, DeferredWork* work, j
|
||||
}
|
||||
|
||||
{ // guard scope
|
||||
Database::CheckoutLockGuard guard(dbb, dbb->dbb_meta_mutex);
|
||||
|
||||
// Do not allow to modify function used by user requests
|
||||
if (function->isUsed())
|
||||
@ -5580,7 +5580,8 @@ static bool modify_function(thread_db* tdbb, SSHORT phase, DeferredWork* work, j
|
||||
LCK_release(tdbb, function->fun_existence_lock);
|
||||
}
|
||||
|
||||
dbb->dbb_functions[function->getId()] = NULL;
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
attachment->att_functions[function->getId()] = NULL;
|
||||
|
||||
if (!(function = Function::lookup(tdbb, work->dfw_id, false,
|
||||
true, FUN_being_altered)))
|
||||
@ -5650,7 +5651,7 @@ static bool modify_function(thread_db* tdbb, SSHORT phase, DeferredWork* work, j
|
||||
{
|
||||
bool valid_blr = false;
|
||||
|
||||
MemoryPool* const csb_pool = dbb->createPool();
|
||||
MemoryPool* const csb_pool = attachment->createPool();
|
||||
Jrd::ContextPoolHolder context(tdbb, csb_pool);
|
||||
|
||||
try
|
||||
@ -5669,11 +5670,11 @@ static bool modify_function(thread_db* tdbb, SSHORT phase, DeferredWork* work, j
|
||||
}
|
||||
catch (const Firebird::Exception&)
|
||||
{
|
||||
dbb->deletePool(csb_pool);
|
||||
attachment->deletePool(csb_pool);
|
||||
throw;
|
||||
}
|
||||
|
||||
dbb->deletePool(csb_pool);
|
||||
attachment->deletePool(csb_pool);
|
||||
|
||||
MODIFY FUN USING
|
||||
FUN.RDB$VALID_BLR = valid_blr ? TRUE : FALSE;
|
||||
@ -5705,6 +5706,7 @@ static bool modify_procedure(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
const QualifiedName name(work->dfw_name, work->dfw_package);
|
||||
|
||||
switch (phase)
|
||||
@ -5758,7 +5760,6 @@ static bool modify_procedure(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
}
|
||||
|
||||
{ // guard scope
|
||||
Database::CheckoutLockGuard guard(dbb, dbb->dbb_meta_mutex);
|
||||
|
||||
// Do not allow to modify procedure used by user requests
|
||||
if (procedure->prc_use_count && MET_procedure_in_use(tdbb, procedure))
|
||||
@ -5782,7 +5783,7 @@ static bool modify_procedure(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
if (procedure->prc_existence_lock) {
|
||||
LCK_release(tdbb, procedure->prc_existence_lock);
|
||||
}
|
||||
(*tdbb->getDatabase()->dbb_procedures)[procedure->getId()] = NULL;
|
||||
(*tdbb->getAttachment()->att_procedures)[procedure->getId()] = NULL;
|
||||
|
||||
if (!(procedure = MET_lookup_procedure_id(tdbb, work->dfw_id, false,
|
||||
true, PRC_being_altered)))
|
||||
@ -5843,7 +5844,7 @@ static bool modify_procedure(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
{
|
||||
SSHORT valid_blr = FALSE;
|
||||
|
||||
MemoryPool* new_pool = dbb->createPool();
|
||||
MemoryPool* new_pool = attachment->createPool();
|
||||
try
|
||||
{
|
||||
Jrd::ContextPoolHolder context(tdbb, new_pool);
|
||||
@ -5857,7 +5858,7 @@ static bool modify_procedure(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
fb_utils::init_status(tdbb->tdbb_status_vector);
|
||||
}
|
||||
|
||||
dbb->deletePool(new_pool);
|
||||
attachment->deletePool(new_pool);
|
||||
|
||||
AutoCacheRequest request(tdbb, irq_prc_validate, IRQ_REQUESTS);
|
||||
|
||||
@ -5895,6 +5896,7 @@ static bool modify_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
|
||||
switch (phase)
|
||||
{
|
||||
@ -5924,11 +5926,11 @@ static bool modify_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr
|
||||
if (arg && (arg->dfw_id & TRIGGER_TYPE_MASK) == TRIGGER_TYPE_DB)
|
||||
{
|
||||
MET_release_trigger(tdbb,
|
||||
&tdbb->getDatabase()->dbb_triggers[arg->dfw_id & ~TRIGGER_TYPE_DB],
|
||||
&tdbb->getAttachment()->att_triggers[arg->dfw_id & ~TRIGGER_TYPE_DB],
|
||||
work->dfw_name);
|
||||
|
||||
MET_load_trigger(tdbb, NULL, work->dfw_name,
|
||||
&tdbb->getDatabase()->dbb_triggers[arg->dfw_id & ~TRIGGER_TYPE_DB]);
|
||||
&tdbb->getAttachment()->att_triggers[arg->dfw_id & ~TRIGGER_TYPE_DB]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5955,7 +5957,7 @@ static bool modify_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr
|
||||
for (int i = 0; i < TRIGGER_MAX; ++i)
|
||||
triggers[i] = NULL;
|
||||
|
||||
MemoryPool* new_pool = dbb->createPool();
|
||||
MemoryPool* new_pool = attachment->createPool();
|
||||
try
|
||||
{
|
||||
Jrd::ContextPoolHolder context(tdbb, new_pool);
|
||||
@ -5977,7 +5979,7 @@ static bool modify_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr
|
||||
}
|
||||
catch (const Firebird::Exception&)
|
||||
{
|
||||
dbb->deletePool(new_pool);
|
||||
attachment->deletePool(new_pool);
|
||||
throw;
|
||||
}
|
||||
|
||||
|
@ -1208,7 +1208,7 @@ SINT64 DPM_gen_id(thread_db* tdbb, SLONG generator, bool initialize, SINT64 val)
|
||||
generator_page* page = (generator_page*) DPM_allocate(tdbb, &window);
|
||||
page->gpg_header.pag_type = pag_ids;
|
||||
page->gpg_sequence = sequence;
|
||||
CCH_must_write(&window);
|
||||
CCH_must_write(tdbb, &window);
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
DPM_pages(tdbb, 0, pag_ids, (ULONG) sequence, window.win_page.getPageNum());
|
||||
vector = dbb->dbb_gen_id_pages =
|
||||
@ -2700,7 +2700,7 @@ static void extend_relation(thread_db* tdbb, jrd_rel* relation, WIN* window, USH
|
||||
ppage->ppg_relation = relation->rel_id;
|
||||
ppage->ppg_sequence = ++pp_sequence;
|
||||
slot = 0;
|
||||
CCH_must_write(&new_pp_window);
|
||||
CCH_must_write(tdbb, &new_pp_window);
|
||||
CCH_RELEASE(tdbb, &new_pp_window);
|
||||
|
||||
vcl* vector = relPages->rel_pages =
|
||||
|
@ -119,6 +119,7 @@ void DYN_ddl(jrd_tra* transaction, ULONG length, const UCHAR* ddl, const string&
|
||||
|
||||
thread_db* const tdbb = JRD_get_thread_data();
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
|
||||
const UCHAR* ptr = ddl;
|
||||
|
||||
@ -132,12 +133,10 @@ void DYN_ddl(jrd_tra* transaction, ULONG length, const UCHAR* ddl, const string&
|
||||
|
||||
// Create a pool for DYN to operate in. It will be released when
|
||||
// the routine exits.
|
||||
MemoryPool* const tempPool = dbb->createPool();
|
||||
MemoryPool* const tempPool = attachment->createPool();
|
||||
Jrd::ContextPoolHolder context(tdbb, tempPool);
|
||||
|
||||
try {
|
||||
Database::CheckoutLockGuard guard(dbb, dbb->dbb_dyn_mutex);
|
||||
|
||||
VIO_start_save_point(tdbb, transaction);
|
||||
transaction->tra_save_point->sav_verb_count++;
|
||||
|
||||
@ -164,12 +163,12 @@ void DYN_ddl(jrd_tra* transaction, ULONG length, const UCHAR* ddl, const string&
|
||||
}
|
||||
}
|
||||
|
||||
dbb->deletePool(tempPool);
|
||||
attachment->deletePool(tempPool);
|
||||
|
||||
ERR_punt();
|
||||
}
|
||||
|
||||
dbb->deletePool(tempPool);
|
||||
attachment->deletePool(tempPool);
|
||||
}
|
||||
|
||||
|
||||
|
@ -490,8 +490,10 @@ void EXE_execute_db_triggers(thread_db* tdbb, jrd_tra* transaction, jrd_req::req
|
||||
* Execute database triggers
|
||||
*
|
||||
**************************************/
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
|
||||
// do nothing if user doesn't want database triggers
|
||||
if (tdbb->getAttachment()->att_flags & ATT_no_db_triggers)
|
||||
if (attachment->att_flags & ATT_no_db_triggers)
|
||||
return;
|
||||
|
||||
int type = 0;
|
||||
@ -523,14 +525,14 @@ void EXE_execute_db_triggers(thread_db* tdbb, jrd_tra* transaction, jrd_req::req
|
||||
return;
|
||||
}
|
||||
|
||||
if (tdbb->getDatabase()->dbb_triggers[type])
|
||||
if (attachment->att_triggers[type])
|
||||
{
|
||||
jrd_tra* old_transaction = tdbb->getTransaction();
|
||||
tdbb->setTransaction(transaction);
|
||||
|
||||
try
|
||||
{
|
||||
EXE_execute_triggers(tdbb, &tdbb->getDatabase()->dbb_triggers[type],
|
||||
EXE_execute_triggers(tdbb, &attachment->att_triggers[type],
|
||||
NULL, NULL, trigger_action, StmtNode::ALL_TRIGS);
|
||||
tdbb->setTransaction(old_transaction);
|
||||
}
|
||||
@ -546,9 +548,11 @@ void EXE_execute_db_triggers(thread_db* tdbb, jrd_tra* transaction, jrd_req::req
|
||||
// Execute DDL triggers.
|
||||
void EXE_execute_ddl_triggers(thread_db* tdbb, jrd_tra* transaction, bool preTriggers, int action)
|
||||
{
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
|
||||
// Our caller verifies (ATT_no_db_triggers) if DDL triggers should not run.
|
||||
|
||||
if (tdbb->getDatabase()->dbb_ddl_triggers)
|
||||
if (attachment->att_ddl_triggers)
|
||||
{
|
||||
jrd_tra* const oldTransaction = tdbb->getTransaction();
|
||||
tdbb->setTransaction(transaction);
|
||||
@ -558,8 +562,8 @@ void EXE_execute_ddl_triggers(thread_db* tdbb, jrd_tra* transaction, bool preTri
|
||||
trig_vec triggers;
|
||||
trig_vec* triggersPtr = &triggers;
|
||||
|
||||
for (trig_vec::iterator i = tdbb->getDatabase()->dbb_ddl_triggers->begin();
|
||||
i != tdbb->getDatabase()->dbb_ddl_triggers->end();
|
||||
for (trig_vec::iterator i = attachment->att_ddl_triggers->begin();
|
||||
i != attachment->att_ddl_triggers->end();
|
||||
++i)
|
||||
{
|
||||
if ((i->type & (1LL << action)) &&
|
||||
|
@ -63,7 +63,7 @@ namespace Jrd
|
||||
AutoCacheRequest(thread_db* tdbb, USHORT aId, USHORT aWhich)
|
||||
: id(aId),
|
||||
which(aWhich),
|
||||
request(tdbb->getDatabase()->findSystemRequest(tdbb, id, which))
|
||||
request(tdbb->getAttachment()->findSystemRequest(tdbb, id, which))
|
||||
{
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ namespace Jrd
|
||||
|
||||
id = aId;
|
||||
which = aWhich;
|
||||
request = tdbb->getDatabase()->findSystemRequest(tdbb, id, which);
|
||||
request = tdbb->getAttachment()->findSystemRequest(tdbb, id, which);
|
||||
}
|
||||
|
||||
void compile(thread_db* tdbb, const UCHAR* blr, ULONG blrLength)
|
||||
@ -125,12 +125,12 @@ namespace Jrd
|
||||
|
||||
inline void cacheRequest()
|
||||
{
|
||||
Database* dbb = JRD_get_thread_data()->getDatabase();
|
||||
Jrd::Attachment* att = JRD_get_thread_data()->getAttachment();
|
||||
|
||||
if (which == IRQ_REQUESTS)
|
||||
dbb->dbb_internal[id] = request->getStatement();
|
||||
att->att_internal[id] = request->getStatement();
|
||||
else if (which == DYN_REQUESTS)
|
||||
dbb->dbb_dyn_req[id] = request->getStatement();
|
||||
att->att_dyn_req[id] = request->getStatement();
|
||||
else
|
||||
{
|
||||
fb_assert(false);
|
||||
|
@ -264,7 +264,7 @@ ExternalFile* EXT_file(jrd_rel* relation, const TEXT* file_name) //, bid* descri
|
||||
file_name = path.c_str();
|
||||
}
|
||||
|
||||
ExternalFile* file = FB_NEW_RPT(*dbb->dbb_permanent, (strlen(file_name) + 1)) ExternalFile();
|
||||
ExternalFile* file = FB_NEW_RPT(*relation->rel_pool, (strlen(file_name) + 1)) ExternalFile();
|
||||
relation->rel_file = file;
|
||||
strcpy(file->ext_filename, file_name);
|
||||
file->ext_flags = 0;
|
||||
|
@ -105,7 +105,7 @@ Connection* Manager::getConnection(thread_db* tdbb, const string& dataSource,
|
||||
{
|
||||
if (!m_initialized)
|
||||
{
|
||||
Database::CheckoutLockGuard guard(tdbb->getDatabase(), m_mutex);
|
||||
MutexLockGuard guard(m_mutex);
|
||||
if (!m_initialized)
|
||||
{
|
||||
m_initialized = true;
|
||||
@ -186,7 +186,7 @@ Connection* Provider::getConnection(thread_db* tdbb, const string& dbName,
|
||||
ERR_post(Arg::Gds(isc_exec_sql_max_call_exceeded));
|
||||
|
||||
{ // m_mutex scope
|
||||
Database::CheckoutLockGuard guard(tdbb->getDatabase(), m_mutex);
|
||||
MutexLockGuard guard(m_mutex);
|
||||
|
||||
Connection** conn_ptr = m_connections.begin();
|
||||
Connection** end = m_connections.end();
|
||||
@ -216,7 +216,7 @@ Connection* Provider::getConnection(thread_db* tdbb, const string& dbName,
|
||||
}
|
||||
|
||||
{ // m_mutex scope
|
||||
Database::CheckoutLockGuard guard(tdbb->getDatabase(), m_mutex);
|
||||
MutexLockGuard guard(m_mutex);
|
||||
m_connections.add(conn);
|
||||
}
|
||||
|
||||
@ -228,7 +228,7 @@ Connection* Provider::getConnection(thread_db* tdbb, const string& dbName,
|
||||
void Provider::releaseConnection(thread_db* tdbb, Connection& conn, bool /*inPool*/)
|
||||
{
|
||||
{ // m_mutex scope
|
||||
Database::CheckoutLockGuard guard(tdbb->getDatabase(), m_mutex);
|
||||
MutexLockGuard guard(m_mutex);
|
||||
|
||||
conn.m_boundAtt = NULL;
|
||||
|
||||
@ -1597,9 +1597,8 @@ void EngineCallbackGuard::init(thread_db* tdbb, Connection& conn)
|
||||
{
|
||||
m_saveConnection = attachment->att_ext_connection;
|
||||
attachment->att_ext_connection = &conn;
|
||||
attachment->att_interface->getMutex()->leave();
|
||||
}
|
||||
|
||||
m_tdbb->getDatabase()->dbb_sync->unlock();
|
||||
}
|
||||
|
||||
if (m_mutex) {
|
||||
@ -1615,17 +1614,17 @@ EngineCallbackGuard::~EngineCallbackGuard()
|
||||
|
||||
if (m_tdbb)
|
||||
{
|
||||
m_tdbb->getDatabase()->dbb_sync->lock();
|
||||
Jrd::Attachment* attachment = m_tdbb->getAttachment();
|
||||
if (attachment)
|
||||
{
|
||||
attachment->att_interface->getMutex()->enter();
|
||||
attachment->att_ext_connection = m_saveConnection;
|
||||
}
|
||||
|
||||
jrd_tra* transaction = m_tdbb->getTransaction();
|
||||
if (transaction) {
|
||||
transaction->tra_callback_count--;
|
||||
}
|
||||
|
||||
Jrd::Attachment* attachment = m_tdbb->getAttachment();
|
||||
if (attachment) {
|
||||
attachment->att_ext_connection = m_saveConnection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,9 +209,9 @@ bool IbUtil::free(void* ptr)
|
||||
typedef void* UDF_ARG;
|
||||
|
||||
template <typename T>
|
||||
T CALL_UDF(Database* dbb, int (*entrypoint)(), UDF_ARG* args)
|
||||
T CALL_UDF(Jrd::Attachment* att, int (*entrypoint)(), UDF_ARG* args)
|
||||
{
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
Jrd::Attachment::Checkout attCout(att);
|
||||
return ((T (*)(UDF_ARG, UDF_ARG, UDF_ARG, UDF_ARG, UDF_ARG, UDF_ARG, UDF_ARG, UDF_ARG, UDF_ARG, UDF_ARG))(entrypoint)) (args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
|
||||
}
|
||||
|
||||
@ -757,7 +757,7 @@ static SLONG blob_lseek(blb* blob, USHORT mode, SLONG offset)
|
||||
**************************************/
|
||||
// As this is a call-back from a UDF, must reacquire the engine mutex
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
Database::SyncGuard dsGuard(tdbb->getDatabase());
|
||||
Jrd::Attachment::SyncGuard guard(tdbb->getAttachment());
|
||||
|
||||
return BLB_lseek(blob, mode, offset);
|
||||
}
|
||||
@ -777,7 +777,7 @@ static void blob_put_segment(blb* blob, const UCHAR* buffer, USHORT length)
|
||||
**************************************/
|
||||
// As this is a call-back from a UDF, must reacquire the engine mutex
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
Database::SyncGuard dsGuard(tdbb->getDatabase());
|
||||
Jrd::Attachment::SyncGuard guard(tdbb->getAttachment());
|
||||
|
||||
BLB_put_segment(tdbb, blob, buffer, length);
|
||||
}
|
||||
@ -801,7 +801,7 @@ static SSHORT blob_get_segment(blb* blob, UCHAR* buffer, USHORT length, USHORT*
|
||||
**************************************/
|
||||
// As this is a call-back from a UDF, must reacquire the engine mutex
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
Database::SyncGuard dsGuard(tdbb->getDatabase());
|
||||
Jrd::Attachment::SyncGuard guard(tdbb->getAttachment());
|
||||
|
||||
*return_length = BLB_get_segment(tdbb, blob, buffer, length);
|
||||
|
||||
@ -921,11 +921,12 @@ static void invoke(thread_db* tdbb,
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* att = tdbb->getAttachment();
|
||||
|
||||
START_CHECK_FOR_EXCEPTIONS(function->fun_exception_message.c_str());
|
||||
if (function->fun_return_arg)
|
||||
{
|
||||
CALL_UDF<void>(dbb, function->fun_entrypoint, args);
|
||||
CALL_UDF<void>(att, function->fun_entrypoint, args);
|
||||
result_is_null = return_ptr->fun_mechanism == FUN_descriptor &&
|
||||
(value->vlu_desc.dsc_flags & DSC_null) ||
|
||||
return_ptr->fun_mechanism == FUN_blob_struct && return_blob_struct &&
|
||||
@ -940,7 +941,7 @@ static void invoke(thread_db* tdbb,
|
||||
case dtype_sql_time:
|
||||
case dtype_sql_date:
|
||||
case dtype_long:
|
||||
value->vlu_misc.vlu_long = CALL_UDF<SLONG>(dbb, function->fun_entrypoint, args);
|
||||
value->vlu_misc.vlu_long = CALL_UDF<SLONG>(att, function->fun_entrypoint, args);
|
||||
break;
|
||||
|
||||
case dtype_short:
|
||||
@ -948,7 +949,7 @@ static void invoke(thread_db* tdbb,
|
||||
// must always be returned as a LONG. See v3.2 release notes
|
||||
// 1994-September-28 David Schnepper
|
||||
|
||||
value->vlu_misc.vlu_short = (SSHORT) CALL_UDF<SLONG>(dbb, function->fun_entrypoint, args);
|
||||
value->vlu_misc.vlu_short = (SSHORT) CALL_UDF<SLONG>(att, function->fun_entrypoint, args);
|
||||
break;
|
||||
|
||||
case dtype_real:
|
||||
@ -956,15 +957,15 @@ static void invoke(thread_db* tdbb,
|
||||
// must always be returned as a DOUBLE. See v3.2 release notes
|
||||
// 1994-September-28 David Schnepper
|
||||
|
||||
value->vlu_misc.vlu_float = (float) CALL_UDF<double>(dbb, function->fun_entrypoint, args);
|
||||
value->vlu_misc.vlu_float = (float) CALL_UDF<double>(att, function->fun_entrypoint, args);
|
||||
break;
|
||||
|
||||
case dtype_int64:
|
||||
value->vlu_misc.vlu_int64 = CALL_UDF<SINT64>(dbb, function->fun_entrypoint, args);
|
||||
value->vlu_misc.vlu_int64 = CALL_UDF<SINT64>(att, function->fun_entrypoint, args);
|
||||
break;
|
||||
|
||||
case dtype_double:
|
||||
value->vlu_misc.vlu_double = CALL_UDF<double>(dbb, function->fun_entrypoint, args);
|
||||
value->vlu_misc.vlu_double = CALL_UDF<double>(att, function->fun_entrypoint, args);
|
||||
break;
|
||||
|
||||
case dtype_timestamp:
|
||||
@ -975,7 +976,7 @@ static void invoke(thread_db* tdbb,
|
||||
}
|
||||
else
|
||||
{
|
||||
UCHAR* temp_ptr = CALL_UDF<UCHAR*>(dbb, function->fun_entrypoint, args);
|
||||
UCHAR* temp_ptr = CALL_UDF<UCHAR*>(att, function->fun_entrypoint, args);
|
||||
|
||||
if (temp_ptr != NULL)
|
||||
{
|
||||
|
@ -232,6 +232,7 @@ void IDX_create_index(thread_db* tdbb,
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
|
||||
if (relation->rel_file)
|
||||
{
|
||||
@ -308,7 +309,7 @@ void IDX_create_index(thread_db* tdbb,
|
||||
void* callback_arg = (idx->idx_flags & idx_unique) ? &ifl_data : NULL;
|
||||
|
||||
AutoPtr<Sort> scb(FB_NEW(transaction->tra_sorts.getPool())
|
||||
Sort(dbb, &transaction->tra_sorts, key_length + sizeof(index_sort_record),
|
||||
Sort(attachment, &transaction->tra_sorts, key_length + sizeof(index_sort_record),
|
||||
2, 1, key_desc, callback, callback_arg));
|
||||
|
||||
jrd_rel* partner_relation = NULL;
|
||||
@ -328,7 +329,6 @@ void IDX_create_index(thread_db* tdbb,
|
||||
|
||||
// Unless this is the only attachment or a database restore, worry about
|
||||
// preserving the page working sets of other attachments.
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
if (attachment && (attachment != dbb->dbb_attachments || attachment->att_next))
|
||||
{
|
||||
if (attachment->att_flags & ATT_gbak_attachment ||
|
||||
@ -539,7 +539,7 @@ IndexBlock* IDX_create_index_block(thread_db* tdbb, jrd_rel* relation, USHORT id
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
CHECK_DBB(dbb);
|
||||
|
||||
IndexBlock* index_block = FB_NEW(*dbb->dbb_permanent) IndexBlock();
|
||||
IndexBlock* index_block = FB_NEW(*relation->rel_pool) IndexBlock();
|
||||
index_block->idb_id = id;
|
||||
|
||||
// link the block in with the relation linked list
|
||||
@ -551,7 +551,7 @@ IndexBlock* IDX_create_index_block(thread_db* tdbb, jrd_rel* relation, USHORT id
|
||||
// any modification to the index so that the cached information
|
||||
// about the index will be discarded
|
||||
|
||||
Lock* lock = FB_NEW_RPT(*dbb->dbb_permanent, 0) Lock;
|
||||
Lock* lock = FB_NEW_RPT(*relation->rel_pool, 0) Lock;
|
||||
index_block->idb_lock = lock;
|
||||
lock->lck_parent = dbb->dbb_lock;
|
||||
lock->lck_dbb = dbb;
|
||||
@ -1491,12 +1491,12 @@ static int index_block_flush(void* ast_object)
|
||||
Lock* lock = index_block->idb_lock;
|
||||
Database* dbb = lock->lck_dbb;
|
||||
|
||||
Database::SyncGuard dsGuard(dbb, true);
|
||||
|
||||
ThreadContextHolder tdbb;
|
||||
tdbb->setDatabase(dbb);
|
||||
tdbb->setAttachment(lock->lck_attachment);
|
||||
|
||||
Jrd::Attachment::SyncGuard guard(lock->lck_attachment);
|
||||
|
||||
release_index_block(tdbb, index_block);
|
||||
}
|
||||
catch (const Firebird::Exception&)
|
||||
|
@ -587,6 +587,8 @@ void INF_database_info(thread_db* tdbb,
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
SyncLockGuard sync(&dbb->dbb_sync, SYNC_SHARED, "INF_database_info");
|
||||
for (const Jrd::Attachment* att = dbb->dbb_attachments; att; att = att->att_next)
|
||||
{
|
||||
if (att->att_flags & ATT_shutdown)
|
||||
@ -604,11 +606,15 @@ void INF_database_info(thread_db* tdbb,
|
||||
if (!(info = INF_put_item(item, len + 1, buffer, info, end)))
|
||||
{
|
||||
if (transaction)
|
||||
{
|
||||
sync.unlock();
|
||||
TRA_commit(tdbb, transaction, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
case isc_info_page_errors:
|
||||
|
@ -518,6 +518,9 @@ void INI_init(thread_db* tdbb)
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
CHECK_DBB(dbb);
|
||||
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
MemoryPool* pool = attachment->att_pool;
|
||||
|
||||
const int* fld;
|
||||
for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1)
|
||||
{
|
||||
@ -541,12 +544,12 @@ void INI_init(thread_db* tdbb)
|
||||
}
|
||||
}
|
||||
|
||||
vec<jrd_fld*>* fields = vec<jrd_fld*>::newVector(*dbb->dbb_permanent, n);
|
||||
vec<jrd_fld*>* fields = vec<jrd_fld*>::newVector(*pool, n);
|
||||
relation->rel_fields = fields;
|
||||
vec<jrd_fld*>::iterator itr = fields->begin();
|
||||
Format* format = Format::newFormat(*dbb->dbb_permanent, n);
|
||||
Format* format = Format::newFormat(*pool, n);
|
||||
relation->rel_current_format = format;
|
||||
vec<Format*>* formats = vec<Format*>::newVector(*dbb->dbb_permanent, 1);
|
||||
vec<Format*>* formats = vec<Format*>::newVector(*pool, 1);
|
||||
relation->rel_formats = formats;
|
||||
(*formats)[0] = format;
|
||||
Format::fmt_desc_iterator desc = format->fmt_desc.begin();
|
||||
@ -575,7 +578,7 @@ void INI_init(thread_db* tdbb)
|
||||
if (desc->dsc_dtype == dtype_blob && desc->dsc_sub_type == isc_blob_text)
|
||||
desc->dsc_scale = CS_METADATA; // blob charset
|
||||
|
||||
jrd_fld* field = FB_NEW(*dbb->dbb_permanent) jrd_fld(*dbb->dbb_permanent);
|
||||
jrd_fld* field = FB_NEW(*pool) jrd_fld(*pool);
|
||||
*itr = field;
|
||||
field->fld_name = names[fld[RFLD_F_NAME]];
|
||||
}
|
||||
@ -602,7 +605,7 @@ void INI_init2(thread_db* tdbb)
|
||||
|
||||
const USHORT major_version = dbb->dbb_ods_version;
|
||||
const USHORT minor_version = dbb->dbb_minor_version;
|
||||
vec<jrd_rel*>* vector = dbb->dbb_relations;
|
||||
vec<jrd_rel*>* vector = tdbb->getAttachment()->att_relations;
|
||||
|
||||
const int* fld;
|
||||
for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1)
|
||||
|
@ -207,16 +207,17 @@ CharSetContainer* CharSetContainer::lookupCharset(thread_db* tdbb, USHORT ttype)
|
||||
CharSetContainer* cs = NULL;
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
fb_assert(attachment);
|
||||
|
||||
USHORT id = TTYPE_TO_CHARSET(ttype);
|
||||
if (id == CS_dynamic)
|
||||
id = tdbb->getCharSet();
|
||||
|
||||
if (id >= dbb->dbb_charsets.getCount())
|
||||
dbb->dbb_charsets.resize(id + 10);
|
||||
if (id >= attachment->att_charsets.getCount())
|
||||
attachment->att_charsets.resize(id + 10);
|
||||
else
|
||||
cs = dbb->dbb_charsets[id];
|
||||
cs = attachment->att_charsets[id];
|
||||
|
||||
// allocate a new character set object if we couldn't find one.
|
||||
if (!cs)
|
||||
@ -225,8 +226,8 @@ CharSetContainer* CharSetContainer::lookupCharset(thread_db* tdbb, USHORT ttype)
|
||||
|
||||
if (lookupInternalCharSet(id, &info) || MET_get_char_coll_subtype_info(tdbb, id, &info))
|
||||
{
|
||||
dbb->dbb_charsets[id] = cs =
|
||||
FB_NEW(*dbb->dbb_permanent) CharSetContainer(*dbb->dbb_permanent, id, &info);
|
||||
attachment->att_charsets[id] = cs =
|
||||
FB_NEW(*attachment->att_pool) CharSetContainer(*attachment->att_pool, id, &info);
|
||||
}
|
||||
else
|
||||
ERR_post(Arg::Gds(isc_text_subtype) << Arg::Num(ttype));
|
||||
@ -347,8 +348,8 @@ Collation* CharSetContainer::lookupCollation(thread_db* tdbb, USHORT tt_id)
|
||||
return charset_collations[id];
|
||||
}
|
||||
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Database::CheckoutLockGuard guard(dbb, createCollationMtx);
|
||||
Jrd::Attachment* att = tdbb->getAttachment();
|
||||
Jrd::Attachment::CheckoutLockGuard guard(att, createCollationMtx); // are we need it ?
|
||||
|
||||
Collation* to_delete = NULL;
|
||||
if (id < charset_collations.getCount() && charset_collations[id] != NULL)
|
||||
@ -503,26 +504,26 @@ static INTL_BOOL lookup_texttype(texttype* tt, const SubtypeInfo* info)
|
||||
}
|
||||
|
||||
|
||||
void Database::releaseIntlObjects()
|
||||
void Jrd::Attachment::releaseIntlObjects()
|
||||
{
|
||||
for (size_t i = 0; i < dbb_charsets.getCount(); i++)
|
||||
for (size_t i = 0; i < att_charsets.getCount(); i++)
|
||||
{
|
||||
if (dbb_charsets[i])
|
||||
if (att_charsets[i])
|
||||
{
|
||||
dbb_charsets[i]->release();
|
||||
att_charsets[i]->release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Database::destroyIntlObjects()
|
||||
void Jrd::Attachment::destroyIntlObjects()
|
||||
{
|
||||
for (size_t i = 0; i < dbb_charsets.getCount(); i++)
|
||||
for (size_t i = 0; i < att_charsets.getCount(); i++)
|
||||
{
|
||||
if (dbb_charsets[i])
|
||||
if (att_charsets[i])
|
||||
{
|
||||
dbb_charsets[i]->destroy();
|
||||
dbb_charsets[i] = NULL;
|
||||
att_charsets[i]->destroy();
|
||||
att_charsets[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1390,13 +1391,13 @@ static int blocking_ast_collation(void* ast_object)
|
||||
try
|
||||
{
|
||||
Database* dbb = tt->existenceLock->lck_dbb;
|
||||
|
||||
Database::SyncGuard dsGuard(dbb, true);
|
||||
Jrd::Attachment* att = tt->existenceLock->lck_attachment;
|
||||
|
||||
ThreadContextHolder tdbb;
|
||||
tdbb->setDatabase(dbb);
|
||||
tdbb->setAttachment(tt->existenceLock->lck_attachment);
|
||||
tdbb->setAttachment(att);
|
||||
|
||||
Jrd::Attachment::SyncGuard guard(att);
|
||||
Jrd::ContextPoolHolder context(tdbb, 0);
|
||||
|
||||
tt->obsolete = true;
|
||||
|
289
src/jrd/jrd.cpp
289
src/jrd/jrd.cpp
@ -104,6 +104,7 @@
|
||||
#include "../jrd/sdw_proto.h"
|
||||
#include "../jrd/shut_proto.h"
|
||||
#include "../jrd/thread_proto.h"
|
||||
#include "../jrd/tpc_proto.h"
|
||||
#include "../jrd/tra_proto.h"
|
||||
#include "../jrd/val_proto.h"
|
||||
#include "../jrd/vio_proto.h"
|
||||
@ -434,12 +435,12 @@ namespace
|
||||
{
|
||||
public:
|
||||
AttachmentHolder(thread_db* tdbb, JAttachment* ja, bool lockAsync)
|
||||
: mutex(ja->getMutex(lockAsync))
|
||||
: mutex(ja->getMutex(lockAsync)),
|
||||
attachment(ja->getHandle()),
|
||||
async(lockAsync)
|
||||
{
|
||||
mutex->enter();
|
||||
|
||||
Jrd::Attachment* attachment = ja->getHandle();
|
||||
|
||||
try
|
||||
{
|
||||
if (!attachment || engineShuttingDown)
|
||||
@ -447,6 +448,10 @@ namespace
|
||||
|
||||
tdbb->setAttachment(attachment);
|
||||
tdbb->setDatabase(attachment->att_database);
|
||||
if (!lockAsync)
|
||||
{
|
||||
attachment->att_use_count++;
|
||||
}
|
||||
}
|
||||
catch (const Firebird::Exception&)
|
||||
{
|
||||
@ -457,11 +462,17 @@ namespace
|
||||
|
||||
~AttachmentHolder()
|
||||
{
|
||||
if (!async)
|
||||
{
|
||||
attachment->att_use_count--;
|
||||
}
|
||||
mutex->leave();
|
||||
}
|
||||
|
||||
private:
|
||||
Firebird::Mutex* mutex;
|
||||
bool async;
|
||||
Jrd::Attachment* attachment;
|
||||
|
||||
private:
|
||||
// copying is prohibited
|
||||
@ -469,12 +480,11 @@ namespace
|
||||
AttachmentHolder& operator =(const AttachmentHolder&);
|
||||
};
|
||||
|
||||
class DatabaseContextHolder : private Database::SyncGuard, public Jrd::ContextPoolHolder
|
||||
class DatabaseContextHolder : public Jrd::ContextPoolHolder
|
||||
{
|
||||
public:
|
||||
DatabaseContextHolder(thread_db* tdbb)
|
||||
: Database::SyncGuard(tdbb->getDatabase()),
|
||||
Jrd::ContextPoolHolder(tdbb, tdbb->getDatabase()->dbb_permanent),
|
||||
: Jrd::ContextPoolHolder(tdbb, tdbb->getDatabase()->dbb_permanent),
|
||||
savedTdbb(tdbb)
|
||||
{
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
@ -539,19 +549,18 @@ void Trigger::compile(thread_db* tdbb)
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* const att = tdbb->getAttachment();
|
||||
|
||||
if (engine.isEmpty() && !extTrigger)
|
||||
{
|
||||
if (!statement /*&& !compile_in_progress*/)
|
||||
{
|
||||
Database::CheckoutLockGuard guard(dbb, dbb->dbb_meta_mutex);
|
||||
|
||||
if (statement)
|
||||
return;
|
||||
|
||||
compile_in_progress = true;
|
||||
// Allocate statement memory pool
|
||||
MemoryPool* new_pool = dbb->createPool();
|
||||
MemoryPool* new_pool = att->createPool();
|
||||
// Trigger request is not compiled yet. Lets do it now
|
||||
USHORT par_flags = (USHORT) (flags & TRG_ignore_perm) ? csb_ignore_perm : 0;
|
||||
if (type & 1)
|
||||
@ -586,7 +595,7 @@ void Trigger::compile(thread_db* tdbb)
|
||||
statement = NULL;
|
||||
}
|
||||
else {
|
||||
dbb->deletePool(new_pool);
|
||||
att->deletePool(new_pool);
|
||||
}
|
||||
|
||||
throw;
|
||||
@ -817,7 +826,7 @@ static void cancel_attachments(thread_db* tdbb)
|
||||
{
|
||||
if ( !(dbb->dbb_flags & (DBB_bugcheck | DBB_not_in_use | DBB_security_db)) )
|
||||
{
|
||||
Database::SyncGuard dsGuard(dbb);
|
||||
SyncLockGuard guard(&dbb->dbb_sync, SYNC_EXCLUSIVE, "cancel_attachments");
|
||||
Jrd::Attachment* lockedAtt = NULL;
|
||||
Jrd::Attachment* att = dbb->dbb_attachments;
|
||||
|
||||
@ -827,36 +836,51 @@ static void cancel_attachments(thread_db* tdbb)
|
||||
// deleted while waiting for lock.
|
||||
RefPtr<JAttachment> jAtt(att->att_interface);
|
||||
MutexLockGuard asyncGuard(*(jAtt->getMutex(true)));
|
||||
att->att_flags |= ATT_shutdown;
|
||||
while (true)
|
||||
{
|
||||
if (att->att_interface->getMutex()->tryEnter() || (att->att_flags & ATT_purge_error))
|
||||
if (att->att_interface->getMutex()->tryEnter())
|
||||
{
|
||||
if (att->att_use_count)
|
||||
{
|
||||
att->att_interface->getMutex()->leave();
|
||||
}
|
||||
else
|
||||
{
|
||||
jAtt->cancel();
|
||||
lockedAtt = att;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (att->att_flags & ATT_purge_error)
|
||||
{
|
||||
lockedAtt = att;
|
||||
break;
|
||||
}
|
||||
|
||||
{ // scope
|
||||
const bool cancel_disable = (att->att_flags & ATT_cancel_disable);
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
if (!cancel_disable)
|
||||
{
|
||||
ThreadStatusGuard temp_status(tdbb);
|
||||
JRD_cancel_operation(tdbb, att, fb_cancel_enable);
|
||||
JRD_cancel_operation(tdbb, att, fb_cancel_raise);
|
||||
}
|
||||
|
||||
THREAD_YIELD();
|
||||
} // end scope
|
||||
|
||||
//{ // scope
|
||||
// const bool cancel_disable = (att->att_flags & ATT_cancel_disable);
|
||||
// SyncUnlockGuard cout(guard);
|
||||
// if (!cancel_disable)
|
||||
// {
|
||||
// ThreadStatusGuard temp_status(tdbb);
|
||||
// JRD_cancel_operation(tdbb, att, fb_cancel_enable);
|
||||
// JRD_cancel_operation(tdbb, att, fb_cancel_raise);
|
||||
// }
|
||||
|
||||
// THREAD_YIELD();
|
||||
//} // end scope
|
||||
|
||||
// check if attachment still exist
|
||||
if (lockedAtt && lockedAtt->att_next != att) {
|
||||
break;
|
||||
}
|
||||
if (dbb->dbb_attachments != att) {
|
||||
if (!lockedAtt && dbb->dbb_attachments != att) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
jAtt->cancel();
|
||||
att = lockedAtt ? lockedAtt->att_next : dbb->dbb_attachments;
|
||||
}
|
||||
}
|
||||
@ -1170,6 +1194,8 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
|
||||
dbb = init(tdbb, expanded_name, config, true);
|
||||
|
||||
fb_assert(dbb);
|
||||
Sync dbbGuard(&dbb->dbb_sync, "attachDatabase");
|
||||
dbbGuard.lock(SYNC_EXCLUSIVE);
|
||||
|
||||
tdbb->setDatabase(dbb);
|
||||
DatabaseContextHolder dbbHolder(tdbb);
|
||||
@ -1217,6 +1243,12 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
|
||||
}
|
||||
|
||||
attachment = Jrd::Attachment::create(dbb);
|
||||
|
||||
RefPtr<JAttachment> jAtt(new JAttachment(attachment));
|
||||
jAtt->addRef();
|
||||
attachment->att_interface = jAtt;
|
||||
MutexLockGuard guard(*(jAtt->getMutex()));
|
||||
|
||||
tdbb->setAttachment(attachment);
|
||||
attachment->att_filename = is_alias ? file_name : expanded_name;
|
||||
attachment->att_network_protocol = options.dpb_network_protocol;
|
||||
@ -1255,8 +1287,10 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
|
||||
|
||||
if (dbb->dbb_filename.empty())
|
||||
{
|
||||
#if defined(DEV_BUILD) && defined(SHARED_METADATA_CACHE)
|
||||
#if defined(DEV_BUILD)
|
||||
// make sure we do not reopen same DB twice
|
||||
if (config->getSharedCache())
|
||||
{
|
||||
for (Database* d = databases; d; d = d->dbb_next)
|
||||
{
|
||||
if (d->dbb_filename == expanded_name)
|
||||
@ -1264,6 +1298,7 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
|
||||
fatal_exception::raise(("Attempt to reopen " + expanded_name).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
first = true;
|
||||
dbb->dbb_filename = expanded_name;
|
||||
@ -1313,7 +1348,9 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
|
||||
}
|
||||
|
||||
options.setBuffers(dbb->dbb_config);
|
||||
CCH_init(tdbb, options.dpb_buffers);
|
||||
CCH_init(tdbb, options.dpb_buffers, config->getSharedCache() && !config->getSharedDatabase());
|
||||
|
||||
dbb->dbb_tip_cache = FB_NEW(*dbb->dbb_permanent) TipCache(dbb);
|
||||
|
||||
// Initialize backup difference subsystem. This must be done before WAL and shadowing
|
||||
// is enabled because nbackup it is a lower level subsystem
|
||||
@ -1338,6 +1375,10 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
|
||||
|
||||
LCK_init(tdbb, LCK_OWNER_attachment);
|
||||
attachment->att_flags |= ATT_lck_init_done;
|
||||
|
||||
INI_init(tdbb);
|
||||
INI_init2(tdbb);
|
||||
PAG_header(tdbb, true);
|
||||
}
|
||||
|
||||
// Attachments to a ReadOnly database need NOT do garbage collection
|
||||
@ -1471,6 +1512,7 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
|
||||
attachment_succeeded = CCH_exclusive_attachment(tdbb, LCK_none, -1);
|
||||
else
|
||||
CCH_exclusive_attachment(tdbb, LCK_none, LCK_WAIT);
|
||||
|
||||
if (attachment->att_flags & ATT_shutdown)
|
||||
{
|
||||
if (dbb->dbb_ast_flags & DBB_shutdown) {
|
||||
@ -1651,11 +1693,6 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
|
||||
// Recover database after crash during backup difference file merge
|
||||
dbb->dbb_backup_manager->endBackup(tdbb, true); // true = do recovery
|
||||
|
||||
RefPtr<JAttachment> jAtt(new JAttachment(attachment));
|
||||
attachment->att_interface = jAtt;
|
||||
|
||||
MutexLockGuard guard(*(jAtt->getMutex()));
|
||||
|
||||
if (attachment->att_trace_manager->needs(TRACE_EVENT_ATTACH))
|
||||
{
|
||||
TraceConnectionImpl conn(attachment);
|
||||
@ -1679,7 +1716,7 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
|
||||
// load DDL triggers
|
||||
MET_load_ddl_triggers(tdbb);
|
||||
|
||||
const trig_vec* trig_connect = dbb->dbb_triggers[DB_TRIGGER_CONNECT];
|
||||
const trig_vec* trig_connect = attachment->att_triggers[DB_TRIGGER_CONNECT];
|
||||
if (trig_connect && !trig_connect->isEmpty())
|
||||
{
|
||||
// Start a transaction to execute ON CONNECT triggers.
|
||||
@ -1707,7 +1744,6 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
|
||||
|
||||
// guardDatabases.leave();
|
||||
|
||||
jAtt->addRef();
|
||||
return jAtt;
|
||||
} // try
|
||||
catch (const Exception& ex)
|
||||
@ -1717,6 +1753,9 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
|
||||
trace_failed_attach(attachment ? attachment->att_trace_manager : NULL,
|
||||
filename, options, false, no_priv);
|
||||
|
||||
dbb->dbb_sync.lock(NULL, SYNC_EXCLUSIVE);
|
||||
dbbGuard.unlock();
|
||||
attachment->att_interface = NULL;
|
||||
unwindAttach(tdbb, ex, user_status, attachment, dbb);
|
||||
}
|
||||
}
|
||||
@ -2249,6 +2288,8 @@ JAttachment* FB_CARG JProvider::createDatabase(IStatus* user_status, const char*
|
||||
|
||||
dbb = init(tdbb, expanded_name, config, false);
|
||||
fb_assert(dbb);
|
||||
Sync dbbGuard(&dbb->dbb_sync, "createDatabase");
|
||||
dbbGuard.lock(SYNC_EXCLUSIVE);
|
||||
|
||||
tdbb->setDatabase(dbb);
|
||||
DatabaseContextHolder dbbHolder(tdbb);
|
||||
@ -2267,6 +2308,12 @@ JAttachment* FB_CARG JProvider::createDatabase(IStatus* user_status, const char*
|
||||
}
|
||||
|
||||
attachment = Jrd::Attachment::create(dbb);
|
||||
|
||||
RefPtr<JAttachment> jAtt(new JAttachment(attachment));
|
||||
jAtt->addRef();
|
||||
attachment->att_interface = jAtt;
|
||||
MutexLockGuard guard(*(jAtt->getMutex()));
|
||||
|
||||
tdbb->setAttachment(attachment);
|
||||
attachment->att_filename = is_alias ? file_name : expanded_name;
|
||||
attachment->att_network_protocol = options.dpb_network_protocol;
|
||||
@ -2396,15 +2443,15 @@ JAttachment* FB_CARG JProvider::createDatabase(IStatus* user_status, const char*
|
||||
if (options.dpb_set_page_buffers)
|
||||
dbb->dbb_page_buffers = options.dpb_page_buffers;
|
||||
|
||||
options.setBuffers(dbb->dbb_config);
|
||||
CCH_init(tdbb, options.dpb_buffers, config->getSharedCache() && !config->getSharedDatabase());
|
||||
|
||||
#ifdef WIN_NT
|
||||
dbb->dbb_filename.assign(first_dbb_file->fil_string);
|
||||
#else
|
||||
dbb->dbb_filename = expanded_name;
|
||||
#endif
|
||||
|
||||
options.setBuffers(dbb->dbb_config);
|
||||
CCH_init(tdbb, options.dpb_buffers);
|
||||
|
||||
// NS: Use alias as database ID only if accessing database using file name is not possible.
|
||||
//
|
||||
// This way we:
|
||||
@ -2416,6 +2463,8 @@ JAttachment* FB_CARG JProvider::createDatabase(IStatus* user_status, const char*
|
||||
else
|
||||
dbb->dbb_database_name = dbb->dbb_filename;
|
||||
|
||||
dbb->dbb_tip_cache = FB_NEW(*dbb->dbb_permanent) TipCache(dbb);
|
||||
|
||||
// Initialize backup difference subsystem. This must be done before WAL and shadowing
|
||||
// is enabled because nbackup it is a lower level subsystem
|
||||
dbb->dbb_backup_manager = FB_NEW(*dbb->dbb_permanent) BackupManager(tdbb, dbb, nbak_state_normal);
|
||||
@ -2492,10 +2541,6 @@ JAttachment* FB_CARG JProvider::createDatabase(IStatus* user_status, const char*
|
||||
|
||||
guardDatabases.leave();
|
||||
|
||||
JAttachment* jAtt = new JAttachment(attachment);
|
||||
jAtt->addRef();
|
||||
attachment->att_interface = jAtt;
|
||||
|
||||
return jAtt;
|
||||
} // try
|
||||
catch (const Exception& ex)
|
||||
@ -2505,6 +2550,10 @@ JAttachment* FB_CARG JProvider::createDatabase(IStatus* user_status, const char*
|
||||
trace_failed_attach(attachment ? attachment->att_trace_manager : NULL,
|
||||
filename, options, true, no_priv);
|
||||
|
||||
dbb->dbb_sync.lock(NULL, SYNC_EXCLUSIVE);
|
||||
dbbGuard.unlock();
|
||||
|
||||
attachment->att_interface = NULL;
|
||||
unwindAttach(tdbb, ex, user_status, attachment, dbb);
|
||||
}
|
||||
}
|
||||
@ -2616,16 +2665,26 @@ void JAttachment::freeEngineData(IStatus* user_status)
|
||||
JRD_cancel_operation(tdbb, getHandle(), fb_cancel_raise);
|
||||
|
||||
MutexLockGuard guard(*getMutex());
|
||||
{
|
||||
while (att->att_use_count)
|
||||
{
|
||||
MutexUnlockGuard cout(*getMutex());
|
||||
THD_sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
|
||||
// if this is the last attachment, mark dbb as not in use
|
||||
{
|
||||
SyncLockGuard sync(&dbb->dbb_sync, SYNC_SHARED, "JAttachment::freeEngineData");
|
||||
|
||||
if (dbb->dbb_attachments == getHandle() && !getHandle()->att_next &&
|
||||
!(dbb->dbb_flags & DBB_being_opened))
|
||||
{
|
||||
dbb->dbb_flags |= DBB_not_in_use;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
@ -3964,12 +4023,13 @@ void JAttachment::transactRequest(IStatus* user_status, ITransaction* tra,
|
||||
{
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
jrd_tra* const transaction = find_transaction(tdbb, isc_req_wrong_db);
|
||||
Jrd::Attachment* const att = transaction->tra_attachment;
|
||||
|
||||
const MessageNode* inMessage = NULL;
|
||||
const MessageNode* outMessage = NULL;
|
||||
|
||||
jrd_req* request = NULL;
|
||||
MemoryPool* new_pool = dbb->createPool();
|
||||
MemoryPool* new_pool = att->createPool();
|
||||
|
||||
try
|
||||
{
|
||||
@ -3999,7 +4059,7 @@ void JAttachment::transactRequest(IStatus* user_status, ITransaction* tra,
|
||||
if (request)
|
||||
CMP_release(tdbb, request);
|
||||
else
|
||||
dbb->deletePool(new_pool);
|
||||
att->deletePool(new_pool);
|
||||
|
||||
throw;
|
||||
}
|
||||
@ -4759,10 +4819,11 @@ bool JRD_reschedule(thread_db* tdbb, SLONG quantum, bool punt)
|
||||
*
|
||||
**************************************/
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* att= tdbb->getAttachment();
|
||||
|
||||
if (dbb->dbb_sync->hasContention())
|
||||
//if (dbb->dbb_sync->hasContention())
|
||||
{
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
Jrd::Attachment::Checkout cout(att);
|
||||
THREAD_YIELD();
|
||||
}
|
||||
|
||||
@ -4789,7 +4850,9 @@ bool JRD_reschedule(thread_db* tdbb, SLONG quantum, bool punt)
|
||||
}
|
||||
|
||||
// Enable signal handler for the monitoring stuff
|
||||
|
||||
if (dbb->dbb_ast_flags & DBB_monitor_off)
|
||||
{
|
||||
SyncLockGuard monGuard(&dbb->dbb_mon_sync, SYNC_EXCLUSIVE, "JRD_reschedule");
|
||||
if (dbb->dbb_ast_flags & DBB_monitor_off)
|
||||
{
|
||||
dbb->dbb_ast_flags &= ~DBB_monitor_off;
|
||||
@ -4803,6 +4866,7 @@ bool JRD_reschedule(thread_db* tdbb, SLONG quantum, bool punt)
|
||||
if (dbb->dbb_ast_flags & DBB_monitor_off)
|
||||
LCK_release(tdbb, dbb->dbb_monitor_lock);
|
||||
}
|
||||
}
|
||||
|
||||
tdbb->tdbb_quantum = (tdbb->tdbb_quantum <= 0) ?
|
||||
(quantum ? quantum : QUANTUM) : tdbb->tdbb_quantum;
|
||||
@ -4863,12 +4927,21 @@ static void check_database(thread_db* tdbb)
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
|
||||
const Jrd::Attachment* attach = dbb->dbb_attachments;
|
||||
while (attach && attach != attachment)
|
||||
attach = attach->att_next;
|
||||
|
||||
if (!attach)
|
||||
status_exception::raise(Arg::Gds(isc_bad_db_handle));
|
||||
// hvlad: i think the check below is unnecessary as attachment pointer is
|
||||
// already validated at AttachmentHolder. If i'm wrong and check is must be
|
||||
// then it should be moved into AttachmentHolder or even into
|
||||
// DatabaseContexHolder to not lock dbb_sync with attachment mutex locked.
|
||||
//
|
||||
//{
|
||||
// SyncLockGuard dbbGuard(&dbb->dbb_sync, SYNC_SHARED, "check_database");
|
||||
//
|
||||
// const Jrd::Attachment* attach = dbb->dbb_attachments;
|
||||
// while (attach && attach != attachment)
|
||||
// attach = attach->att_next;
|
||||
//
|
||||
// if (!attach)
|
||||
// status_exception::raise(Arg::Gds(isc_bad_db_handle));
|
||||
//}
|
||||
|
||||
if (dbb->dbb_flags & DBB_bugcheck)
|
||||
{
|
||||
@ -4900,6 +4973,9 @@ static void check_database(thread_db* tdbb)
|
||||
// Enable signal handler for the monitoring stuff.
|
||||
// See also comments in JRD_reshedule.
|
||||
|
||||
if (dbb->dbb_ast_flags & DBB_monitor_off)
|
||||
{
|
||||
SyncLockGuard monGuard(&dbb->dbb_mon_sync, SYNC_EXCLUSIVE, "check_database");
|
||||
if (dbb->dbb_ast_flags & DBB_monitor_off)
|
||||
{
|
||||
dbb->dbb_ast_flags &= ~DBB_monitor_off;
|
||||
@ -4908,6 +4984,7 @@ static void check_database(thread_db* tdbb)
|
||||
if (dbb->dbb_ast_flags & DBB_monitor_off)
|
||||
LCK_release(tdbb, dbb->dbb_monitor_lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5146,6 +5223,8 @@ void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_cli
|
||||
ERR_post(Arg::Gds(isc_bad_dpb_content));
|
||||
}
|
||||
}
|
||||
else
|
||||
rdr.getInt();
|
||||
break;
|
||||
|
||||
case isc_dpb_page_size:
|
||||
@ -5497,7 +5576,8 @@ static Database* init(thread_db* tdbb,
|
||||
|
||||
// Check to see if the database is already actively attached
|
||||
|
||||
#ifdef SHARED_METADATA_CACHE
|
||||
if (config->getSharedCache())
|
||||
{
|
||||
for (dbb = databases; dbb; dbb = dbb->dbb_next)
|
||||
{
|
||||
if (!(dbb->dbb_flags & (DBB_bugcheck | DBB_not_in_use)) &&
|
||||
@ -5510,14 +5590,12 @@ static Database* init(thread_db* tdbb,
|
||||
Arg::Gds(isc_obj_in_use) << Arg::Str("DATABASE"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
dbb = Database::create();
|
||||
dbb->dbb_config = config;
|
||||
tdbb->setDatabase(dbb);
|
||||
|
||||
dbb->dbb_bufferpool = dbb->createPool();
|
||||
|
||||
// provide context pool for the rest stuff
|
||||
Jrd::ContextPoolHolder context(tdbb, dbb->dbb_permanent);
|
||||
|
||||
@ -5705,9 +5783,9 @@ static void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment)
|
||||
|
||||
dbb->dbb_extManager.closeAttachment(tdbb, attachment);
|
||||
|
||||
if (dbb->dbb_config->getSharedCache() && dbb->dbb_relations)
|
||||
if (!dbb->dbb_config->getSharedDatabase() && attachment->att_relations)
|
||||
{
|
||||
vec<jrd_rel*>& rels = *dbb->dbb_relations;
|
||||
vec<jrd_rel*>& rels = *attachment->att_relations;
|
||||
for (size_t i = 1; i < rels.count(); i++)
|
||||
{
|
||||
jrd_rel* relation = rels[i];
|
||||
@ -5724,6 +5802,8 @@ static void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment)
|
||||
dbb->dbb_event_mgr->deleteSession(attachment->att_event_session);
|
||||
}
|
||||
|
||||
attachment->shutdown(tdbb);
|
||||
|
||||
if (attachment->att_id_lock)
|
||||
LCK_release(tdbb, attachment->att_id_lock);
|
||||
|
||||
@ -5764,7 +5844,7 @@ static void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment)
|
||||
{
|
||||
MemoryPool* const pool = &attachment->att_dsql_instance->dbb_pool;
|
||||
delete attachment->att_dsql_instance;
|
||||
dbb->deletePool(pool);
|
||||
attachment->deletePool(pool);
|
||||
}
|
||||
|
||||
// remove the attachment block from the dbb linked list
|
||||
@ -5781,8 +5861,8 @@ static void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment)
|
||||
// CMP_release() changes att_requests.
|
||||
while (!attachment->att_requests.isEmpty())
|
||||
CMP_release(tdbb, attachment->att_requests.back());
|
||||
|
||||
for (JrdStatement** i = dbb->dbb_internal.begin(); i != dbb->dbb_internal.end(); ++i)
|
||||
/**
|
||||
for (JrdStatement** i = attachment->att_internal.begin(); i != attachment->att_internal.end(); ++i)
|
||||
{
|
||||
if (*i)
|
||||
{
|
||||
@ -5790,13 +5870,16 @@ static void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment)
|
||||
|
||||
for (jrd_req** j = stmt->requests.begin(); j != stmt->requests.end(); ++j)
|
||||
{
|
||||
if (*j && (*j)->req_attachment == attachment)
|
||||
if (*j)
|
||||
{
|
||||
fb_assert(!(*j)->req_attachment || (*j)->req_attachment == attachment);
|
||||
EXE_release(tdbb, *j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (JrdStatement** i = dbb->dbb_dyn_req.begin(); i != dbb->dbb_dyn_req.end(); ++i)
|
||||
for (JrdStatement** i = attachment->att_dyn_req.begin(); i != attachment->att_dyn_req.end(); ++i)
|
||||
{
|
||||
if (*i)
|
||||
{
|
||||
@ -5804,11 +5887,46 @@ static void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment)
|
||||
|
||||
for (jrd_req** j = stmt->requests.begin(); j != stmt->requests.end(); ++j)
|
||||
{
|
||||
if (*j && (*j)->req_attachment == attachment)
|
||||
if (*j)
|
||||
{
|
||||
fb_assert(!(*j)->req_attachment || (*j)->req_attachment == attachment);
|
||||
EXE_release(tdbb, *j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
**/
|
||||
|
||||
MET_clear_cache(tdbb);
|
||||
|
||||
// Shut down any extern relations
|
||||
|
||||
if (attachment->att_relations)
|
||||
{
|
||||
vec<jrd_rel*>* vector = attachment->att_relations;
|
||||
vec<jrd_rel*>::iterator ptr = vector->begin(), end = vector->end();
|
||||
|
||||
while (ptr < end)
|
||||
{
|
||||
jrd_rel* relation = *ptr++;
|
||||
if (relation)
|
||||
{
|
||||
if (relation->rel_file)
|
||||
{
|
||||
EXT_fini(relation, false);
|
||||
}
|
||||
|
||||
for (IndexBlock* index_block = relation->rel_index_blocks; index_block;
|
||||
index_block = index_block->idb_next)
|
||||
{
|
||||
if (index_block->idb_lock)
|
||||
LCK_release(tdbb, index_block->idb_lock);
|
||||
}
|
||||
|
||||
delete relation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCL_release_all(attachment->att_security_classes);
|
||||
|
||||
@ -5917,8 +6035,6 @@ static void shutdown_database(Database* dbb, const bool release_pools)
|
||||
TRA_header_write(tdbb, dbb, 0L); // Update transaction info on header page.
|
||||
#endif
|
||||
|
||||
MET_clear_cache(tdbb);
|
||||
|
||||
#ifdef GARBAGE_THREAD
|
||||
VIO_fini(tdbb);
|
||||
#endif
|
||||
@ -5938,36 +6054,6 @@ static void shutdown_database(Database* dbb, const bool release_pools)
|
||||
LCK_release(tdbb, dbb->dbb_retaining_lock);
|
||||
|
||||
dbb->dbb_shared_counter.shutdown(tdbb);
|
||||
dbb->destroyIntlObjects();
|
||||
|
||||
// Shut down any extern relations
|
||||
|
||||
if (dbb->dbb_relations)
|
||||
{
|
||||
vec<jrd_rel*>* vector = dbb->dbb_relations;
|
||||
vec<jrd_rel*>::iterator ptr = vector->begin(), end = vector->end();
|
||||
|
||||
while (ptr < end)
|
||||
{
|
||||
jrd_rel* relation = *ptr++;
|
||||
if (relation)
|
||||
{
|
||||
if (relation->rel_file)
|
||||
{
|
||||
EXT_fini(relation, false);
|
||||
}
|
||||
|
||||
for (IndexBlock* index_block = relation->rel_index_blocks; index_block;
|
||||
index_block = index_block->idb_next)
|
||||
{
|
||||
if (index_block->idb_lock)
|
||||
LCK_release(tdbb, index_block->idb_lock);
|
||||
}
|
||||
|
||||
delete relation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dbb->dbb_lock)
|
||||
LCK_release(tdbb, dbb->dbb_lock);
|
||||
@ -6138,7 +6224,7 @@ UCHAR* JRD_num_attachments(UCHAR* const buf, USHORT buf_len, JRD_info_tag flag,
|
||||
|
||||
for (Database* dbb = databases; dbb; dbb = dbb->dbb_next)
|
||||
{
|
||||
Database::SyncGuard dsGuard(dbb);
|
||||
SyncLockGuard guard(&dbb->dbb_sync, SYNC_SHARED, "JRD_num_attachments");
|
||||
|
||||
#ifdef WIN_NT
|
||||
// Get drive letters for db files
|
||||
@ -6420,7 +6506,7 @@ static void purge_attachment(thread_db* tdbb, Jrd::Attachment* attachment, const
|
||||
{
|
||||
try
|
||||
{
|
||||
const trig_vec* trig_disconnect = dbb->dbb_triggers[DB_TRIGGER_DISCONNECT];
|
||||
const trig_vec* trig_disconnect = attachment->att_triggers[DB_TRIGGER_DISCONNECT];
|
||||
if (!(attachment->att_flags & ATT_no_db_triggers) &&
|
||||
!(attachment->att_flags & ATT_shutdown) &&
|
||||
trig_disconnect && !trig_disconnect->isEmpty())
|
||||
@ -7173,7 +7259,6 @@ static void start_transaction(thread_db* tdbb, bool transliterate, jrd_tra** tra
|
||||
transliterateException(tdbb, ex, &tempStatus);
|
||||
status_exception::raise(tempStatus.get());
|
||||
}
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@ -7326,7 +7411,7 @@ namespace
|
||||
#endif
|
||||
|
||||
|
||||
void JRD_shutdown_attachments(const Database* dbb)
|
||||
void JRD_shutdown_attachments(Database* dbb)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -7346,6 +7431,10 @@ void JRD_shutdown_attachments(const Database* dbb)
|
||||
MemoryPool& pool = *getDefaultMemoryPool();
|
||||
PingQueue* const queue = FB_NEW(pool) PingQueue(pool);
|
||||
|
||||
Sync guard(&dbb->dbb_sync, "JRD_shutdown_attachments");
|
||||
if (!dbb->dbb_sync.ourExclusiveLock())
|
||||
guard.lock(SYNC_SHARED);
|
||||
|
||||
for (const Jrd::Attachment* attachment = dbb->dbb_attachments;
|
||||
attachment; attachment = attachment->att_next)
|
||||
{
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "../common/classes/stack.h"
|
||||
#include "../common/classes/timestamp.h"
|
||||
#include "../common/classes/GenericMap.h"
|
||||
#include "../common/classes/Synchronize.h"
|
||||
#include "../common/utils_proto.h"
|
||||
#include "../common/StatusHolder.h"
|
||||
#include "../jrd/RandomGenerator.h"
|
||||
@ -123,7 +124,7 @@ class JrdStatement;
|
||||
class Lock;
|
||||
class jrd_file;
|
||||
class Format;
|
||||
class BufferControl;
|
||||
class BufferDesc;
|
||||
class SparseBitmap;
|
||||
class jrd_rel;
|
||||
class ExternalFile;
|
||||
@ -179,7 +180,6 @@ public:
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Flags to indicate normal internal requests vs. dyn internal requests
|
||||
//
|
||||
@ -407,7 +407,8 @@ private:
|
||||
|
||||
public:
|
||||
explicit thread_db(ISC_STATUS* status)
|
||||
: ThreadData(ThreadData::tddDBB)
|
||||
: ThreadData(ThreadData::tddDBB),
|
||||
tdbb_bdbs(*getDefaultMemoryPool())
|
||||
{
|
||||
tdbb_default = NULL;
|
||||
database = NULL;
|
||||
@ -417,19 +418,33 @@ public:
|
||||
tdbb_quantum = QUANTUM;
|
||||
tdbb_flags = 0;
|
||||
tdbb_temp_traid = 0;
|
||||
QUE_INIT(tdbb_latches);
|
||||
reqStat = traStat = attStat = dbbStat = RuntimeStatistics::getDummy();
|
||||
|
||||
tdbb_status_vector = status;
|
||||
fb_utils::init_status(tdbb_status_vector);
|
||||
|
||||
tdbb_thread = Firebird::ThreadSync::getThread("thread_db");
|
||||
}
|
||||
|
||||
~thread_db()
|
||||
{
|
||||
#ifdef DEV_BUILD
|
||||
for (size_t n = 0; n < tdbb_bdbs.getCount(); n++)
|
||||
{
|
||||
fb_assert(tdbb_bdbs[n] == NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ISC_STATUS* tdbb_status_vector;
|
||||
SSHORT tdbb_quantum; // Cycles remaining until voluntary schedule
|
||||
USHORT tdbb_flags;
|
||||
|
||||
SLONG tdbb_temp_traid; // current temporary table scope
|
||||
|
||||
que tdbb_latches; // shared latches held by thread
|
||||
// BDB's held by thread
|
||||
Firebird::HalfStaticArray<BufferDesc*, 16> tdbb_bdbs;
|
||||
Firebird::ThreadSync* tdbb_thread;
|
||||
|
||||
MemoryPool* getDefaultPool()
|
||||
{
|
||||
@ -507,6 +522,44 @@ public:
|
||||
}
|
||||
|
||||
bool checkCancelState(bool punt);
|
||||
|
||||
void registerBdb(BufferDesc* bdb)
|
||||
{
|
||||
size_t pos;
|
||||
if (tdbb_bdbs.find(NULL, pos))
|
||||
tdbb_bdbs[pos] = bdb;
|
||||
else
|
||||
tdbb_bdbs.add(bdb);
|
||||
}
|
||||
|
||||
void clearBdb(BufferDesc* bdb)
|
||||
{
|
||||
size_t pos;
|
||||
if (tdbb_bdbs.find(bdb, pos))
|
||||
{
|
||||
tdbb_bdbs[pos] = NULL;
|
||||
|
||||
if (pos == tdbb_bdbs.getCount() - 1)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (tdbb_bdbs[pos] != NULL)
|
||||
{
|
||||
tdbb_bdbs.shrink(pos + 1);
|
||||
break;
|
||||
}
|
||||
if (pos == 0)
|
||||
{
|
||||
tdbb_bdbs.shrink(0);
|
||||
break;
|
||||
}
|
||||
pos--;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
fb_assert(false);
|
||||
}
|
||||
};
|
||||
|
||||
// tdbb_flags
|
||||
|
@ -86,6 +86,6 @@ void JRD_compile(Jrd::thread_db* tdbb, Jrd::Attachment* attachment, Jrd::jrd_req
|
||||
ULONG blr_length, const UCHAR* blr, Firebird::RefStrPtr,
|
||||
ULONG dbginfo_length, const UCHAR* dbginfo, bool isInternalRequest);
|
||||
bool JRD_verify_database_access(const Firebird::PathName&);
|
||||
void JRD_shutdown_attachments(const Jrd::Database* dbb);
|
||||
void JRD_shutdown_attachments(Jrd::Database* dbb);
|
||||
void JRD_cancel_operation(Jrd::thread_db* tdbb, Jrd::Attachment* attachment, int option);
|
||||
#endif /* JRD_JRD_PROTO_H */
|
||||
|
@ -74,6 +74,26 @@ static bool internal_enqueue(thread_db*, Arg::StatusVector&, Lock*, USHORT, SSHO
|
||||
static void set_lock_attachment(Lock*, Jrd::Attachment*);
|
||||
|
||||
|
||||
#ifdef DEBUG_LCK
|
||||
class LckSync
|
||||
{
|
||||
public:
|
||||
LckSync(Lock* lock, const char* sWhere) :
|
||||
m_sync(&lock->lck_sync, sWhere)
|
||||
{
|
||||
ThreadSync *thd = ThreadSync::getThread(NULL);
|
||||
m_sync.lock(SYNC_EXCLUSIVE);
|
||||
}
|
||||
|
||||
~LckSync()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
Sync m_sync;
|
||||
};
|
||||
#endif
|
||||
|
||||
// globals and macros
|
||||
|
||||
inline LOCK_OWNER_T LCK_OWNER_ID_DBB(thread_db* tdbb)
|
||||
@ -83,11 +103,10 @@ inline LOCK_OWNER_T LCK_OWNER_ID_DBB(thread_db* tdbb)
|
||||
|
||||
inline LOCK_OWNER_T LCK_OWNER_ID_ATT(thread_db* tdbb)
|
||||
{
|
||||
#ifdef SHARED_METADATA_CACHE
|
||||
if (tdbb->getDatabase()->dbb_config->getSharedCache())
|
||||
return (LOCK_OWNER_T) getpid() << 32 | tdbb->getAttachment()->att_lock_owner_id;
|
||||
#else
|
||||
else
|
||||
return (LOCK_OWNER_T) getpid() << 32 | tdbb->getDatabase()->dbb_lock_owner_id;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline SLONG* LCK_OWNER_HANDLE_DBB(thread_db* tdbb)
|
||||
@ -97,11 +116,10 @@ inline SLONG* LCK_OWNER_HANDLE_DBB(thread_db* tdbb)
|
||||
|
||||
inline SLONG* LCK_OWNER_HANDLE_ATT(thread_db* tdbb)
|
||||
{
|
||||
#ifdef SHARED_METADATA_CACHE
|
||||
if (tdbb->getDatabase()->dbb_config->getSharedCache())
|
||||
return &tdbb->getAttachment()->att_lock_owner_handle;
|
||||
#else
|
||||
else
|
||||
return &tdbb->getDatabase()->dbb_lock_owner_handle;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -134,10 +152,11 @@ inline void ENQUEUE(thread_db* tdbb, Arg::StatusVector& statusVector, Lock* lock
|
||||
inline bool CONVERT(thread_db* tdbb, Arg::StatusVector& statusVector, Lock* lock, USHORT level, SSHORT wait)
|
||||
{
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* const att = tdbb->getAttachment();
|
||||
|
||||
return lock->lck_compatible ?
|
||||
internal_enqueue(tdbb, statusVector, lock, level, wait, true) :
|
||||
dbb->dbb_lock_mgr->convert(dbb, statusVector, lock->lck_id, level, wait, lock->lck_ast,
|
||||
dbb->dbb_lock_mgr->convert(att, statusVector, lock->lck_id, level, wait, lock->lck_ast,
|
||||
lock->lck_object);
|
||||
}
|
||||
|
||||
@ -154,12 +173,13 @@ inline void DEQUEUE(thread_db* tdbb, Lock* lock)
|
||||
inline USHORT DOWNGRADE(thread_db* tdbb, Lock* lock)
|
||||
{
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* const att = tdbb->getAttachment();
|
||||
|
||||
Arg::StatusVector statusVector;
|
||||
|
||||
USHORT ret = lock->lck_compatible ?
|
||||
internal_downgrade(tdbb, statusVector, lock) :
|
||||
dbb->dbb_lock_mgr->downgrade(dbb, statusVector, lock->lck_id);
|
||||
dbb->dbb_lock_mgr->downgrade(att, statusVector, lock->lck_id);
|
||||
|
||||
fb_assert(statusVector.isEmpty());
|
||||
|
||||
@ -192,7 +212,7 @@ inline bool checkLock(const Lock* l)
|
||||
|
||||
/* The following check should be part of LCK_CHECK_LOCK, but it fails
|
||||
when the exclusive attachment to a database is changed to a shared
|
||||
attachment. When that occurs we fb_assert all our internal locks, but
|
||||
attachment. When that occurs we assert all our internal locks, but
|
||||
while we are in the process of asserting DBB_assert_locks is set, but
|
||||
we haven't gotten physical locks yet.
|
||||
|
||||
@ -221,7 +241,7 @@ public:
|
||||
m_save_lock(NULL)
|
||||
{
|
||||
Jrd::Attachment* att = m_tdbb->getAttachment();
|
||||
m_save_lock = att->att_wait_lock;
|
||||
m_save_lock = att ? att->att_wait_lock : NULL;
|
||||
|
||||
m_cancel_disabled = (m_tdbb->tdbb_flags & TDBB_wait_cancel_disable);
|
||||
m_tdbb->tdbb_flags |= TDBB_wait_cancel_disable;
|
||||
@ -231,15 +251,23 @@ public:
|
||||
|
||||
if (lock->lck_type == LCK_tra)
|
||||
{
|
||||
fb_assert(att);
|
||||
|
||||
m_tdbb->tdbb_flags &= ~TDBB_wait_cancel_disable;
|
||||
if (att)
|
||||
{
|
||||
att->att_wait_lock = lock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~WaitCancelGuard()
|
||||
{
|
||||
Jrd::Attachment* att = m_tdbb->getAttachment();
|
||||
if (att)
|
||||
{
|
||||
att->att_wait_lock = m_save_lock;
|
||||
}
|
||||
|
||||
if (m_cancel_disabled)
|
||||
m_tdbb->tdbb_flags |= TDBB_wait_cancel_disable;
|
||||
@ -298,6 +326,10 @@ bool LCK_convert(thread_db* tdbb, Lock* lock, USHORT level, SSHORT wait)
|
||||
SET_TDBB(tdbb);
|
||||
fb_assert(LCK_CHECK_LOCK(lock));
|
||||
|
||||
#ifdef DEBUG_LCK
|
||||
LckSync sync(lock, "LCK_convert");
|
||||
#endif
|
||||
|
||||
Database* dbb = lock->lck_dbb;
|
||||
|
||||
Jrd::Attachment* const old_attachment = lock->lck_attachment;
|
||||
@ -305,6 +337,7 @@ bool LCK_convert(thread_db* tdbb, Lock* lock, USHORT level, SSHORT wait)
|
||||
|
||||
WaitCancelGuard guard(tdbb, lock, wait);
|
||||
Arg::StatusVector statusVector;
|
||||
|
||||
const bool result = CONVERT(tdbb, statusVector, lock, level, wait);
|
||||
|
||||
if (!result)
|
||||
@ -401,6 +434,10 @@ void LCK_downgrade(thread_db* tdbb, Lock* lock)
|
||||
SET_TDBB(tdbb);
|
||||
fb_assert(LCK_CHECK_LOCK(lock));
|
||||
|
||||
#ifdef DEBUG_LCK
|
||||
LckSync sync(lock, "LCK_downgrade");
|
||||
#endif
|
||||
|
||||
if (lock->lck_id && lock->lck_physical != LCK_none)
|
||||
{
|
||||
const USHORT level = DOWNGRADE(tdbb, lock);
|
||||
@ -434,6 +471,7 @@ void LCK_fini(thread_db* tdbb, enum lck_owner_t owner_type)
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* const att = tdbb->getAttachment();
|
||||
|
||||
switch (owner_type)
|
||||
{
|
||||
@ -450,7 +488,7 @@ void LCK_fini(thread_db* tdbb, enum lck_owner_t owner_type)
|
||||
break;
|
||||
}
|
||||
|
||||
dbb->dbb_lock_mgr->shutdownOwner(dbb, owner_handle_ptr);
|
||||
dbb->dbb_lock_mgr->shutdownOwner(att, owner_handle_ptr);
|
||||
}
|
||||
|
||||
|
||||
@ -607,6 +645,10 @@ bool LCK_lock(thread_db* tdbb, Lock* lock, USHORT level, SSHORT wait)
|
||||
SET_TDBB(tdbb);
|
||||
fb_assert(LCK_CHECK_LOCK(lock));
|
||||
|
||||
#ifdef DEBUG_LCK
|
||||
LckSync sync(lock, "LCK_lock");
|
||||
#endif
|
||||
|
||||
Database* dbb = lock->lck_dbb;
|
||||
set_lock_attachment(lock, tdbb->getAttachment());
|
||||
|
||||
@ -615,6 +657,7 @@ bool LCK_lock(thread_db* tdbb, Lock* lock, USHORT level, SSHORT wait)
|
||||
|
||||
ENQUEUE(tdbb, statusVector, lock, level, wait);
|
||||
fb_assert(LCK_CHECK_LOCK(lock));
|
||||
|
||||
if (!lock->lck_id)
|
||||
{
|
||||
set_lock_attachment(lock, NULL);
|
||||
@ -752,6 +795,10 @@ void LCK_release(thread_db* tdbb, Lock* lock)
|
||||
SET_TDBB(tdbb);
|
||||
fb_assert(LCK_CHECK_LOCK(lock));
|
||||
|
||||
#ifdef DEBUG_LCK
|
||||
LckSync sync(lock, "LCK_release");
|
||||
#endif
|
||||
|
||||
if (lock->lck_physical != LCK_none) {
|
||||
DEQUEUE(tdbb, lock);
|
||||
}
|
||||
@ -779,6 +826,7 @@ void LCK_re_post(thread_db* tdbb, Lock* lock)
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* const att = tdbb->getAttachment();
|
||||
|
||||
fb_assert(LCK_CHECK_LOCK(lock));
|
||||
|
||||
@ -790,7 +838,7 @@ void LCK_re_post(thread_db* tdbb, Lock* lock)
|
||||
return;
|
||||
}
|
||||
|
||||
dbb->dbb_lock_mgr->repost(dbb, lock->lck_ast, lock->lck_object, lock->lck_owner_handle);
|
||||
dbb->dbb_lock_mgr->repost(att, lock->lck_ast, lock->lck_object, lock->lck_owner_handle);
|
||||
|
||||
fb_assert(LCK_CHECK_LOCK(lock));
|
||||
}
|
||||
@ -892,11 +940,12 @@ static void enqueue(thread_db* tdbb, Arg::StatusVector& statusVector, Lock* lock
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* const att = tdbb->getAttachment();
|
||||
|
||||
fb_assert(LCK_CHECK_LOCK(lock));
|
||||
|
||||
Lock* parent = lock->lck_parent;
|
||||
lock->lck_id = dbb->dbb_lock_mgr->enqueue(dbb, statusVector, lock->lck_id,
|
||||
lock->lck_id = dbb->dbb_lock_mgr->enqueue(att, statusVector, lock->lck_id,
|
||||
(parent ? parent->lck_id : 0), lock->lck_type, (const UCHAR*) &lock->lck_key,
|
||||
lock->lck_length, level, lock->lck_ast, lock->lck_object, lock->lck_data, wait,
|
||||
lock->lck_owner_handle);
|
||||
@ -1306,6 +1355,7 @@ static USHORT internal_downgrade(thread_db* tdbb, Arg::StatusVector& statusVecto
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* const att = tdbb->getAttachment();
|
||||
|
||||
fb_assert(LCK_CHECK_LOCK(first));
|
||||
fb_assert(first->lck_compatible);
|
||||
@ -1320,7 +1370,7 @@ static USHORT internal_downgrade(thread_db* tdbb, Arg::StatusVector& statusVecto
|
||||
|
||||
if (level < first->lck_physical)
|
||||
{
|
||||
if (dbb->dbb_lock_mgr->convert(dbb, statusVector, first->lck_id, level, LCK_NO_WAIT,
|
||||
if (dbb->dbb_lock_mgr->convert(att, statusVector, first->lck_id, level, LCK_NO_WAIT,
|
||||
external_ast, first))
|
||||
{
|
||||
for (Lock* lock = first; lock; lock = lock->lck_identical)
|
||||
@ -1357,6 +1407,7 @@ static bool internal_enqueue(thread_db* tdbb, Arg::StatusVector& statusVector, L
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* const att = tdbb->getAttachment();
|
||||
|
||||
fb_assert(LCK_CHECK_LOCK(lock));
|
||||
fb_assert(lock->lck_compatible);
|
||||
@ -1387,7 +1438,7 @@ static bool internal_enqueue(thread_db* tdbb, Arg::StatusVector& statusVector, L
|
||||
|
||||
if (level > match->lck_physical)
|
||||
{
|
||||
if (!dbb->dbb_lock_mgr->convert(dbb, statusVector, match->lck_id, level, wait,
|
||||
if (!dbb->dbb_lock_mgr->convert(att, statusVector, match->lck_id, level, wait,
|
||||
external_ast, lock))
|
||||
{
|
||||
return false;
|
||||
@ -1416,7 +1467,7 @@ static bool internal_enqueue(thread_db* tdbb, Arg::StatusVector& statusVector, L
|
||||
// enqueue the lock, but swap out the ast and the ast argument
|
||||
// with the local ast handler, passing it the lock block itself
|
||||
|
||||
lock->lck_id = dbb->dbb_lock_mgr->enqueue(dbb, statusVector, lock->lck_id,
|
||||
lock->lck_id = dbb->dbb_lock_mgr->enqueue(att, statusVector, lock->lck_id,
|
||||
(lock->lck_parent ? lock->lck_parent->lck_id : 0), lock->lck_type,
|
||||
(const UCHAR*) &lock->lck_key, lock->lck_length, level, external_ast, lock, lock->lck_data,
|
||||
wait, lock->lck_owner_handle);
|
||||
@ -1446,6 +1497,16 @@ static void set_lock_attachment(Lock* lock, Jrd::Attachment* attachment)
|
||||
if (lock->lck_attachment == attachment)
|
||||
return;
|
||||
|
||||
Database* dbb = attachment ? attachment->att_database :
|
||||
(lock->lck_attachment ? lock->lck_attachment->att_database : NULL);
|
||||
|
||||
fb_assert(dbb);
|
||||
if (!dbb)
|
||||
return;
|
||||
|
||||
Sync lckSync(&dbb->dbb_lck_sync, "set_lock_attachment");
|
||||
lckSync.lock(SYNC_EXCLUSIVE);
|
||||
|
||||
// If lock has an attachment it must not be a part of linked list
|
||||
fb_assert(!lock->lck_attachment ? !lock->lck_prior && !lock->lck_next : true);
|
||||
|
||||
|
@ -24,6 +24,12 @@
|
||||
#ifndef JRD_LCK_H
|
||||
#define JRD_LCK_H
|
||||
|
||||
//#define DEBUG_LCK
|
||||
|
||||
#ifdef DEBUG_LCK
|
||||
#include "../common/classes/SyncObject.h"
|
||||
#endif
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
class Database;
|
||||
@ -93,6 +99,10 @@ public:
|
||||
lck_tail[0] = 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LCK
|
||||
Firebird::SyncObject lck_sync;
|
||||
#endif
|
||||
|
||||
Lock* lck_parent;
|
||||
|
||||
Lock* lck_next; // lck_next and lck_prior form a doubly linked list of locks
|
||||
|
164
src/jrd/met.epp
164
src/jrd/met.epp
@ -222,7 +222,7 @@ void MET_get_domain(thread_db* tdbb, const MetaName& name, dsc* desc, FieldInfo*
|
||||
{
|
||||
fieldInfo->nullable = FLD.RDB$NULL_FLAG.NULL || FLD.RDB$NULL_FLAG == 0;
|
||||
|
||||
MemoryPool* csb_pool = dbb->createPool();
|
||||
MemoryPool* csb_pool = attachment->createPool();
|
||||
Jrd::ContextPoolHolder context(tdbb, csb_pool);
|
||||
try
|
||||
{
|
||||
@ -245,7 +245,7 @@ void MET_get_domain(thread_db* tdbb, const MetaName& name, dsc* desc, FieldInfo*
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
dbb->deletePool(csb_pool);
|
||||
attachment->deletePool(csb_pool);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@ -308,7 +308,7 @@ MetaName MET_get_relation_field(thread_db* tdbb,
|
||||
fieldInfo->nullable = RFL.RDB$NULL_FLAG.NULL ?
|
||||
(FLD.RDB$NULL_FLAG.NULL || FLD.RDB$NULL_FLAG == 0) : RFL.RDB$NULL_FLAG == 0;
|
||||
|
||||
MemoryPool* csb_pool = dbb->createPool();
|
||||
MemoryPool* csb_pool = attachment->createPool();
|
||||
Jrd::ContextPoolHolder context(tdbb, csb_pool);
|
||||
try
|
||||
{
|
||||
@ -338,7 +338,7 @@ MetaName MET_get_relation_field(thread_db* tdbb,
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
dbb->deletePool(csb_pool);
|
||||
attachment->deletePool(csb_pool);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@ -371,9 +371,9 @@ void MET_update_partners(thread_db* tdbb)
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
|
||||
vec<jrd_rel*>* relations = dbb->dbb_relations;
|
||||
vec<jrd_rel*>* relations = attachment->att_relations;
|
||||
|
||||
vec<jrd_rel*>::iterator ptr = relations->begin();
|
||||
for (const vec<jrd_rel*>::const_iterator end = relations->end(); ptr < end; ++ptr)
|
||||
@ -435,9 +435,11 @@ void MET_verify_cache(thread_db* tdbb)
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* att = tdbb->getAttachment();
|
||||
if (!att)
|
||||
return;
|
||||
|
||||
vec<jrd_prc*>* procedures = dbb->dbb_procedures;
|
||||
vec<jrd_prc*>* procedures = att->att_procedures;
|
||||
if (procedures)
|
||||
{
|
||||
jrd_prc* procedure;
|
||||
@ -538,12 +540,13 @@ void MET_clear_cache(thread_db* tdbb)
|
||||
#endif
|
||||
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* att = tdbb->getAttachment();
|
||||
|
||||
for (int i = 0; i < DB_TRIGGER_MAX; i++) {
|
||||
release_cached_triggers(tdbb, dbb->dbb_triggers[i]);
|
||||
release_cached_triggers(tdbb, att->att_triggers[i]);
|
||||
}
|
||||
|
||||
vec<jrd_rel*>* relations = dbb->dbb_relations;
|
||||
vec<jrd_rel*>* relations = att->att_relations;
|
||||
if (relations)
|
||||
{ // scope
|
||||
vec<jrd_rel*>::iterator ptr, end;
|
||||
@ -561,7 +564,7 @@ void MET_clear_cache(thread_db* tdbb)
|
||||
}
|
||||
} // scope
|
||||
|
||||
vec<jrd_prc*>* procedures = dbb->dbb_procedures;
|
||||
vec<jrd_prc*>* procedures = att->att_procedures;
|
||||
if (procedures)
|
||||
{
|
||||
jrd_prc* procedure;
|
||||
@ -645,14 +648,15 @@ bool MET_procedure_in_use(thread_db* tdbb, jrd_prc* proc)
|
||||
MET_verify_cache(tdbb);
|
||||
#endif
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* att = tdbb->getAttachment();
|
||||
|
||||
// This should not really happen
|
||||
vec<jrd_prc*>* procedures = dbb->dbb_procedures;
|
||||
vec<jrd_prc*>* procedures = att->att_procedures;
|
||||
if (!procedures) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vec<jrd_rel*>* relations = dbb->dbb_relations;
|
||||
vec<jrd_rel*>* relations = att->att_relations;
|
||||
{ // scope
|
||||
vec<jrd_rel*>::iterator ptr, end;
|
||||
for (ptr = relations->begin(), end = relations->end(); ptr < end; ++ptr)
|
||||
@ -1230,7 +1234,7 @@ Format* MET_format(thread_db* tdbb, jrd_rel* relation, USHORT number)
|
||||
unsigned bufferPos = 2;
|
||||
USHORT count = buffer[0] | (buffer[1] << 8);
|
||||
|
||||
format = Format::newFormat(*dbb->dbb_permanent, count);
|
||||
format = Format::newFormat(*relation->rel_pool, count);
|
||||
|
||||
Array<Ods::Descriptor> odsDescs;
|
||||
Ods::Descriptor* odsDesc = odsDescs.getBuffer(count);
|
||||
@ -1266,14 +1270,14 @@ Format* MET_format(thread_db* tdbb, jrd_rel* relation, USHORT number)
|
||||
END_FOR
|
||||
|
||||
if (!format)
|
||||
format = Format::newFormat(*dbb->dbb_permanent);
|
||||
format = Format::newFormat(*relation->rel_pool);
|
||||
|
||||
format->fmt_version = number;
|
||||
|
||||
// Link the format block into the world
|
||||
|
||||
formats = relation->rel_formats =
|
||||
vec<Format*>::newVector(*dbb->dbb_permanent, relation->rel_formats, number + 1);
|
||||
vec<Format*>::newVector(*relation->rel_pool, relation->rel_formats, number + 1);
|
||||
(*formats)[number] = format;
|
||||
|
||||
return format;
|
||||
@ -1596,14 +1600,14 @@ void MET_load_db_triggers(thread_db* tdbb, int type)
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
CHECK_DBB(dbb);
|
||||
|
||||
if ((tdbb->getAttachment()->att_flags & ATT_no_db_triggers) ||
|
||||
tdbb->getDatabase()->dbb_triggers[type] != NULL)
|
||||
if ((attachment->att_flags & ATT_no_db_triggers) ||
|
||||
attachment->att_triggers[type] != NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tdbb->getDatabase()->dbb_triggers[type] = FB_NEW(*tdbb->getDatabase()->dbb_permanent)
|
||||
trig_vec(*tdbb->getDatabase()->dbb_permanent);
|
||||
attachment->att_triggers[type] = FB_NEW(*attachment->att_pool)
|
||||
trig_vec(*attachment->att_pool);
|
||||
|
||||
AutoRequest trigger_request;
|
||||
int encoded_type = type | TRIGGER_TYPE_DB;
|
||||
@ -1615,7 +1619,7 @@ void MET_load_db_triggers(thread_db* tdbb, int type)
|
||||
TRG.RDB$TRIGGER_INACTIVE EQ 0
|
||||
SORTED BY TRG.RDB$TRIGGER_SEQUENCE
|
||||
{
|
||||
MET_load_trigger(tdbb, NULL, TRG.RDB$TRIGGER_NAME, &tdbb->getDatabase()->dbb_triggers[type]);
|
||||
MET_load_trigger(tdbb, NULL, TRG.RDB$TRIGGER_NAME, &attachment->att_triggers[type]);
|
||||
}
|
||||
END_FOR
|
||||
}
|
||||
@ -1629,13 +1633,13 @@ void MET_load_ddl_triggers(thread_db* tdbb)
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
CHECK_DBB(dbb);
|
||||
|
||||
if ((tdbb->getAttachment()->att_flags & ATT_no_db_triggers) ||
|
||||
tdbb->getDatabase()->dbb_ddl_triggers != NULL)
|
||||
if ((attachment->att_flags & ATT_no_db_triggers) ||
|
||||
attachment->att_ddl_triggers != NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tdbb->getDatabase()->dbb_ddl_triggers = FB_NEW(*tdbb->getDatabase()->dbb_permanent)
|
||||
attachment->att_ddl_triggers = FB_NEW(*tdbb->getDatabase()->dbb_permanent)
|
||||
trig_vec(*tdbb->getDatabase()->dbb_permanent);
|
||||
|
||||
AutoRequest trigger_request;
|
||||
@ -1649,7 +1653,7 @@ void MET_load_ddl_triggers(thread_db* tdbb)
|
||||
if ((TRG.RDB$TRIGGER_TYPE & TRIGGER_TYPE_MASK) == TRIGGER_TYPE_DDL)
|
||||
{
|
||||
MET_load_trigger(tdbb, NULL, TRG.RDB$TRIGGER_NAME,
|
||||
&tdbb->getDatabase()->dbb_ddl_triggers);
|
||||
&attachment->att_ddl_triggers);
|
||||
}
|
||||
}
|
||||
END_FOR
|
||||
@ -2196,7 +2200,6 @@ bool MET_lookup_partner(thread_db* tdbb, jrd_rel* relation, index_desc* idx, con
|
||||
SET_TDBB(tdbb);
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Database::CheckoutLockGuard guard(dbb, dbb->dbb_meta_mutex);
|
||||
|
||||
if (relation->rel_flags & REL_check_partners) {
|
||||
scan_partners(tdbb, relation);
|
||||
@ -2297,7 +2300,7 @@ jrd_prc* MET_lookup_procedure(thread_db* tdbb, const QualifiedName& name, bool n
|
||||
jrd_prc* check_procedure = NULL;
|
||||
|
||||
// See if we already know the procedure by name
|
||||
vec<jrd_prc*>* procedures = dbb->dbb_procedures;
|
||||
vec<jrd_prc*>* procedures = attachment->att_procedures;
|
||||
if (procedures)
|
||||
{
|
||||
vec<jrd_prc*>::iterator ptr = procedures->begin();
|
||||
@ -2373,7 +2376,7 @@ jrd_prc* MET_lookup_procedure_id(thread_db* tdbb, SSHORT id,
|
||||
|
||||
jrd_prc* procedure;
|
||||
|
||||
vec<jrd_prc*>* procedures = dbb->dbb_procedures;
|
||||
vec<jrd_prc*>* procedures = attachment->att_procedures;
|
||||
if (procedures && id < (SSHORT) procedures->count() && (procedure = (*procedures)[id]) &&
|
||||
procedure->getId() == id &&
|
||||
!(procedure->prc_flags & PRC_being_scanned) &&
|
||||
@ -2437,7 +2440,7 @@ jrd_rel* MET_lookup_relation(thread_db* tdbb, const MetaName& name)
|
||||
|
||||
// See if we already know the relation by name
|
||||
|
||||
vec<jrd_rel*>* relations = dbb->dbb_relations;
|
||||
vec<jrd_rel*>* relations = attachment->att_relations;
|
||||
jrd_rel* check_relation = NULL;
|
||||
|
||||
vec<jrd_rel*>::iterator ptr = relations->begin();
|
||||
@ -2447,9 +2450,8 @@ jrd_rel* MET_lookup_relation(thread_db* tdbb, const MetaName& name)
|
||||
|
||||
if (relation)
|
||||
{
|
||||
if (relation->rel_flags & REL_deleting)
|
||||
{
|
||||
Database::CheckoutLockGuard guard(dbb, relation->rel_drop_mutex);
|
||||
if (relation->rel_flags & REL_deleting) {
|
||||
Jrd::Attachment::CheckoutLockGuard guard(attachment, relation->rel_drop_mutex);
|
||||
}
|
||||
|
||||
if (!(relation->rel_flags & REL_deleted))
|
||||
@ -2537,12 +2539,11 @@ jrd_rel* MET_lookup_relation_id(thread_db* tdbb, SLONG id, bool return_deleted)
|
||||
|
||||
jrd_rel* check_relation = NULL;
|
||||
jrd_rel* relation;
|
||||
vec<jrd_rel*>* vector = dbb->dbb_relations;
|
||||
vec<jrd_rel*>* vector = attachment->att_relations;
|
||||
if (vector && (id < (SLONG) vector->count()) && (relation = (*vector)[id]))
|
||||
{
|
||||
if (relation->rel_flags & REL_deleting)
|
||||
{
|
||||
Database::CheckoutLockGuard guard(dbb, relation->rel_drop_mutex);
|
||||
if (relation->rel_flags & REL_deleting) {
|
||||
Jrd::Attachment::CheckoutLockGuard guard(attachment, relation->rel_drop_mutex);
|
||||
}
|
||||
|
||||
if (relation->rel_flags & REL_deleted)
|
||||
@ -2739,7 +2740,7 @@ void MET_parse_sys_trigger(thread_db* tdbb, jrd_rel* relation)
|
||||
JrdStatement* statement = NULL;
|
||||
|
||||
{
|
||||
Jrd::ContextPoolHolder context(tdbb, dbb->createPool());
|
||||
Jrd::ContextPoolHolder context(tdbb, attachment->createPool());
|
||||
PAR_blr(tdbb, relation, blr.begin(), length, NULL, NULL, &statement, true, par_flags);
|
||||
}
|
||||
|
||||
@ -2828,18 +2829,16 @@ jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
|
||||
vec<jrd_prc*>* vector = dbb->dbb_procedures;
|
||||
vec<jrd_prc*>* vector = attachment->att_procedures;
|
||||
if (!vector)
|
||||
{
|
||||
vector = dbb->dbb_procedures = vec<jrd_prc*>::newVector(*dbb->dbb_permanent, id + 10);
|
||||
vector = attachment->att_procedures = vec<jrd_prc*>::newVector(*attachment->att_pool, id + 10);
|
||||
}
|
||||
else if (id >= (int) vector->count())
|
||||
{
|
||||
vector->resize(id + 10);
|
||||
}
|
||||
|
||||
Database::CheckoutLockGuard guard(dbb, dbb->dbb_meta_mutex);
|
||||
|
||||
jrd_prc* procedure = (*vector)[id];
|
||||
|
||||
if (procedure && !(procedure->prc_flags & PRC_obsolete))
|
||||
@ -2983,7 +2982,7 @@ jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
|
||||
(fb_utils::implicit_domain(F.RDB$FIELD_NAME) && !F.RDB$DEFAULT_VALUE.NULL)))
|
||||
{
|
||||
procedure->prc_defaults++;
|
||||
MemoryPool* pool = dbb->createPool();
|
||||
MemoryPool* pool = attachment->createPool();
|
||||
Jrd::ContextPoolHolder context(tdbb, pool);
|
||||
|
||||
try
|
||||
@ -2996,7 +2995,7 @@ jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
|
||||
// Here we lose pools created for previous defaults.
|
||||
// Probably we should use common pool for defaults and procedure itself.
|
||||
|
||||
dbb->deletePool(pool);
|
||||
attachment->deletePool(pool);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@ -3034,7 +3033,7 @@ jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
|
||||
prc_t prc_type = prc_legacy;
|
||||
const bool external = !P.RDB$ENGINE_NAME.NULL; // ODS_12_0
|
||||
|
||||
MemoryPool* csb_pool = dbb->createPool();
|
||||
MemoryPool* csb_pool = attachment->createPool();
|
||||
|
||||
{ // scope
|
||||
Jrd::ContextPoolHolder context(tdbb, csb_pool);
|
||||
@ -3063,7 +3062,7 @@ jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
|
||||
procedure->setStatement(NULL);
|
||||
}
|
||||
else {
|
||||
dbb->deletePool(csb_pool);
|
||||
attachment->deletePool(csb_pool);
|
||||
}
|
||||
|
||||
ERR_post(Arg::Gds(isc_bad_proc_BLR) << Arg::Str(procedure->getName().toString()));
|
||||
@ -3166,11 +3165,13 @@ jrd_rel* MET_relation(thread_db* tdbb, USHORT id)
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
CHECK_DBB(dbb);
|
||||
|
||||
vec<jrd_rel*>* vector = dbb->dbb_relations;
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
vec<jrd_rel*>* vector = attachment->att_relations;
|
||||
MemoryPool* pool = attachment->att_pool;
|
||||
|
||||
if (!vector)
|
||||
{
|
||||
vector = dbb->dbb_relations = vec<jrd_rel*>::newVector(*dbb->dbb_permanent, id + 10);
|
||||
vector = attachment->att_relations = vec<jrd_rel*>::newVector(*pool, id + 10);
|
||||
}
|
||||
else if (id >= vector->count())
|
||||
{
|
||||
@ -3186,12 +3187,12 @@ jrd_rel* MET_relation(thread_db* tdbb, USHORT id)
|
||||
// reserved for system relations
|
||||
const USHORT max_sys_rel = USER_DEF_REL_INIT_ID - 1;
|
||||
|
||||
relation = FB_NEW(*dbb->dbb_permanent) jrd_rel(*dbb->dbb_permanent);
|
||||
relation = FB_NEW(*pool) jrd_rel(*pool);
|
||||
(*vector)[id] = relation;
|
||||
relation->rel_id = id;
|
||||
|
||||
{ // Scope block.
|
||||
Lock* lock = FB_NEW_RPT(*dbb->dbb_permanent, 0) Lock;
|
||||
Lock* lock = FB_NEW_RPT(*pool, 0) Lock;
|
||||
relation->rel_partners_lock = lock;
|
||||
lock->lck_parent = dbb->dbb_lock;
|
||||
lock->lck_dbb = dbb;
|
||||
@ -3204,7 +3205,7 @@ jrd_rel* MET_relation(thread_db* tdbb, USHORT id)
|
||||
}
|
||||
|
||||
{ // Scope block.
|
||||
Lock* lock = FB_NEW_RPT(*dbb->dbb_permanent, 0) Lock;
|
||||
Lock* lock = FB_NEW_RPT(*pool, 0) Lock;
|
||||
relation->rel_rescan_lock = lock;
|
||||
lock->lck_parent = dbb->dbb_lock;
|
||||
lock->lck_dbb = dbb;
|
||||
@ -3222,7 +3223,7 @@ jrd_rel* MET_relation(thread_db* tdbb, USHORT id)
|
||||
}
|
||||
|
||||
{ // Scope block.
|
||||
Lock* lock = FB_NEW_RPT(*dbb->dbb_permanent, 0) Lock;
|
||||
Lock* lock = FB_NEW_RPT(*pool, 0) Lock;
|
||||
relation->rel_existence_lock = lock;
|
||||
lock->lck_parent = dbb->dbb_lock;
|
||||
lock->lck_dbb = dbb;
|
||||
@ -3286,8 +3287,9 @@ void MET_remove_procedure(thread_db* tdbb, int id, jrd_prc* procedure)
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* att = tdbb->getAttachment();
|
||||
|
||||
vec<jrd_prc*>* pvector = dbb->dbb_procedures;
|
||||
vec<jrd_prc*>* pvector = att->att_procedures;
|
||||
if (!pvector) {
|
||||
return;
|
||||
}
|
||||
@ -3440,7 +3442,6 @@ void MET_scan_partners(thread_db* tdbb, jrd_rel* relation)
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Database::CheckoutLockGuard guard(dbb, dbb->dbb_meta_mutex);
|
||||
|
||||
if (relation->rel_flags & REL_check_partners)
|
||||
{
|
||||
@ -3480,8 +3481,6 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation)
|
||||
|
||||
try {
|
||||
|
||||
Database::CheckoutLockGuard guard(dbb, dbb->dbb_meta_mutex);
|
||||
|
||||
if (relation->rel_flags & REL_scanned || relation->rel_flags & REL_deleted)
|
||||
{
|
||||
return;
|
||||
@ -3507,7 +3506,7 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation)
|
||||
// Pick up relation level stuff
|
||||
relation->rel_current_fmt = REL.RDB$FORMAT;
|
||||
vec<jrd_fld*>* vector = relation->rel_fields =
|
||||
vec<jrd_fld*>::newVector(*dbb->dbb_permanent, relation->rel_fields, REL.RDB$FIELD_ID + 1);
|
||||
vec<jrd_fld*>::newVector(*relation->rel_pool, relation->rel_fields, REL.RDB$FIELD_ID + 1);
|
||||
if (!REL.RDB$SECURITY_CLASS.NULL) {
|
||||
relation->rel_security_name = REL.RDB$SECURITY_CLASS;
|
||||
}
|
||||
@ -3930,14 +3929,14 @@ static int blocking_ast_dsql_cache(void* ast_object)
|
||||
try
|
||||
{
|
||||
Database* dbb = item->lock->lck_dbb;
|
||||
|
||||
Database::SyncGuard dsGuard(dbb, true);
|
||||
Jrd::Attachment* att = item->lock->lck_attachment;
|
||||
|
||||
ThreadContextHolder tdbb;
|
||||
tdbb->setDatabase(dbb);
|
||||
tdbb->setAttachment(item->lock->lck_attachment);
|
||||
tdbb->setAttachment(att);
|
||||
|
||||
Jrd::ContextPoolHolder context(tdbb, 0);
|
||||
Jrd::Attachment::SyncGuard guard(att);
|
||||
|
||||
item->obsolete = true;
|
||||
item->locked = false;
|
||||
@ -4010,14 +4009,14 @@ static int blocking_ast_procedure(void* ast_object)
|
||||
try
|
||||
{
|
||||
Database* dbb = procedure->prc_existence_lock->lck_dbb;
|
||||
|
||||
Database::SyncGuard dsGuard(dbb, true);
|
||||
Jrd::Attachment* att = procedure->prc_existence_lock->lck_attachment;
|
||||
|
||||
ThreadContextHolder tdbb;
|
||||
tdbb->setDatabase(dbb);
|
||||
tdbb->setAttachment(procedure->prc_existence_lock->lck_attachment);
|
||||
tdbb->setAttachment(att);
|
||||
|
||||
Jrd::ContextPoolHolder context(tdbb, 0);
|
||||
Jrd::Attachment::SyncGuard guard(att);
|
||||
|
||||
if (procedure->prc_existence_lock) {
|
||||
LCK_release(tdbb, procedure->prc_existence_lock);
|
||||
@ -4052,14 +4051,14 @@ static int blocking_ast_relation(void* ast_object)
|
||||
try
|
||||
{
|
||||
Database* dbb = relation->rel_existence_lock->lck_dbb;
|
||||
|
||||
Database::SyncGuard dsGuard(dbb, true);
|
||||
Jrd::Attachment* att = relation->rel_existence_lock->lck_attachment;
|
||||
|
||||
ThreadContextHolder tdbb;
|
||||
tdbb->setDatabase(dbb);
|
||||
tdbb->setAttachment(relation->rel_existence_lock->lck_attachment);
|
||||
tdbb->setAttachment(att);
|
||||
|
||||
Jrd::ContextPoolHolder context(tdbb, 0);
|
||||
Jrd::Attachment::SyncGuard guard(att);
|
||||
|
||||
if (relation->rel_use_count) {
|
||||
relation->rel_flags |= REL_blocking;
|
||||
@ -4086,14 +4085,14 @@ static int partners_ast_relation(void* ast_object)
|
||||
try
|
||||
{
|
||||
Database* dbb = relation->rel_partners_lock->lck_dbb;
|
||||
|
||||
Database::SyncGuard dsGuard(dbb, true);
|
||||
Jrd::Attachment* att = relation->rel_partners_lock->lck_attachment;
|
||||
|
||||
ThreadContextHolder tdbb;
|
||||
tdbb->setDatabase(dbb);
|
||||
tdbb->setAttachment(relation->rel_partners_lock->lck_attachment);
|
||||
tdbb->setAttachment(att);
|
||||
|
||||
Jrd::ContextPoolHolder context(tdbb, 0);
|
||||
Jrd::Attachment::SyncGuard guard(att);
|
||||
|
||||
LCK_release(tdbb, relation->rel_partners_lock);
|
||||
relation->rel_flags |= REL_check_partners;
|
||||
@ -4112,14 +4111,14 @@ static int rescan_ast_relation(void* ast_object)
|
||||
try
|
||||
{
|
||||
Database* dbb = relation->rel_rescan_lock->lck_dbb;
|
||||
|
||||
Database::SyncGuard dsGuard(dbb, true);
|
||||
Jrd::Attachment* att = relation->rel_rescan_lock->lck_attachment;
|
||||
|
||||
ThreadContextHolder tdbb;
|
||||
tdbb->setDatabase(dbb);
|
||||
tdbb->setAttachment(relation->rel_rescan_lock->lck_attachment);
|
||||
tdbb->setAttachment(att);
|
||||
|
||||
Jrd::ContextPoolHolder context(tdbb, 0);
|
||||
Jrd::Attachment::SyncGuard guard(att);
|
||||
|
||||
LCK_release(tdbb, relation->rel_rescan_lock);
|
||||
relation->rel_flags &= ~REL_scanned;
|
||||
@ -4708,13 +4707,13 @@ static bool resolve_charset_and_collation(thread_db* tdbb,
|
||||
if (charset == NULL)
|
||||
charset = (const UCHAR*) DEFAULT_CHARACTER_SET_NAME;
|
||||
|
||||
if (dbb->dbb_charset_ids.get((const TEXT*) charset, *id))
|
||||
if (attachment->att_charset_ids.get((const TEXT*) charset, *id))
|
||||
return true;
|
||||
|
||||
USHORT charset_id = 0;
|
||||
if (get_type(tdbb, &charset_id, charset, "RDB$CHARACTER_SET_NAME"))
|
||||
{
|
||||
dbb->dbb_charset_ids.put((const TEXT*) charset, charset_id);
|
||||
attachment->att_charset_ids.put((const TEXT*) charset, charset_id);
|
||||
*id = charset_id;
|
||||
return true;
|
||||
}
|
||||
@ -4727,7 +4726,7 @@ static bool resolve_charset_and_collation(thread_db* tdbb,
|
||||
WITH CS.RDB$CHARACTER_SET_NAME EQ charset
|
||||
{
|
||||
found = true;
|
||||
dbb->dbb_charset_ids.put((const TEXT*) charset, CS.RDB$CHARACTER_SET_ID);
|
||||
attachment->att_charset_ids.put((const TEXT*) charset, CS.RDB$CHARACTER_SET_ID);
|
||||
*id = CS.RDB$CHARACTER_SET_ID;
|
||||
}
|
||||
END_FOR
|
||||
@ -4759,7 +4758,7 @@ static bool resolve_charset_and_collation(thread_db* tdbb,
|
||||
AND AL1.RDB$TYPE EQ CS.RDB$CHARACTER_SET_ID
|
||||
{
|
||||
found = true;
|
||||
dbb->dbb_charset_ids.put((const TEXT*) charset, CS.RDB$CHARACTER_SET_ID);
|
||||
attachment->att_charset_ids.put((const TEXT*) charset, CS.RDB$CHARACTER_SET_ID);
|
||||
*id = CS.RDB$CHARACTER_SET_ID | (COL.RDB$COLLATION_ID << 8);
|
||||
}
|
||||
END_FOR
|
||||
@ -4790,8 +4789,7 @@ static void save_trigger_data(thread_db* tdbb, trig_vec** ptr, jrd_rel* relation
|
||||
|
||||
if (!vector)
|
||||
{
|
||||
vector = FB_NEW(*tdbb->getDatabase()->dbb_permanent)
|
||||
trig_vec(*tdbb->getDatabase()->dbb_permanent);
|
||||
vector = FB_NEW(*relation->rel_pool) trig_vec(*relation->rel_pool);
|
||||
*ptr = vector;
|
||||
}
|
||||
|
||||
@ -4898,19 +4896,19 @@ void scan_partners(thread_db* tdbb, jrd_rel* relation)
|
||||
{
|
||||
// This seems a good candidate for vcl.
|
||||
references->frgn_reference_ids =
|
||||
vec<int>::newVector(*dbb->dbb_permanent, references->frgn_reference_ids,
|
||||
vec<int>::newVector(*relation->rel_pool, references->frgn_reference_ids,
|
||||
index_number + 1);
|
||||
|
||||
(*references->frgn_reference_ids)[index_number] = IDX.RDB$INDEX_ID - 1;
|
||||
|
||||
references->frgn_relations =
|
||||
vec<int>::newVector(*dbb->dbb_permanent, references->frgn_relations,
|
||||
vec<int>::newVector(*relation->rel_pool, references->frgn_relations,
|
||||
index_number + 1);
|
||||
|
||||
(*references->frgn_relations)[index_number] = partner_relation->rel_id;
|
||||
|
||||
references->frgn_indexes =
|
||||
vec<int>::newVector(*dbb->dbb_permanent, references->frgn_indexes,
|
||||
vec<int>::newVector(*relation->rel_pool, references->frgn_indexes,
|
||||
index_number + 1);
|
||||
|
||||
(*references->frgn_indexes)[index_number] = IND.RDB$INDEX_ID - 1;
|
||||
@ -4954,19 +4952,19 @@ void scan_partners(thread_db* tdbb, jrd_rel* relation)
|
||||
if (partner_relation && !IDX.RDB$INDEX_INACTIVE && !IND.RDB$INDEX_INACTIVE)
|
||||
{
|
||||
dependencies->prim_reference_ids =
|
||||
vec<int>::newVector(*dbb->dbb_permanent, dependencies->prim_reference_ids,
|
||||
vec<int>::newVector(*relation->rel_pool, dependencies->prim_reference_ids,
|
||||
index_number + 1);
|
||||
|
||||
(*dependencies->prim_reference_ids)[index_number] = IDX.RDB$INDEX_ID - 1;
|
||||
|
||||
dependencies->prim_relations =
|
||||
vec<int>::newVector(*dbb->dbb_permanent, dependencies->prim_relations,
|
||||
vec<int>::newVector(*relation->rel_pool, dependencies->prim_relations,
|
||||
index_number + 1);
|
||||
|
||||
(*dependencies->prim_relations)[index_number] = partner_relation->rel_id;
|
||||
|
||||
dependencies->prim_indexes =
|
||||
vec<int>::newVector(*dbb->dbb_permanent, dependencies->prim_indexes,
|
||||
vec<int>::newVector(*relation->rel_pool, dependencies->prim_indexes,
|
||||
index_number + 1);
|
||||
|
||||
(*dependencies->prim_indexes)[index_number] = IND.RDB$INDEX_ID - 1;
|
||||
|
@ -107,6 +107,8 @@ void NBackupStateLock::blockingAstHandler(thread_db* tdbb)
|
||||
{
|
||||
backup_manager->beginFlush();
|
||||
NBAK_TRACE_AST( ("backup_manager->beginFlush()") );
|
||||
|
||||
Firebird::MutexUnlockGuard counterGuard(counterMutex);
|
||||
CCH_flush_ast(tdbb);
|
||||
NBAK_TRACE_AST(("database FLUSHED"));
|
||||
}
|
||||
@ -263,9 +265,8 @@ void BackupManager::beginBackup(thread_db* tdbb)
|
||||
#endif
|
||||
|
||||
// Zero out first page (empty allocation table)
|
||||
BufferDesc temp_bdb;
|
||||
BufferDesc temp_bdb(database->dbb_bcb);
|
||||
temp_bdb.bdb_page = 0;
|
||||
temp_bdb.bdb_dbb = database;
|
||||
temp_bdb.bdb_buffer = reinterpret_cast<Ods::pag*>(alloc_buffer);
|
||||
memset(alloc_buffer, 0, database->dbb_page_size);
|
||||
if (!PIO_write(diff_file, &temp_bdb, temp_bdb.bdb_buffer, tdbb->tdbb_status_vector))
|
||||
@ -314,10 +315,9 @@ ULONG BackupManager::getPageCount()
|
||||
PageSpace* pageSpace;
|
||||
|
||||
public:
|
||||
explicit PioCount(Database* d)
|
||||
explicit PioCount(Database* d) : temp_bdb(d->dbb_bcb)
|
||||
{
|
||||
fb_assert(d);
|
||||
temp_bdb.bdb_dbb = d;
|
||||
pageSpace = d->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
|
||||
fb_assert(pageSpace);
|
||||
}
|
||||
@ -515,14 +515,13 @@ bool BackupManager::actualizeAlloc(thread_db* tdbb)
|
||||
alloc_table = FB_NEW(*database->dbb_permanent) AllocItemTree(database->dbb_permanent);
|
||||
while (true)
|
||||
{
|
||||
BufferDesc temp_bdb;
|
||||
BufferDesc temp_bdb(database->dbb_bcb);
|
||||
// Difference file pointer pages have one ULONG as number of pages allocated on the page and
|
||||
// then go physical numbers of pages from main database file. Offsets of numbers correspond
|
||||
// to difference file pages.
|
||||
|
||||
// Get offset of pointer page. We can do so because page sizes are powers of 2
|
||||
temp_bdb.bdb_page = last_allocated_page & ~(database->dbb_page_size / sizeof(ULONG) - 1);
|
||||
temp_bdb.bdb_dbb = database;
|
||||
temp_bdb.bdb_buffer = reinterpret_cast<Ods::pag*>(alloc_buffer);
|
||||
|
||||
if (!PIO_read(diff_file, &temp_bdb, temp_bdb.bdb_buffer, status_vector)) {
|
||||
@ -585,9 +584,8 @@ ULONG BackupManager::allocateDifferencePage(thread_db* tdbb, ULONG db_page)
|
||||
// Grow file first. This is done in such order to keep difference
|
||||
// file consistent in case of write error. We should always be able
|
||||
// to read next alloc page when previous one is full.
|
||||
BufferDesc temp_bdb;
|
||||
BufferDesc temp_bdb(database->dbb_bcb);
|
||||
temp_bdb.bdb_page = last_allocated_page + 1;
|
||||
temp_bdb.bdb_dbb = database;
|
||||
temp_bdb.bdb_buffer = reinterpret_cast<Ods::pag*>(empty_buffer);
|
||||
if (!PIO_write(diff_file, &temp_bdb, (Ods::pag*)empty_buffer, status_vector)) {
|
||||
return 0;
|
||||
@ -598,7 +596,6 @@ ULONG BackupManager::allocateDifferencePage(thread_db* tdbb, ULONG db_page)
|
||||
{
|
||||
// Pointer page is full. Its time to create new one.
|
||||
temp_bdb.bdb_page = last_allocated_page + 2;
|
||||
temp_bdb.bdb_dbb = database;
|
||||
temp_bdb.bdb_buffer = reinterpret_cast<Ods::pag*>(empty_buffer);
|
||||
if (!PIO_write(diff_file, &temp_bdb, (Ods::pag*)empty_buffer, status_vector)) {
|
||||
return 0;
|
||||
@ -607,7 +604,6 @@ ULONG BackupManager::allocateDifferencePage(thread_db* tdbb, ULONG db_page)
|
||||
|
||||
// Write new item to the allocation table
|
||||
temp_bdb.bdb_page = last_allocated_page & ~(database->dbb_page_size / sizeof(ULONG) - 1);
|
||||
temp_bdb.bdb_dbb = database;
|
||||
temp_bdb.bdb_buffer = reinterpret_cast<Ods::pag*>(alloc_buffer);
|
||||
alloc_buffer[++alloc_buffer[0]] = db_page;
|
||||
if (!PIO_write(diff_file, &temp_bdb, temp_bdb.bdb_buffer, status_vector)) {
|
||||
@ -640,10 +636,9 @@ ULONG BackupManager::allocateDifferencePage(thread_db* tdbb, ULONG db_page)
|
||||
|
||||
bool BackupManager::writeDifference(ISC_STATUS* status, ULONG diff_page, Ods::pag* page)
|
||||
{
|
||||
NBAK_TRACE(("write_diff"));
|
||||
BufferDesc temp_bdb;
|
||||
NBAK_TRACE(("write_diff page=%d, diff=%d", page->pag_pageno, diff_page));
|
||||
BufferDesc temp_bdb(database->dbb_bcb);
|
||||
temp_bdb.bdb_page = diff_page;
|
||||
temp_bdb.bdb_dbb = database;
|
||||
temp_bdb.bdb_buffer = page;
|
||||
// Check that diff page is not allocation page
|
||||
fb_assert(diff_page % (database->dbb_page_size / sizeof(ULONG)));
|
||||
@ -654,13 +649,12 @@ bool BackupManager::writeDifference(ISC_STATUS* status, ULONG diff_page, Ods::pa
|
||||
|
||||
bool BackupManager::readDifference(thread_db* tdbb, ULONG diff_page, Ods::pag* page)
|
||||
{
|
||||
NBAK_TRACE(("read_diff"));
|
||||
BufferDesc temp_bdb;
|
||||
BufferDesc temp_bdb(database->dbb_bcb);
|
||||
temp_bdb.bdb_page = diff_page;
|
||||
temp_bdb.bdb_dbb = database;
|
||||
temp_bdb.bdb_buffer = page;
|
||||
if (!PIO_read(diff_file, &temp_bdb, page, tdbb->tdbb_status_vector))
|
||||
return false;
|
||||
NBAK_TRACE(("read_diff page=%d, diff=%d", page->pag_pageno, diff_page));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -737,9 +731,8 @@ bool BackupManager::actualizeState(thread_db* tdbb)
|
||||
// Read original page from database file or shadows.
|
||||
SSHORT retryCount = 0;
|
||||
Ods::header_page* header = reinterpret_cast<Ods::header_page*>(spare_buffer);
|
||||
BufferDesc temp_bdb;
|
||||
BufferDesc temp_bdb(database->dbb_bcb);
|
||||
temp_bdb.bdb_page = HEADER_PAGE_NUMBER;
|
||||
temp_bdb.bdb_dbb = database;
|
||||
temp_bdb.bdb_buffer = reinterpret_cast<Ods::pag*>(header);
|
||||
PageSpace* pageSpace = database->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
|
||||
fb_assert(pageSpace);
|
||||
|
@ -310,12 +310,18 @@ public:
|
||||
// State Lock member functions
|
||||
bool lockStateWrite(thread_db* tdbb, SSHORT wait)
|
||||
{
|
||||
fb_assert(!(tdbb->tdbb_flags & TDBB_backup_write_locked));
|
||||
tdbb->tdbb_flags |= TDBB_backup_write_locked;
|
||||
return stateLock->lockWrite(tdbb, wait);
|
||||
if (stateLock->lockWrite(tdbb, wait))
|
||||
return true;
|
||||
|
||||
tdbb->tdbb_flags &= ~TDBB_backup_write_locked;
|
||||
return false;
|
||||
}
|
||||
|
||||
void unlockStateWrite(thread_db* tdbb)
|
||||
{
|
||||
fb_assert(tdbb->tdbb_flags & TDBB_backup_write_locked);
|
||||
tdbb->tdbb_flags &= ~TDBB_backup_write_locked;
|
||||
stateLock->unlockWrite(tdbb);
|
||||
}
|
||||
|
@ -78,9 +78,9 @@ public:
|
||||
USHORT fil_fudge; // Fudge factor for page relocation
|
||||
HANDLE fil_desc; // File descriptor
|
||||
//int *fil_trace; // Trace file, if any
|
||||
Firebird::Mutex fil_mutex;
|
||||
Firebird::RWLock* fil_ext_lock; // file extend lock
|
||||
#ifdef SUPERSERVER_V2
|
||||
Firebird::Mutex fil_mutex;
|
||||
void* fil_io_events[MAX_FILE_IO]; // Overlapped I/O events
|
||||
#endif
|
||||
USHORT fil_flags;
|
||||
@ -93,6 +93,7 @@ public:
|
||||
const USHORT FIL_force_write = 1;
|
||||
const USHORT FIL_no_fs_cache = 2; // not using file system cache
|
||||
const USHORT FIL_readonly = 4; // file opened in readonly mode
|
||||
const USHORT FIL_sh_write = 8; // file opened in shared write mode
|
||||
|
||||
// Physical IO trace events
|
||||
|
||||
|
@ -115,7 +115,7 @@ static void release_io_event(jrd_file*, OVERLAPPED*);
|
||||
#endif
|
||||
static bool maybeCloseFile(HANDLE&);
|
||||
static jrd_file* seek_file(jrd_file*, BufferDesc*, ISC_STATUS*, OVERLAPPED*, OVERLAPPED**);
|
||||
static jrd_file* setup_file(Database*, const Firebird::PathName&, HANDLE, bool);
|
||||
static jrd_file* setup_file(Database*, const Firebird::PathName&, HANDLE, bool, bool);
|
||||
static bool nt_error(const TEXT*, const jrd_file*, ISC_STATUS, ISC_STATUS* const);
|
||||
static void adjustFileSystemCacheSize();
|
||||
|
||||
@ -126,9 +126,8 @@ struct AdjustFsCache
|
||||
|
||||
static InitMutex<AdjustFsCache> adjustFsCacheOnce;
|
||||
|
||||
inline static DWORD getShareFlags(bool temporary = false)
|
||||
inline static DWORD getShareFlags(const bool shared_access, bool temporary = false)
|
||||
{
|
||||
static bool shared_access = Config::getSharedDatabase();
|
||||
return FILE_SHARE_READ | ((!temporary && shared_access) ? FILE_SHARE_WRITE : 0);
|
||||
}
|
||||
|
||||
@ -224,8 +223,9 @@ jrd_file* PIO_create(Database* dbb, const Firebird::PathName& string,
|
||||
adjustFsCacheOnce.init();
|
||||
|
||||
const TEXT* file_name = string.c_str();
|
||||
const bool shareMode = dbb->dbb_config->getSharedDatabase();
|
||||
|
||||
DWORD dwShareMode = getShareFlags(temporary);
|
||||
DWORD dwShareMode = getShareFlags(shareMode, temporary);
|
||||
if (share_delete)
|
||||
dwShareMode |= FILE_SHARE_DELETE;
|
||||
|
||||
@ -253,7 +253,7 @@ jrd_file* PIO_create(Database* dbb, const Firebird::PathName& string,
|
||||
Firebird::PathName workspace(string);
|
||||
ISC_expand_filename(workspace, false);
|
||||
|
||||
return setup_file(dbb, workspace, desc, false);
|
||||
return setup_file(dbb, workspace, desc, false, shareMode);
|
||||
}
|
||||
|
||||
|
||||
@ -299,7 +299,7 @@ void PIO_extend(Database* dbb, jrd_file* main_file, const ULONG extPages, const
|
||||
if (!main_file->fil_ext_lock)
|
||||
return;
|
||||
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
// Database::Checkout dcoHolder(dbb);
|
||||
FileExtendLockGuard extLock(main_file->fil_ext_lock, true);
|
||||
|
||||
ULONG leftPages = extPages;
|
||||
@ -343,7 +343,7 @@ void PIO_flush(Database* dbb, jrd_file* main_file)
|
||||
* Flush the operating system cache back to good, solid oxide.
|
||||
*
|
||||
**************************************/
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
// Database::Checkout dcoHolder(dbb);
|
||||
for (jrd_file* file = main_file; file; file = file->fil_next)
|
||||
{
|
||||
FlushFileBuffers(file->fil_desc);
|
||||
@ -372,12 +372,13 @@ void PIO_force_write(jrd_file* file, const bool forceWrite, const bool notUseFSC
|
||||
const int force = forceWrite ? FILE_FLAG_WRITE_THROUGH : 0;
|
||||
const int fsCache = notUseFSCache ? FILE_FLAG_NO_BUFFERING : 0;
|
||||
const int writeMode = (file->fil_flags & FIL_readonly) ? 0 : GENERIC_WRITE;
|
||||
const bool sharedMode = (file->fil_flags & FIL_sh_write);
|
||||
|
||||
HANDLE& hFile = file->fil_desc;
|
||||
maybeCloseFile(hFile);
|
||||
hFile = CreateFile(file->fil_string,
|
||||
GENERIC_READ | writeMode,
|
||||
getShareFlags(),
|
||||
getShareFlags(sharedMode),
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | force | fsCache | g_dwExtraFlags,
|
||||
@ -494,13 +495,12 @@ USHORT PIO_init_data(Database* dbb, jrd_file* main_file, ISC_STATUS* status_vect
|
||||
const char* const zero_buff = zeros().getBuffer();
|
||||
const size_t zero_buff_size = zeros().getSize();
|
||||
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
// Database::Checkout dcoHolder(dbb);
|
||||
FileExtendLockGuard extLock(main_file->fil_ext_lock, false);
|
||||
|
||||
// Fake buffer, used in seek_file. Page space ID doesn't matter there
|
||||
// as we already know file to work with
|
||||
BufferDesc bdb;
|
||||
bdb.bdb_dbb = dbb;
|
||||
BufferDesc bdb(dbb->dbb_bcb);
|
||||
bdb.bdb_page = PageNumber(0, startPage);
|
||||
|
||||
OVERLAPPED overlapped;
|
||||
@ -525,7 +525,8 @@ USHORT PIO_init_data(Database* dbb, jrd_file* main_file, ISC_STATUS* status_vect
|
||||
if (write_pages > leftPages)
|
||||
write_pages = leftPages;
|
||||
|
||||
seek_file(main_file, &bdb, status_vector, &overlapped, &overlapped_ptr);
|
||||
jrd_file* file1 = seek_file(main_file, &bdb, status_vector, &overlapped, &overlapped_ptr);
|
||||
fb_assert(file1 == file);
|
||||
|
||||
const DWORD to_write = (DWORD) write_pages * dbb->dbb_page_size;
|
||||
DWORD written;
|
||||
@ -562,12 +563,13 @@ jrd_file* PIO_open(Database* dbb,
|
||||
**************************************/
|
||||
const TEXT* const ptr = (string.hasData() ? string : file_name).c_str();
|
||||
bool readOnly = false;
|
||||
const bool shareMode = dbb->dbb_config->getSharedDatabase();
|
||||
|
||||
adjustFsCacheOnce.init();
|
||||
|
||||
HANDLE desc = CreateFile(ptr,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
getShareFlags() | (share_delete ? FILE_SHARE_DELETE : 0),
|
||||
getShareFlags(shareMode) | (share_delete ? FILE_SHARE_DELETE : 0),
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL |
|
||||
@ -604,7 +606,7 @@ jrd_file* PIO_open(Database* dbb,
|
||||
}
|
||||
}
|
||||
|
||||
return setup_file(dbb, string, desc, readOnly);
|
||||
return setup_file(dbb, string, desc, readOnly, shareMode);
|
||||
}
|
||||
|
||||
|
||||
@ -620,10 +622,11 @@ bool PIO_read(jrd_file* file, BufferDesc* bdb, Ods::pag* page, ISC_STATUS* statu
|
||||
* Read a data page.
|
||||
*
|
||||
**************************************/
|
||||
Database* const dbb = bdb->bdb_dbb;
|
||||
const DWORD size = dbb->dbb_page_size;
|
||||
BufferControl *bcb = bdb->bdb_bcb;
|
||||
const DWORD size = bcb->bcb_page_size;
|
||||
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
Database* const dbb = bcb->bcb_database;
|
||||
// Database::Checkout dcoHolder(dbb);
|
||||
FileExtendLockGuard extLock(file->fil_ext_lock, false);
|
||||
|
||||
OVERLAPPED overlapped, *overlapped_ptr;
|
||||
@ -694,7 +697,7 @@ bool PIO_read_ahead(Database* dbb,
|
||||
**************************************/
|
||||
OVERLAPPED overlapped, *overlapped_ptr;
|
||||
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
// Database::Checkout dcoHolder(dbb);
|
||||
|
||||
// If an I/O status block was passed the caller wants to queue an asynchronous I/O.
|
||||
|
||||
@ -782,7 +785,7 @@ bool PIO_status(Database* dbb, phys_io_blk* piob, ISC_STATUS* status_vector)
|
||||
* Check the status of an asynchronous I/O.
|
||||
*
|
||||
**************************************/
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
// Database::Checkout dcoHolder(dbb);
|
||||
|
||||
if (!(piob->piob_flags & PIOB_success))
|
||||
{
|
||||
@ -822,10 +825,11 @@ bool PIO_write(jrd_file* file, BufferDesc* bdb, Ods::pag* page, ISC_STATUS* stat
|
||||
**************************************/
|
||||
OVERLAPPED overlapped, *overlapped_ptr;
|
||||
|
||||
Database* const dbb = bdb->bdb_dbb;
|
||||
const DWORD size = dbb->dbb_page_size;
|
||||
BufferControl *bcb = bdb->bdb_bcb;
|
||||
const DWORD size = bcb->bcb_page_size;
|
||||
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
Database* const dbb = bcb->bcb_database;
|
||||
// Database::Checkout dcoHolder(dbb);
|
||||
FileExtendLockGuard extLock(file->fil_ext_lock, false);
|
||||
|
||||
file = seek_file(file, bdb, status_vector, &overlapped, &overlapped_ptr);
|
||||
@ -985,7 +989,7 @@ static jrd_file* seek_file(jrd_file* file,
|
||||
* file block and seek to the proper page in that file.
|
||||
*
|
||||
**************************************/
|
||||
Database* const dbb = bdb->bdb_dbb;
|
||||
BufferControl *bcb = bdb->bdb_bcb;
|
||||
ULONG page = bdb->bdb_page.getPageNum();
|
||||
|
||||
for (;; file = file->fil_next)
|
||||
@ -1001,7 +1005,7 @@ static jrd_file* seek_file(jrd_file* file,
|
||||
page -= file->fil_min_page - file->fil_fudge;
|
||||
|
||||
LARGE_INTEGER liOffset;
|
||||
liOffset.QuadPart = UInt32x32To64((DWORD) page, (DWORD) dbb->dbb_page_size);
|
||||
liOffset.QuadPart = UInt32x32To64((DWORD) page, (DWORD) bcb->bcb_page_size);
|
||||
|
||||
overlapped->Offset = liOffset.LowPart;
|
||||
overlapped->OffsetHigh = liOffset.HighPart;
|
||||
@ -1011,8 +1015,6 @@ static jrd_file* seek_file(jrd_file* file,
|
||||
|
||||
*overlapped_ptr = overlapped;
|
||||
|
||||
fb_assert(dbb == bdb->bdb_dbb);
|
||||
|
||||
#ifdef SUPERSERVER_V2
|
||||
Firebird::MutexLockGuard guard(file->fil_mutex);
|
||||
|
||||
@ -1027,7 +1029,7 @@ static jrd_file* seek_file(jrd_file* file,
|
||||
|
||||
if (!overlapped->hEvent && !(overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
||||
{
|
||||
nt_error("CreateEvent", file, isc_io_access_err, status_vector);
|
||||
nt_error("CreateEvent", file, isc_io_access_err, NULL/*status_vector*/);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1041,7 +1043,8 @@ static jrd_file* seek_file(jrd_file* file,
|
||||
static jrd_file* setup_file(Database* dbb,
|
||||
const Firebird::PathName& file_name,
|
||||
HANDLE desc,
|
||||
bool read_only)
|
||||
bool read_only,
|
||||
bool shareMode)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -1067,6 +1070,8 @@ static jrd_file* setup_file(Database* dbb,
|
||||
|
||||
if (read_only)
|
||||
file->fil_flags |= FIL_readonly;
|
||||
if (shareMode)
|
||||
file->fil_flags |= FIL_sh_write;
|
||||
|
||||
// If this isn't the primary file, we're done
|
||||
|
||||
|
@ -551,7 +551,7 @@ PAG PAG_allocate(thread_db* tdbb, WIN* window)
|
||||
|
||||
const ULONG pageNum = relative_bit + sequence * pageMgr.pagesPerPIP;
|
||||
window->win_page = pageNum;
|
||||
new_page = CCH_fake(tdbb, window, 0); // don't wait on latch
|
||||
new_page = CCH_fake(tdbb, window, 1); // don't wait on latch ?
|
||||
if (new_page)
|
||||
{
|
||||
BackupManager::StateReadGuard stateGuard(tdbb);
|
||||
@ -605,7 +605,7 @@ PAG PAG_allocate(thread_db* tdbb, WIN* window)
|
||||
// PIO_init_data returns zero - perhaps it is not supported,
|
||||
// no space left on disk or IO error occurred. Try to write
|
||||
// one page and handle IO errors if any.
|
||||
CCH_must_write(window);
|
||||
CCH_must_write(tdbb, window);
|
||||
try
|
||||
{
|
||||
CCH_RELEASE(tdbb, window);
|
||||
@ -683,9 +683,9 @@ PAG PAG_allocate(thread_db* tdbb, WIN* window)
|
||||
page->scn_header.pag_type = pag_scns;
|
||||
page->scn_sequence = scn_page / pageMgr.pagesPerSCN;
|
||||
|
||||
CCH_must_write(window);
|
||||
CCH_must_write(tdbb, window);
|
||||
CCH_RELEASE(tdbb, window);
|
||||
CCH_must_write(&pip_window);
|
||||
CCH_must_write(tdbb, &pip_window);
|
||||
CCH_RELEASE(tdbb, &pip_window);
|
||||
|
||||
return PAG_allocate(tdbb, window);
|
||||
@ -712,9 +712,9 @@ PAG PAG_allocate(thread_db* tdbb, WIN* window)
|
||||
const UCHAR* end = (UCHAR*) new_pip_page + dbb->dbb_page_size;
|
||||
memset(new_pip_page->pip_bits, 0xff, end - new_pip_page->pip_bits);
|
||||
|
||||
CCH_must_write(window);
|
||||
CCH_must_write(tdbb, window);
|
||||
CCH_RELEASE(tdbb, window);
|
||||
CCH_must_write(&pip_window);
|
||||
CCH_must_write(tdbb, &pip_window);
|
||||
CCH_RELEASE(tdbb, &pip_window);
|
||||
|
||||
return PAG_allocate(tdbb, window);
|
||||
@ -1298,7 +1298,7 @@ void PAG_init2(thread_db* tdbb, USHORT shadow_number)
|
||||
window.win_page = file->fil_min_page;
|
||||
USHORT file_length = 0;
|
||||
ULONG last_page = 0;
|
||||
BufferDesc temp_bdb;
|
||||
BufferDesc temp_bdb(dbb->dbb_bcb);
|
||||
SLONG next_page = 0;
|
||||
do {
|
||||
// note that we do not have to get a read lock on
|
||||
@ -1315,7 +1315,6 @@ void PAG_init2(thread_db* tdbb, USHORT shadow_number)
|
||||
header_page* header = (header_page*) temp_page;
|
||||
temp_bdb.bdb_buffer = (PAG) header;
|
||||
temp_bdb.bdb_page = window.win_page;
|
||||
temp_bdb.bdb_dbb = dbb;
|
||||
|
||||
// Read the required page into the local buffer
|
||||
PIO_read(file, &temp_bdb, (PAG) header, status);
|
||||
@ -1717,13 +1716,13 @@ static int blocking_ast_attachment(void* ast_object)
|
||||
try
|
||||
{
|
||||
Database* const dbb = attachment->att_database;
|
||||
Database::SyncGuard dsGuard(dbb, true);
|
||||
|
||||
ThreadContextHolder tdbb;
|
||||
tdbb->setDatabase(dbb);
|
||||
tdbb->setAttachment(attachment);
|
||||
|
||||
Jrd::ContextPoolHolder context(tdbb, dbb->dbb_permanent);
|
||||
Jrd::Attachment::SyncGuard guard(attachment);
|
||||
|
||||
attachment->att_flags |= ATT_shutdown;
|
||||
attachment->cancelExternalConnection(tdbb);
|
||||
@ -2175,12 +2174,12 @@ void PageManager::releaseLocks()
|
||||
|
||||
USHORT PageManager::getTempPageSpaceID(thread_db* tdbb)
|
||||
{
|
||||
USHORT result;
|
||||
|
||||
if (Config::getSharedDatabase())
|
||||
{
|
||||
SET_TDBB(tdbb);
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
USHORT result;
|
||||
|
||||
if (dbb->dbb_config->getSharedDatabase())
|
||||
{
|
||||
Jrd::Attachment* const attachment = tdbb->getAttachment();
|
||||
|
||||
if (!attachment->att_temp_pg_lock)
|
||||
|
@ -126,7 +126,7 @@ void PCMET_expression_index(thread_db* tdbb, const MetaName& name, USHORT id, jr
|
||||
|
||||
CompilerScratch* csb = 0;
|
||||
// allocate a new pool to contain the expression tree for the expression index
|
||||
new_pool = dbb->createPool();
|
||||
new_pool = attachment->createPool();
|
||||
{ // scope
|
||||
Jrd::ContextPoolHolder context(tdbb, new_pool);
|
||||
MET_scan_relation(tdbb, relation);
|
||||
@ -181,7 +181,7 @@ void PCMET_expression_index(thread_db* tdbb, const MetaName& name, USHORT id, jr
|
||||
|
||||
// Get rid of the pool containing the expression tree
|
||||
|
||||
dbb->deletePool(new_pool);
|
||||
attachment->deletePool(new_pool);
|
||||
}
|
||||
|
||||
|
||||
@ -243,7 +243,7 @@ void PCMET_lookup_index(thread_db* tdbb, jrd_rel* relation, index_desc* idx)
|
||||
// with the index block in the "permanent" metadata cache
|
||||
|
||||
{ // scope
|
||||
Jrd::ContextPoolHolder context(tdbb, dbb->createPool());
|
||||
Jrd::ContextPoolHolder context(tdbb, attachment->createPool());
|
||||
idx->idx_expression = static_cast<ValueExprNode*>(MET_parse_blob(
|
||||
tdbb, relation, &IDX.RDB$EXPRESSION_BLR, &csb,
|
||||
&idx->idx_expression_statement, false, false));
|
||||
|
@ -172,7 +172,7 @@ Sort* SortedStream::init(thread_db* tdbb) const
|
||||
// establish a callback routine to reject duplicate records.
|
||||
|
||||
AutoPtr<Sort> scb(FB_NEW(request->req_sorts.getPool())
|
||||
Sort(tdbb->getDatabase(), &request->req_sorts,
|
||||
Sort(tdbb->getAttachment(), &request->req_sorts,
|
||||
m_map->length, m_map->keyItems.getCount(), m_map->keyItems.getCount(),
|
||||
m_map->keyItems.begin(),
|
||||
((m_map->flags & FLAG_PROJECT) ? rejectDuplicate : NULL), 0));
|
||||
|
@ -99,6 +99,8 @@ void SDW_add(thread_db* tdbb, const TEXT* file_name, USHORT shadow_number, USHOR
|
||||
dbb->dbb_flags & DBB_no_fs_cache);
|
||||
}
|
||||
|
||||
SyncLockGuard guard(&dbb->dbb_shadow_sync, SYNC_EXCLUSIVE, "SDW_add");
|
||||
|
||||
Shadow* shadow = allocate_shadow(shadow_file, shadow_number, file_flags);
|
||||
|
||||
// dump out the header page, even if it is a conditional
|
||||
@ -132,6 +134,8 @@ int SDW_add_file(thread_db* tdbb, const TEXT* file_name, SLONG start, USHORT sha
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
|
||||
SyncLockGuard guard(&dbb->dbb_shadow_sync, SYNC_EXCLUSIVE, "SDW_add_file");
|
||||
|
||||
// Find the file to be extended
|
||||
|
||||
jrd_file* shadow_file = 0;
|
||||
@ -202,9 +206,8 @@ int SDW_add_file(thread_db* tdbb, const TEXT* file_name, SLONG start, USHORT sha
|
||||
header->hdr_next_page = 0;
|
||||
|
||||
// fool PIO_write into writing the scratch page into the correct place
|
||||
BufferDesc temp_bdb;
|
||||
BufferDesc temp_bdb(dbb->dbb_bcb);
|
||||
temp_bdb.bdb_page = next->fil_min_page;
|
||||
temp_bdb.bdb_dbb = dbb;
|
||||
temp_bdb.bdb_buffer = (PAG) header;
|
||||
header->hdr_header.pag_pageno = temp_bdb.bdb_page.getPageNum();
|
||||
if (!PIO_write(shadow_file, &temp_bdb, reinterpret_cast<Ods::pag*>(header), 0))
|
||||
@ -296,6 +299,8 @@ void SDW_check(thread_db* tdbb)
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
|
||||
SyncLockGuard guard(&dbb->dbb_shadow_sync, SYNC_EXCLUSIVE, "SDW_check");
|
||||
|
||||
// first get rid of any shadows that need to be
|
||||
// deleted or shutdown; deleted shadows must also be shutdown
|
||||
|
||||
@ -362,6 +367,8 @@ bool SDW_check_conditional(thread_db* tdbb)
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
CHECK_DBB(dbb);
|
||||
|
||||
SyncLockGuard guard(&dbb->dbb_shadow_sync, SYNC_EXCLUSIVE, "SDW_check_conditional");
|
||||
|
||||
// first get rid of any shadows that need to be
|
||||
// deleted or shutdown; deleted shadows must also be shutdown
|
||||
|
||||
@ -424,6 +431,7 @@ void SDW_close()
|
||||
*
|
||||
**************************************/
|
||||
Database* dbb = GET_DBB();
|
||||
SyncLockGuard guard(&dbb->dbb_shadow_sync, SYNC_SHARED, "SDW_close");
|
||||
|
||||
for (Shadow* shadow = dbb->dbb_shadow; shadow; shadow = shadow->sdw_next)
|
||||
PIO_close(shadow->sdw_file);
|
||||
@ -446,6 +454,8 @@ void SDW_dump_pages(thread_db* tdbb)
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
SyncLockGuard guard(&dbb->dbb_shadow_sync, SYNC_EXCLUSIVE, "SDW_dump_pages");
|
||||
|
||||
gds__log("conditional shadow dumped for database %s", dbb->dbb_filename.c_str());
|
||||
const SLONG max = PAG_last_page(tdbb);
|
||||
|
||||
@ -529,6 +539,8 @@ void SDW_get_shadows(thread_db* tdbb)
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
CHECK_DBB(dbb);
|
||||
|
||||
SyncLockGuard guard(&dbb->dbb_shadow_sync, SYNC_EXCLUSIVE, "SDW_get_shadows");
|
||||
|
||||
// unless we have one, get a shared lock to ensure that we don't miss any signals
|
||||
|
||||
dbb->dbb_ast_flags &= ~DBB_get_shadows;
|
||||
@ -574,6 +586,8 @@ void SDW_init(thread_db* tdbb, bool activate, bool delete_files)
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
CHECK_DBB(dbb);
|
||||
|
||||
SyncLockGuard guard(&dbb->dbb_shadow_sync, SYNC_EXCLUSIVE, "SDW_init");
|
||||
|
||||
// set up the lock block for synchronizing addition of new shadows
|
||||
|
||||
header_page* header; // for sizeof here, used later
|
||||
@ -629,6 +643,9 @@ bool SDW_lck_update(thread_db* tdbb, SLONG sdw_update_flags)
|
||||
*
|
||||
**************************************/
|
||||
Database* dbb = GET_DBB();
|
||||
|
||||
SyncLockGuard guard(&dbb->dbb_shadow_sync, SYNC_EXCLUSIVE, "SDW_lck_update");
|
||||
|
||||
Lock* lock = dbb->dbb_shadow_lock;
|
||||
if (!lock)
|
||||
return false;
|
||||
@ -672,6 +689,8 @@ void SDW_notify(thread_db* tdbb)
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
CHECK_DBB(dbb);
|
||||
|
||||
SyncLockGuard guard(&dbb->dbb_shadow_sync, SYNC_EXCLUSIVE, "SDW_notify");
|
||||
|
||||
// get current shadow lock count from database header page --
|
||||
// note that since other processes need the header page to issue locks
|
||||
// on the shadow count, this is effectively an uninterruptible operation
|
||||
@ -728,6 +747,8 @@ bool SDW_rollover_to_shadow(thread_db* tdbb, jrd_file* file, const bool inAst)
|
||||
if (file != pageSpace->file)
|
||||
return true;
|
||||
|
||||
SyncLockGuard guard(&dbb->dbb_shadow_sync, SYNC_EXCLUSIVE, "SDW_rollover_to_shadow");
|
||||
|
||||
Lock temp_lock;
|
||||
Lock* update_lock = &temp_lock;
|
||||
update_lock->lck_dbb = dbb;
|
||||
@ -914,6 +935,8 @@ void SDW_start(thread_db* tdbb, const TEXT* file_name,
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
|
||||
SyncLockGuard guard(&dbb->dbb_shadow_sync, SYNC_EXCLUSIVE, "SDW_start");
|
||||
|
||||
USHORT header_fetched = 0;
|
||||
|
||||
// check that this shadow has not already been started,
|
||||
@ -1165,22 +1188,22 @@ static int blocking_ast_shadowing(void* ast_object)
|
||||
* new shadow files before doing the next physical write.
|
||||
*
|
||||
**************************************/
|
||||
Database* new_dbb = static_cast<Database*>(ast_object);
|
||||
Database* dbb = static_cast<Database*>(ast_object);
|
||||
|
||||
try
|
||||
{
|
||||
Database::SyncGuard dsGuard(new_dbb, true);
|
||||
SyncLockGuard guard(&dbb->dbb_shadow_sync, SYNC_EXCLUSIVE, "blocking_ast_shadowing");
|
||||
|
||||
Lock* lock = new_dbb->dbb_shadow_lock;
|
||||
Lock* lock = dbb->dbb_shadow_lock;
|
||||
|
||||
// Since this routine will be called asynchronously,
|
||||
// we must establish a thread context
|
||||
ThreadContextHolder tdbb;
|
||||
tdbb->setDatabase(new_dbb);
|
||||
tdbb->setDatabase(dbb);
|
||||
|
||||
new_dbb->dbb_ast_flags |= DBB_get_shadows;
|
||||
dbb->dbb_ast_flags |= DBB_get_shadows;
|
||||
if (LCK_read_data(tdbb, lock) & SDW_rollover)
|
||||
update_dbb_to_sdw(new_dbb);
|
||||
update_dbb_to_sdw(dbb);
|
||||
|
||||
LCK_release(tdbb, lock);
|
||||
}
|
||||
@ -1316,7 +1339,7 @@ static void update_dbb_to_sdw(Database* dbb)
|
||||
return; // should be a BUGCHECK
|
||||
|
||||
// close the main database file if possible and release all file blocks
|
||||
|
||||
// hvlad: need sync for this code
|
||||
PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
|
||||
PIO_close(pageSpace->file);
|
||||
|
||||
|
@ -567,7 +567,6 @@ static bool shutdown_locks(thread_db* tdbb, SSHORT flag)
|
||||
for (int retry = 0; retry < 10 && dbb->dbb_use_count; retry++)
|
||||
{
|
||||
// Let active database threads rundown
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
THREAD_SLEEP(1 * 100);
|
||||
}
|
||||
|
||||
|
@ -158,7 +158,7 @@ namespace
|
||||
} // namespace
|
||||
|
||||
|
||||
Sort::Sort(Database* dbb,
|
||||
Sort::Sort(Jrd::Attachment* attachment,
|
||||
SortOwner* owner,
|
||||
USHORT record_length,
|
||||
size_t keys,
|
||||
@ -187,7 +187,7 @@ Sort::Sort(Database* dbb,
|
||||
* includes index key (which must be unique) and record numbers.
|
||||
*
|
||||
**************************************/
|
||||
fb_assert(dbb && owner);
|
||||
fb_assert(attachment && owner);
|
||||
fb_assert(unique_keys <= keys);
|
||||
|
||||
try
|
||||
@ -198,7 +198,7 @@ Sort::Sort(Database* dbb,
|
||||
|
||||
MemoryPool& pool = owner->getPool();
|
||||
|
||||
m_dbb = dbb;
|
||||
m_attachment = attachment;
|
||||
m_longs = ROUNDUP(record_length + SIZEOF_SR_BCKPTR, FB_ALIGNMENT) >> SHIFTLONG;
|
||||
m_dup_callback = call_back;
|
||||
m_dup_callback_arg = user_arg;
|
||||
@ -1735,8 +1735,6 @@ void Sort::orderAndSave()
|
||||
* scratch file as one big chunk
|
||||
*
|
||||
**************************************/
|
||||
Database::Checkout dcoHolder(m_dbb);
|
||||
|
||||
run_control* run = m_runs;
|
||||
run->run_records = 0;
|
||||
|
||||
@ -1831,7 +1829,6 @@ void Sort::sort()
|
||||
* been requested, detect and handle them.
|
||||
*
|
||||
**************************************/
|
||||
Database::Checkout dcoHolder(m_dbb);
|
||||
|
||||
// First, insert a pointer to the high key
|
||||
|
||||
|
@ -213,7 +213,7 @@ typedef bool (*FPTR_REJECT_DUP_CALLBACK)(const UCHAR*, const UCHAR*, void*);
|
||||
class Sort
|
||||
{
|
||||
public:
|
||||
Sort(Database*, SortOwner*,
|
||||
Sort(Jrd::Attachment*, SortOwner*,
|
||||
USHORT, size_t, size_t, const sort_key_def*,
|
||||
FPTR_REJECT_DUP_CALLBACK, void*, FB_UINT64 = 0);
|
||||
~Sort();
|
||||
@ -254,7 +254,7 @@ private:
|
||||
|
||||
static void quick(SLONG, SORTP**, ULONG);
|
||||
|
||||
Database* m_dbb; // Database
|
||||
Attachment* m_attachment; // Attachment
|
||||
SortOwner* m_owner; // Sort owner
|
||||
UCHAR* m_memory; // ALLOC: Memory for sort
|
||||
UCHAR* m_end_memory; // End of memory
|
||||
|
333
src/jrd/tpc.cpp
333
src/jrd/tpc.cpp
@ -22,33 +22,35 @@
|
||||
*/
|
||||
|
||||
#include "firebird.h"
|
||||
#include <string.h>
|
||||
#include "../common/common.h"
|
||||
#include "../jrd/jrd.h"
|
||||
#include "../jrd/tpc.h"
|
||||
#include "../jrd/ods.h"
|
||||
#include "../jrd/tra.h"
|
||||
#include "../jrd/lck.h"
|
||||
#include "../jrd/pag.h"
|
||||
#include "gen/iberror.h"
|
||||
#include "../jrd/cch_proto.h"
|
||||
#include "../jrd/err_proto.h"
|
||||
#include "../yvalve/gds_proto.h"
|
||||
#include "../jrd/lck_proto.h"
|
||||
#include "../jrd/mov_proto.h"
|
||||
#include "../jrd/tpc_proto.h"
|
||||
#include "../jrd/tra_proto.h"
|
||||
#include "../common/classes/auto.h"
|
||||
#include "../common/utils_proto.h"
|
||||
|
||||
using namespace Jrd;
|
||||
|
||||
static TxPageCache* allocate_tpc(thread_db*, SLONG);
|
||||
static SLONG cache_transactions(thread_db*, TxPageCache**, SLONG);
|
||||
static int extend_cache(thread_db*, SLONG);
|
||||
|
||||
|
||||
int TPC_cache_state(thread_db* tdbb, SLONG number)
|
||||
using namespace Firebird;
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
TipCache::TipCache(Database* dbb) :
|
||||
m_dbb(dbb),
|
||||
m_cache(*m_dbb->dbb_permanent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TipCache::~TipCache()
|
||||
{
|
||||
clearCache();
|
||||
}
|
||||
|
||||
|
||||
int TipCache::CacheState(thread_db* tdbb, SLONG number)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -60,39 +62,44 @@ int TPC_cache_state(thread_db* tdbb, SLONG number)
|
||||
* Get the current state of a transaction in the cache.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
CHECK_DBB(dbb);
|
||||
|
||||
const TxPageCache* tip_cache = dbb->dbb_tip_cache;
|
||||
if (!tip_cache)
|
||||
{
|
||||
TPC_initialize_tpc(tdbb, number);
|
||||
tip_cache = dbb->dbb_tip_cache;
|
||||
}
|
||||
|
||||
if (number && dbb->dbb_pc_transactions)
|
||||
if (number && m_dbb->dbb_pc_transactions)
|
||||
{
|
||||
if (TRA_precommited(tdbb, number, number))
|
||||
return tra_precommitted;
|
||||
}
|
||||
|
||||
SyncLockGuard sync(&m_sync, SYNC_SHARED, "TipCache::CacheState");
|
||||
|
||||
if (!m_cache.getCount())
|
||||
{
|
||||
SyncUnlockGuard unlock(sync);
|
||||
InitializeTpc(tdbb, number);
|
||||
}
|
||||
|
||||
// if the transaction is older than the oldest
|
||||
// transaction in our tip cache, it must be committed
|
||||
// hvlad: system transaction always committed too
|
||||
|
||||
TxPage* tip_cache = m_cache[m_cache.getCount() - 1];
|
||||
if (number < tip_cache->tpc_base || number == 0)
|
||||
return tra_committed;
|
||||
|
||||
// locate the specific TIP cache block for the transaction
|
||||
|
||||
const SLONG trans_per_tip = dbb->dbb_page_manager.transPerTIP;
|
||||
for (; tip_cache; tip_cache = tip_cache->tpc_next)
|
||||
const SLONG trans_per_tip = m_dbb->dbb_page_manager.transPerTIP;
|
||||
const SLONG base = number - number % trans_per_tip;
|
||||
|
||||
size_t pos;
|
||||
if (m_cache.find(base, pos))
|
||||
{
|
||||
if ((ULONG) number < (ULONG) (tip_cache->tpc_base + trans_per_tip)) {
|
||||
tip_cache = m_cache[pos];
|
||||
|
||||
fb_assert(number >= tip_cache->tpc_base);
|
||||
fb_assert((ULONG) number < (ULONG) (tip_cache->tpc_base + trans_per_tip));
|
||||
|
||||
return TRA_state(tip_cache->tpc_transactions, tip_cache->tpc_base, number);
|
||||
}
|
||||
}
|
||||
|
||||
// Cover all possibilities by returning active
|
||||
|
||||
@ -100,7 +107,7 @@ int TPC_cache_state(thread_db* tdbb, SLONG number)
|
||||
}
|
||||
|
||||
|
||||
void TPC_initialize_tpc(thread_db* tdbb, SLONG number)
|
||||
void TipCache::InitializeTpc(thread_db* tdbb, SLONG number)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -113,14 +120,13 @@ void TPC_initialize_tpc(thread_db* tdbb, SLONG number)
|
||||
* number. This is used at TRA_start () time.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
CHECK_DBB(dbb);
|
||||
|
||||
TxPageCache* tip_cache = dbb->dbb_tip_cache;
|
||||
if (!tip_cache)
|
||||
SyncLockGuard sync(&m_sync, SYNC_EXCLUSIVE, "TipCache::InitializeTpc");
|
||||
|
||||
if (!m_cache.getCount())
|
||||
{
|
||||
cache_transactions(tdbb, NULL, 0);
|
||||
sync.unlock();
|
||||
cacheTransactions(tdbb, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -128,24 +134,25 @@ void TPC_initialize_tpc(thread_db* tdbb, SLONG number)
|
||||
// find the end of the linked list, and cache
|
||||
// all transactions from that point up to the most recent transaction
|
||||
|
||||
const SLONG trans_per_tip = dbb->dbb_page_manager.transPerTIP;
|
||||
const SLONG trans_per_tip = m_dbb->dbb_page_manager.transPerTIP;
|
||||
|
||||
TxPageCache** tip_cache_ptr;
|
||||
for (tip_cache_ptr = &dbb->dbb_tip_cache; *tip_cache_ptr;
|
||||
tip_cache_ptr = &(*tip_cache_ptr)->tpc_next)
|
||||
{
|
||||
tip_cache = *tip_cache_ptr;
|
||||
}
|
||||
const TxPage* tip_cache = m_cache[m_cache.getCount() - 1];
|
||||
|
||||
if ((ULONG) number < (ULONG) (tip_cache->tpc_base + trans_per_tip))
|
||||
return;
|
||||
|
||||
if (tip_cache->tpc_base < MAX_TRA_NUMBER - trans_per_tip)
|
||||
cache_transactions(tdbb, tip_cache_ptr, tip_cache->tpc_base + trans_per_tip);
|
||||
{
|
||||
// ensure last_known calculated *before* unlock !!!
|
||||
const SLONG last_known = tip_cache->tpc_base;
|
||||
sync.unlock();
|
||||
|
||||
cacheTransactions(tdbb, last_known + trans_per_tip);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TPC_set_state(thread_db* tdbb, SLONG number, SSHORT state)
|
||||
void TipCache::SetState(thread_db* tdbb, SLONG number, SSHORT state)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -158,23 +165,26 @@ void TPC_set_state(thread_db* tdbb, SLONG number, SSHORT state)
|
||||
* in the TIP cache.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
CHECK_DBB(dbb);
|
||||
|
||||
const SLONG trans_per_tip = dbb->dbb_page_manager.transPerTIP;
|
||||
const SLONG trans_per_tip = m_dbb->dbb_page_manager.transPerTIP;
|
||||
const SLONG base = number - number % trans_per_tip;
|
||||
const SLONG byte = TRANS_OFFSET(number % trans_per_tip);
|
||||
const SSHORT shift = TRANS_SHIFT(number);
|
||||
|
||||
for (TxPageCache* tip_cache = dbb->dbb_tip_cache; tip_cache; tip_cache = tip_cache->tpc_next)
|
||||
{
|
||||
if ((ULONG) number < (ULONG) (tip_cache->tpc_base + trans_per_tip))
|
||||
SyncLockGuard sync(&m_sync, SYNC_EXCLUSIVE, "TipCache::SetState");
|
||||
|
||||
size_t pos = 0;
|
||||
if (m_cache.find(base, pos))
|
||||
{
|
||||
TxPage* tip_cache = m_cache[pos];
|
||||
|
||||
fb_assert(number >= tip_cache->tpc_base);
|
||||
fb_assert((ULONG) number < (ULONG) (tip_cache->tpc_base + trans_per_tip));
|
||||
|
||||
UCHAR* address = tip_cache->tpc_transactions + byte;
|
||||
*address &= ~(TRA_MASK << shift);
|
||||
*address |= state << shift;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// right now we don't set the state of a transaction on a page
|
||||
@ -182,7 +192,7 @@ void TPC_set_state(thread_db* tdbb, SLONG number, SSHORT state)
|
||||
}
|
||||
|
||||
|
||||
int TPC_snapshot_state(thread_db* tdbb, SLONG number)
|
||||
int TipCache::SnapshotState(thread_db* tdbb, SLONG number)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -197,41 +207,49 @@ int TPC_snapshot_state(thread_db* tdbb, SLONG number)
|
||||
* further checking to see if it really is.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
CHECK_DBB(dbb);
|
||||
|
||||
const TxPageCache* tip_cache = dbb->dbb_tip_cache;
|
||||
if (!tip_cache)
|
||||
{
|
||||
cache_transactions(tdbb, NULL, 0);
|
||||
tip_cache = dbb->dbb_tip_cache;
|
||||
}
|
||||
|
||||
if (number && dbb->dbb_pc_transactions)
|
||||
if (number && m_dbb->dbb_pc_transactions)
|
||||
{
|
||||
if (TRA_precommited(tdbb, number, number)) {
|
||||
return tra_precommitted;
|
||||
}
|
||||
}
|
||||
|
||||
SyncLockGuard sync(&m_sync, SYNC_SHARED, "TipCache::SnapshotState");
|
||||
|
||||
if (!m_cache.getCount())
|
||||
{
|
||||
sync.unlock();
|
||||
cacheTransactions(tdbb, 0);
|
||||
sync.lock(SYNC_SHARED, "TipCache::SnapshotState");
|
||||
}
|
||||
|
||||
// if the transaction is older than the oldest
|
||||
// transaction in our tip cache, it must be committed
|
||||
// hvlad: system transaction always committed too
|
||||
|
||||
TxPage* tip_cache = m_cache[0];
|
||||
if (number < tip_cache->tpc_base || number == 0) {
|
||||
return tra_committed;
|
||||
}
|
||||
|
||||
// locate the specific TIP cache block for the transaction
|
||||
|
||||
const SLONG trans_per_tip = dbb->dbb_page_manager.transPerTIP;
|
||||
for (; tip_cache; tip_cache = tip_cache->tpc_next)
|
||||
{
|
||||
if ((ULONG) number < (ULONG) (tip_cache->tpc_base + trans_per_tip))
|
||||
const SLONG trans_per_tip = m_dbb->dbb_page_manager.transPerTIP;
|
||||
const SLONG base = number - number % trans_per_tip;
|
||||
|
||||
size_t pos;
|
||||
if (m_cache.find(base, pos))
|
||||
{
|
||||
tip_cache = m_cache[pos];
|
||||
|
||||
fb_assert(number >= tip_cache->tpc_base);
|
||||
fb_assert((ULONG) number < (ULONG) (tip_cache->tpc_base + trans_per_tip));
|
||||
|
||||
const USHORT state = TRA_state(tip_cache->tpc_transactions, tip_cache->tpc_base, number);
|
||||
|
||||
sync.unlock();
|
||||
|
||||
// committed or dead transactions always stay that
|
||||
// way, so no need to check their current state
|
||||
|
||||
@ -242,10 +260,10 @@ int TPC_snapshot_state(thread_db* tdbb, SLONG number)
|
||||
// see if we can get a lock on the transaction; if we can't
|
||||
// then we know it is still active
|
||||
Lock temp_lock;
|
||||
temp_lock.lck_dbb = dbb;
|
||||
temp_lock.lck_dbb = m_dbb;
|
||||
temp_lock.lck_type = LCK_tra;
|
||||
temp_lock.lck_owner_handle = LCK_get_owner_handle(tdbb, temp_lock.lck_type);
|
||||
temp_lock.lck_parent = dbb->dbb_lock;
|
||||
temp_lock.lck_parent = m_dbb->dbb_lock;
|
||||
temp_lock.lck_length = sizeof(SLONG);
|
||||
temp_lock.lck_key.lck_long = number;
|
||||
|
||||
@ -267,15 +285,14 @@ int TPC_snapshot_state(thread_db* tdbb, SLONG number)
|
||||
|
||||
return TRA_fetch_state(tdbb, number);
|
||||
}
|
||||
}
|
||||
|
||||
// if the transaction has been started since we last looked, extend the cache upward
|
||||
|
||||
return extend_cache(tdbb, number);
|
||||
sync.unlock();
|
||||
return extendCache(tdbb, number);
|
||||
}
|
||||
|
||||
|
||||
void TPC_update_cache(thread_db* tdbb, const Ods::tx_inv_page* tip_page, SLONG sequence)
|
||||
void TipCache::UpdateCache(thread_db* tdbb, const Ods::tx_inv_page* tip_page, SLONG sequence)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -291,23 +308,22 @@ void TPC_update_cache(thread_db* tdbb, const Ods::tx_inv_page* tip_page, SLONG s
|
||||
*
|
||||
**************************************/
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
CHECK_DBB(dbb);
|
||||
|
||||
const SLONG trans_per_tip = dbb->dbb_page_manager.transPerTIP;
|
||||
const SLONG trans_per_tip = m_dbb->dbb_page_manager.transPerTIP;
|
||||
const SLONG first_trans = sequence * trans_per_tip;
|
||||
|
||||
// while we're in the area we can check to see if there are
|
||||
// any tip cache pages we can release--this is cheaper and
|
||||
// easier than finding out when a TIP page is dropped
|
||||
|
||||
TxPageCache* tip_cache;
|
||||
while ( (tip_cache = dbb->dbb_tip_cache) )
|
||||
SyncLockGuard sync(&m_sync, SYNC_EXCLUSIVE, "TipCache::UpdateCache");
|
||||
|
||||
TxPage* tip_cache = NULL;
|
||||
while (m_cache.getCount())
|
||||
{
|
||||
if ((ULONG) dbb->dbb_oldest_transaction >= (ULONG) (tip_cache->tpc_base + trans_per_tip))
|
||||
tip_cache = m_cache[0];
|
||||
if ((ULONG) m_dbb->dbb_oldest_transaction >= (ULONG) (tip_cache->tpc_base + trans_per_tip))
|
||||
{
|
||||
dbb->dbb_tip_cache = tip_cache->tpc_next;
|
||||
m_cache.remove((size_t)0);
|
||||
delete tip_cache;
|
||||
}
|
||||
else
|
||||
@ -317,25 +333,22 @@ void TPC_update_cache(thread_db* tdbb, const Ods::tx_inv_page* tip_page, SLONG s
|
||||
// find the appropriate page in the TIP cache and assign all transaction
|
||||
// bits -- it's not worth figuring out which ones are actually used
|
||||
|
||||
for (; tip_cache; tip_cache = tip_cache->tpc_next)
|
||||
{
|
||||
if (first_trans == tip_cache->tpc_base)
|
||||
{
|
||||
size_t pos;
|
||||
if (m_cache.find(first_trans, pos)) {
|
||||
tip_cache = m_cache[pos];
|
||||
}
|
||||
else {
|
||||
tip_cache = allocTxPage(tdbb, first_trans);
|
||||
m_cache.insert(pos, tip_cache);
|
||||
}
|
||||
fb_assert(first_trans == tip_cache->tpc_base);
|
||||
|
||||
const USHORT l = TRANS_OFFSET(trans_per_tip);
|
||||
memcpy(tip_cache->tpc_transactions, tip_page->tip_transactions, l);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// note that a potential optimization here would be to extend the cache
|
||||
// if the fetched page is not already in cache; it would involve a little
|
||||
// extra effort to make sure the pages remained in order, and since there
|
||||
// is a fetched page passed to us we can't fetch any other pages in this
|
||||
// routine, so I just decided not to do it - djb
|
||||
}
|
||||
|
||||
|
||||
static TxPageCache* allocate_tpc(thread_db* tdbb, SLONG base)
|
||||
TipCache::TxPage* TipCache::allocTxPage(thread_db* tdbb, SLONG base)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -348,19 +361,20 @@ static TxPageCache* allocate_tpc(thread_db* tdbb, SLONG base)
|
||||
* of all transactions on one page.
|
||||
*
|
||||
**************************************/
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
const SLONG trans_per_tip = dbb->dbb_page_manager.transPerTIP;
|
||||
fb_assert(m_sync.ourExclusiveLock());
|
||||
|
||||
const SLONG trans_per_tip = m_dbb->dbb_page_manager.transPerTIP;
|
||||
|
||||
// allocate a TIP cache block with enough room for all desired transactions
|
||||
|
||||
TxPageCache* tip_cache = FB_NEW_RPT(*dbb->dbb_permanent, trans_per_tip / 4) TxPageCache();
|
||||
TxPage* tip_cache = FB_NEW_RPT(*m_dbb->dbb_permanent, trans_per_tip / 4) TxPage();
|
||||
tip_cache->tpc_base = base;
|
||||
|
||||
return tip_cache;
|
||||
}
|
||||
|
||||
|
||||
static SLONG cache_transactions(thread_db* tdbb, TxPageCache** tip_cache_ptr, SLONG oldest)
|
||||
SLONG TipCache::cacheTransactions(thread_db* tdbb, SLONG oldest)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -374,14 +388,14 @@ static SLONG cache_transactions(thread_db* tdbb, TxPageCache** tip_cache_ptr, SL
|
||||
* the oldest interesting transaction.
|
||||
*
|
||||
**************************************/
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
CHECK_DBB(dbb);
|
||||
|
||||
// m_sync should be unlocked here !
|
||||
|
||||
// check the header page for the oldest and newest transaction numbers
|
||||
|
||||
#ifdef SUPERSERVER_V2
|
||||
const SLONG top = dbb->dbb_next_transaction;
|
||||
const ULONG hdr_oldest = dbb->dbb_oldest_transaction;
|
||||
const SLONG top = m_dbb->dbb_next_transaction;
|
||||
const ULONG hdr_oldest = m_dbb->dbb_oldest_transaction;
|
||||
#else
|
||||
WIN window(HEADER_PAGE_NUMBER);
|
||||
const Ods::header_page* header = (Ods::header_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_header);
|
||||
@ -389,46 +403,56 @@ static SLONG cache_transactions(thread_db* tdbb, TxPageCache** tip_cache_ptr, SL
|
||||
const SLONG hdr_oldest = header->hdr_oldest_transaction;
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
#endif
|
||||
oldest = MAX(oldest, hdr_oldest);
|
||||
|
||||
// allocate TxPageCache blocks to hold all transaction states --
|
||||
// assign one TxPageCache block per page to simplify cache maintenance
|
||||
|
||||
const SLONG trans_per_tip = dbb->dbb_page_manager.transPerTIP;
|
||||
if (!tip_cache_ptr)
|
||||
tip_cache_ptr = &dbb->dbb_tip_cache;
|
||||
|
||||
for (SLONG base = oldest - oldest % trans_per_tip; base <= top; base += trans_per_tip)
|
||||
{
|
||||
*tip_cache_ptr = allocate_tpc(tdbb, base);
|
||||
tip_cache_ptr = &(*tip_cache_ptr)->tpc_next;
|
||||
|
||||
if (base >= MAX_TRA_NUMBER - trans_per_tip)
|
||||
break;
|
||||
}
|
||||
|
||||
// now get the inventory of all transactions, which will
|
||||
// automatically fill in the tip cache pages
|
||||
|
||||
TRA_get_inventory(tdbb, NULL, oldest, top);
|
||||
|
||||
// hvlad: No need to cache TIP pages below hdr_oldest just refreshed from
|
||||
// header page. Moreover out tip cache can now contain an gap between last
|
||||
// cached tip page and new pages if our process was idle for long time
|
||||
|
||||
for (TxPageCache* tip_cache = dbb->dbb_tip_cache;
|
||||
tip_cache && ((ULONG) (tip_cache->tpc_base + trans_per_tip) < (ULONG) hdr_oldest);
|
||||
tip_cache = dbb->dbb_tip_cache)
|
||||
oldest = MAX(oldest, hdr_oldest);
|
||||
|
||||
// now get the inventory of all transactions, which will automatically
|
||||
// fill in the tip cache pages
|
||||
// hvlad: note, call below will call UpdateCache() which will acquire m_sync
|
||||
// in exclusive mode. This is the reason why m_sync must be unlocked at the
|
||||
// entry of this routine
|
||||
|
||||
TRA_get_inventory(tdbb, NULL, oldest, top);
|
||||
|
||||
SyncLockGuard sync(&m_sync, SYNC_EXCLUSIVE, "TipCache::UpdateCache");
|
||||
|
||||
const SLONG trans_per_tip = m_dbb->dbb_page_manager.transPerTIP;
|
||||
while (m_cache.getCount())
|
||||
{
|
||||
dbb->dbb_tip_cache = tip_cache->tpc_next;
|
||||
TxPage* tip_cache = m_cache[0];
|
||||
if ((ULONG) (tip_cache->tpc_base + trans_per_tip) < (ULONG) hdr_oldest)
|
||||
{
|
||||
m_cache.remove((size_t)0);
|
||||
delete tip_cache;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return hdr_oldest;
|
||||
}
|
||||
|
||||
|
||||
static int extend_cache(thread_db* tdbb, SLONG number)
|
||||
void TipCache::clearCache()
|
||||
{
|
||||
fb_assert(m_sync.ourExclusiveLock());
|
||||
|
||||
while (m_cache.getCount())
|
||||
{
|
||||
const size_t pos = m_cache.getCount() - 1;
|
||||
TxPage* tip_page = m_cache[pos];
|
||||
|
||||
m_cache.remove(pos);
|
||||
delete tip_page;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int TipCache::extendCache(thread_db* tdbb, SLONG number)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -443,33 +467,45 @@ static int extend_cache(thread_db* tdbb, SLONG number)
|
||||
* the state of the passed transaction.
|
||||
*
|
||||
**************************************/
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
const SLONG trans_per_tip = dbb->dbb_page_manager.transPerTIP;
|
||||
|
||||
// m_sync should be unlocked here !
|
||||
|
||||
const SLONG trans_per_tip = m_dbb->dbb_page_manager.transPerTIP;
|
||||
|
||||
// find the end of the linked list, and cache
|
||||
// all transactions from that point up to the
|
||||
// most recent transaction
|
||||
|
||||
TxPageCache* tip_cache = 0;
|
||||
TxPageCache** tip_cache_ptr;
|
||||
for (tip_cache_ptr = &dbb->dbb_tip_cache; *tip_cache_ptr;
|
||||
tip_cache_ptr = &(*tip_cache_ptr)->tpc_next)
|
||||
{
|
||||
tip_cache = *tip_cache_ptr;
|
||||
}
|
||||
Sync sync(&m_sync, "extendCache");
|
||||
sync.lock(SYNC_SHARED);
|
||||
|
||||
fb_assert(m_cache.getCount() > 0);
|
||||
TxPage* tip_cache = m_cache[m_cache.getCount() - 1];
|
||||
|
||||
if (tip_cache->tpc_base < MAX_TRA_NUMBER - trans_per_tip)
|
||||
{
|
||||
const SLONG oldest = cache_transactions(tdbb, tip_cache_ptr, tip_cache->tpc_base + trans_per_tip);
|
||||
// ensure last_known calculated *before* unlock !!!
|
||||
const SLONG last_known = tip_cache->tpc_base;
|
||||
sync.unlock();
|
||||
|
||||
const SLONG oldest = cacheTransactions(tdbb, last_known + trans_per_tip);
|
||||
if (number < oldest)
|
||||
return tra_committed;
|
||||
|
||||
sync.lock(SYNC_SHARED);
|
||||
}
|
||||
|
||||
// find the right block for this transaction and return the state
|
||||
|
||||
for (tip_cache = dbb->dbb_tip_cache; tip_cache; tip_cache = tip_cache->tpc_next)
|
||||
const SLONG base = number - number % trans_per_tip;
|
||||
size_t pos;
|
||||
if (m_cache.find(base, pos))
|
||||
{
|
||||
if ((ULONG) number < (ULONG) (tip_cache->tpc_base + trans_per_tip))
|
||||
tip_cache = m_cache[pos];
|
||||
|
||||
fb_assert(number >= tip_cache->tpc_base);
|
||||
fb_assert((ULONG) number < (ULONG) (tip_cache->tpc_base + trans_per_tip));
|
||||
|
||||
return TRA_state(tip_cache->tpc_transactions, tip_cache->tpc_base, number);
|
||||
}
|
||||
|
||||
@ -479,3 +515,4 @@ static int extend_cache(thread_db* tdbb, SLONG number)
|
||||
return tra_active;
|
||||
}
|
||||
|
||||
} // namespace Jrd
|
||||
|
@ -24,11 +24,77 @@
|
||||
#ifndef JRD_TPC_PROTO_H
|
||||
#define JRD_TPC_PROTO_H
|
||||
|
||||
int TPC_cache_state(Jrd::thread_db*, SLONG);
|
||||
void TPC_initialize_tpc(Jrd::thread_db*, SLONG);
|
||||
void TPC_set_state(Jrd::thread_db*, SLONG, SSHORT);
|
||||
int TPC_snapshot_state(Jrd::thread_db*, SLONG);
|
||||
void TPC_update_cache(Jrd::thread_db*, const Ods::tx_inv_page*, SLONG);
|
||||
#include "../common/classes/array.h"
|
||||
#include "../common/classes/SyncObject.h"
|
||||
|
||||
namespace Ods {
|
||||
struct tx_inv_page;
|
||||
};
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
class Database;
|
||||
class thread_db;
|
||||
|
||||
class TipCache
|
||||
{
|
||||
public:
|
||||
TipCache(Database* dbb);
|
||||
~TipCache();
|
||||
|
||||
int CacheState(thread_db*, SLONG number);
|
||||
void InitializeTpc(thread_db*, SLONG number);
|
||||
void SetState(thread_db*, SLONG number, SSHORT state);
|
||||
int SnapshotState(thread_db*, SLONG number);
|
||||
void UpdateCache(thread_db*, const Ods::tx_inv_page* tip_page, SLONG sequence);
|
||||
|
||||
private:
|
||||
class TxPage : public pool_alloc_rpt<SCHAR, type_tpc>
|
||||
{
|
||||
public:
|
||||
SLONG tpc_base; // id of first transaction in this block
|
||||
UCHAR tpc_transactions[1]; // two bits per transaction
|
||||
|
||||
static const SLONG generate(const void*, const TxPage* item)
|
||||
{ return item->tpc_base; }
|
||||
};
|
||||
|
||||
TxPage* allocTxPage(thread_db* tdbb, SLONG base);
|
||||
SLONG cacheTransactions(thread_db* tdbb, SLONG oldest);
|
||||
int extendCache(thread_db* tdbb, SLONG number);
|
||||
void clearCache();
|
||||
|
||||
Database* m_dbb;
|
||||
Firebird::SyncObject m_sync;
|
||||
Firebird::SortedArray<TxPage*, Firebird::EmptyStorage<TxPage*>, SLONG, TxPage> m_cache;
|
||||
};
|
||||
|
||||
|
||||
inline int TPC_cache_state(thread_db* tdbb, SLONG number)
|
||||
{
|
||||
return tdbb->getDatabase()->dbb_tip_cache->CacheState(tdbb, number);
|
||||
}
|
||||
|
||||
inline void TPC_initialize_tpc(thread_db* tdbb, SLONG number)
|
||||
{
|
||||
tdbb->getDatabase()->dbb_tip_cache->InitializeTpc(tdbb, number);
|
||||
}
|
||||
|
||||
inline void TPC_set_state(thread_db* tdbb, SLONG number, SSHORT state)
|
||||
{
|
||||
tdbb->getDatabase()->dbb_tip_cache->SetState(tdbb, number, state);
|
||||
}
|
||||
|
||||
inline int TPC_snapshot_state(thread_db* tdbb, SLONG number)
|
||||
{
|
||||
return tdbb->getDatabase()->dbb_tip_cache->SnapshotState(tdbb, number);
|
||||
}
|
||||
|
||||
inline void TPC_update_cache(thread_db* tdbb, const Ods::tx_inv_page* tip_page, SLONG sequence)
|
||||
{
|
||||
tdbb->getDatabase()->dbb_tip_cache->UpdateCache(tdbb, tip_page, sequence);
|
||||
}
|
||||
|
||||
} // namespace Jrd
|
||||
#endif // JRD_TPC_PROTO_H
|
||||
|
||||
|
@ -521,7 +521,7 @@ void TRA_extend_tip(thread_db* tdbb, ULONG sequence) //, WIN* precedence_window)
|
||||
tx_inv_page* tip = (tx_inv_page*) DPM_allocate(tdbb, &window);
|
||||
tip->tip_header.pag_type = pag_transactions;
|
||||
|
||||
CCH_must_write(&window);
|
||||
CCH_must_write(tdbb, &window);
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
|
||||
// Release prior page
|
||||
@ -778,9 +778,12 @@ void TRA_invalidate(Database* database, ULONG mask)
|
||||
* modified a page that couldn't be written.
|
||||
*
|
||||
**************************************/
|
||||
SyncLockGuard dbbGuard(&database->dbb_sync, SYNC_EXCLUSIVE, "TRA_invalidate");
|
||||
|
||||
for (Jrd::Attachment* attachment = database->dbb_attachments; attachment;
|
||||
attachment = attachment->att_next)
|
||||
{
|
||||
Jrd::Attachment::SyncGuard attGuard(attachment);
|
||||
for (jrd_tra* transaction = attachment->att_transactions; transaction;
|
||||
transaction = transaction->tra_next)
|
||||
{
|
||||
@ -1069,7 +1072,7 @@ jrd_tra* TRA_reconnect(thread_db* tdbb, const UCHAR* id, USHORT length)
|
||||
Arg::Gds(isc_tra_state) << Arg::Num(number) << Arg::Str(text));
|
||||
}
|
||||
|
||||
MemoryPool* const pool = dbb->createPool();
|
||||
MemoryPool* const pool = attachment->createPool();
|
||||
Jrd::ContextPoolHolder context(tdbb, pool);
|
||||
jrd_tra* const trans = jrd_tra::create(pool, attachment, NULL);
|
||||
trans->tra_number = number;
|
||||
@ -1160,7 +1163,7 @@ void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction)
|
||||
}
|
||||
|
||||
{ // scope
|
||||
vec<jrd_rel*>& rels = *dbb->dbb_relations;
|
||||
vec<jrd_rel*>& rels = *attachment->att_relations;
|
||||
for (size_t i = 0; i < rels.count(); i++)
|
||||
{
|
||||
jrd_rel* relation = rels[i];
|
||||
@ -1228,7 +1231,7 @@ void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction)
|
||||
|
||||
// Release the transaction and its pool
|
||||
|
||||
jrd_tra::destroy(dbb, transaction);
|
||||
jrd_tra::destroy(attachment, transaction);
|
||||
}
|
||||
|
||||
|
||||
@ -1418,7 +1421,6 @@ void TRA_set_state(thread_db* tdbb, jrd_tra* transaction, SLONG number, SSHORT s
|
||||
|
||||
const ULONG trans_per_tip = dbb->dbb_page_manager.transPerTIP;
|
||||
const SLONG sequence = number / trans_per_tip;
|
||||
//trans_per_tip = dbb->dbb_page_manager.transPerTIP;
|
||||
const ULONG byte = TRANS_OFFSET(number % trans_per_tip);
|
||||
const SSHORT shift = TRANS_SHIFT(number);
|
||||
|
||||
@ -1427,7 +1429,7 @@ void TRA_set_state(thread_db* tdbb, jrd_tra* transaction, SLONG number, SSHORT s
|
||||
|
||||
#ifdef SUPERSERVER_V2
|
||||
CCH_MARK(tdbb, &window);
|
||||
const ULONG generation = tip->pag_generation;
|
||||
const ULONG generation = tip->tip_header.pag_generation;
|
||||
#else
|
||||
CCH_MARK_MUST_WRITE(tdbb, &window);
|
||||
#endif
|
||||
@ -1459,7 +1461,7 @@ void TRA_set_state(thread_db* tdbb, jrd_tra* transaction, SLONG number, SSHORT s
|
||||
THREAD_YIELD();
|
||||
}
|
||||
tip = reinterpret_cast<tx_inv_page*>(CCH_FETCH(tdbb, &window, LCK_write, pag_transactions));
|
||||
if (generation == tip->pag_generation)
|
||||
if (generation == tip->tip_header.pag_generation)
|
||||
CCH_MARK_MUST_WRITE(tdbb, &window);
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
#endif
|
||||
@ -1597,7 +1599,7 @@ jrd_tra* TRA_start(thread_db* tdbb, ULONG flags, SSHORT lock_timeout, Jrd::jrd_t
|
||||
// To handle the problems of relation locks, allocate a temporary
|
||||
// transaction block first, seize relation locks, then go ahead and
|
||||
// make up the real transaction block.
|
||||
MemoryPool* const pool = outer ? outer->tra_pool : dbb->createPool();
|
||||
MemoryPool* const pool = outer ? outer->tra_pool : attachment->createPool();
|
||||
Jrd::ContextPoolHolder context(tdbb, pool);
|
||||
jrd_tra* const temp = jrd_tra::create(pool, attachment, outer);
|
||||
|
||||
@ -1612,7 +1614,7 @@ jrd_tra* TRA_start(thread_db* tdbb, ULONG flags, SSHORT lock_timeout, Jrd::jrd_t
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
jrd_tra::destroy(dbb, temp);
|
||||
jrd_tra::destroy(attachment, temp);
|
||||
throw;
|
||||
}
|
||||
|
||||
@ -1652,7 +1654,7 @@ jrd_tra* TRA_start(thread_db* tdbb, int tpb_length, const UCHAR* tpb, Jrd::jrd_t
|
||||
// To handle the problems of relation locks, allocate a temporary
|
||||
// transaction block first, seize relation locks, then go ahead and
|
||||
// make up the real transaction block.
|
||||
MemoryPool* const pool = outer ? outer->tra_pool : dbb->createPool();
|
||||
MemoryPool* const pool = outer ? outer->tra_pool : attachment->createPool();
|
||||
Jrd::ContextPoolHolder context(tdbb, pool);
|
||||
jrd_tra* const temp = jrd_tra::create(pool, attachment, outer);
|
||||
|
||||
@ -1665,7 +1667,7 @@ jrd_tra* TRA_start(thread_db* tdbb, int tpb_length, const UCHAR* tpb, Jrd::jrd_t
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
jrd_tra::destroy(dbb, temp);
|
||||
jrd_tra::destroy(attachment, temp);
|
||||
throw;
|
||||
}
|
||||
|
||||
@ -1967,15 +1969,14 @@ static int blocking_ast_transaction(void* ast_object)
|
||||
try
|
||||
{
|
||||
Database* dbb = transaction->tra_cancel_lock->lck_dbb;
|
||||
|
||||
Database::SyncGuard dsGuard(dbb, true);
|
||||
Jrd::Attachment* att = transaction->tra_cancel_lock->lck_attachment;
|
||||
|
||||
ThreadContextHolder tdbb;
|
||||
tdbb->setDatabase(dbb);
|
||||
Jrd::Attachment* att = transaction->tra_cancel_lock->lck_attachment;
|
||||
tdbb->setAttachment(att);
|
||||
|
||||
Jrd::ContextPoolHolder context(tdbb, 0);
|
||||
Jrd::Attachment::SyncGuard guard(att);
|
||||
|
||||
if (transaction->tra_cancel_lock)
|
||||
LCK_release(tdbb, transaction->tra_cancel_lock);
|
||||
@ -3335,7 +3336,7 @@ static jrd_tra* transaction_start(thread_db* tdbb, jrd_tra* temp)
|
||||
if (!(dbb->dbb_flags & DBB_read_only))
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
#endif
|
||||
jrd_tra::destroy(dbb, trans);
|
||||
jrd_tra::destroy(attachment, trans);
|
||||
ERR_post(Arg::Gds(isc_lock_conflict));
|
||||
}
|
||||
|
||||
|
@ -192,11 +192,11 @@ public:
|
||||
return transaction;
|
||||
}
|
||||
|
||||
static void destroy(Database* const dbb, jrd_tra* const transaction)
|
||||
static void destroy(Attachment* const attachment, jrd_tra* const transaction)
|
||||
{
|
||||
if (transaction)
|
||||
{
|
||||
if (!dbb || transaction->tra_outer)
|
||||
if (!attachment || transaction->tra_outer)
|
||||
delete transaction;
|
||||
else
|
||||
{
|
||||
@ -204,7 +204,7 @@ public:
|
||||
Firebird::MemoryStats temp_stats;
|
||||
pool->setStatsGroup(temp_stats);
|
||||
delete transaction;
|
||||
dbb->deletePool(pool);
|
||||
attachment->deletePool(pool);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
TraceRuntimeStats stats(m_attachment->att_database, m_request->req_fetch_baseline,
|
||||
TraceRuntimeStats stats(m_attachment, m_request->req_fetch_baseline,
|
||||
&m_request->req_request->req_stats,
|
||||
fb_utils::query_performance_counter() - m_start_clock,
|
||||
m_request->req_fetch_rowcount);
|
||||
@ -210,7 +210,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
TraceRuntimeStats stats(m_attachment->att_database, m_request->req_fetch_baseline,
|
||||
TraceRuntimeStats stats(m_attachment, m_request->req_fetch_baseline,
|
||||
&m_request->req_request->req_stats, m_request->req_fetch_elapsed,
|
||||
m_request->req_fetch_rowcount);
|
||||
|
||||
|
@ -64,9 +64,9 @@ public:
|
||||
|
||||
m_need_trace = false;
|
||||
|
||||
const Attachment* attachment = m_transaction->tra_attachment;
|
||||
Attachment* attachment = m_transaction->tra_attachment;
|
||||
|
||||
TraceRuntimeStats stats(attachment->att_database, m_baseline, &m_transaction->tra_stats,
|
||||
TraceRuntimeStats stats(attachment, m_baseline, &m_transaction->tra_stats,
|
||||
fb_utils::query_performance_counter() - m_start_clock, 0);
|
||||
|
||||
TraceConnectionImpl conn(attachment);
|
||||
@ -137,8 +137,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
Database* dbb = m_tdbb->getDatabase();
|
||||
TraceRuntimeStats stats(dbb, m_request->req_fetch_baseline, &m_request->req_stats,
|
||||
TraceRuntimeStats stats(m_tdbb->getAttachment(), m_request->req_fetch_baseline, &m_request->req_stats,
|
||||
fb_utils::query_performance_counter() - m_start_clock,
|
||||
m_request->req_fetch_rowcount);
|
||||
|
||||
@ -197,8 +196,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
Database* dbb = m_tdbb->getDatabase();
|
||||
TraceRuntimeStats stats(dbb, m_request->req_fetch_baseline, &m_request->req_stats,
|
||||
TraceRuntimeStats stats(m_tdbb->getAttachment(), m_request->req_fetch_baseline, &m_request->req_stats,
|
||||
m_request->req_fetch_elapsed, m_request->req_fetch_rowcount);
|
||||
|
||||
TraceConnectionImpl conn(m_tdbb->getAttachment());
|
||||
@ -260,8 +258,7 @@ public:
|
||||
|
||||
m_need_trace = false;
|
||||
|
||||
Database* dbb = m_tdbb->getDatabase();
|
||||
TraceRuntimeStats stats(dbb, m_request->req_fetch_baseline, &m_request->req_stats,
|
||||
TraceRuntimeStats stats(m_tdbb->getAttachment(), m_request->req_fetch_baseline, &m_request->req_stats,
|
||||
fb_utils::query_performance_counter() - m_start_clock, 0);
|
||||
|
||||
TraceConnectionImpl conn(m_tdbb->getAttachment());
|
||||
@ -388,8 +385,7 @@ public:
|
||||
|
||||
m_need_trace = false;
|
||||
|
||||
Database* dbb = m_tdbb->getDatabase();
|
||||
TraceRuntimeStats stats(dbb, m_request->req_fetch_baseline, &m_request->req_stats,
|
||||
TraceRuntimeStats stats(m_tdbb->getAttachment(), m_request->req_fetch_baseline, &m_request->req_stats,
|
||||
fb_utils::query_performance_counter() - m_start_clock,
|
||||
m_request->req_fetch_rowcount);
|
||||
|
||||
|
@ -563,14 +563,14 @@ const char* TraceServiceImpl::getRemoteProcessName()
|
||||
|
||||
/// TraceRuntimeStats
|
||||
|
||||
TraceRuntimeStats::TraceRuntimeStats(Database* dbb, RuntimeStatistics* baseline, RuntimeStatistics* stats,
|
||||
TraceRuntimeStats::TraceRuntimeStats(Attachment* att, RuntimeStatistics* baseline, RuntimeStatistics* stats,
|
||||
SINT64 clock, SINT64 records_fetched)
|
||||
{
|
||||
m_info.pin_time = clock * 1000 / fb_utils::query_performance_frequency();
|
||||
m_info.pin_records_fetched = records_fetched;
|
||||
|
||||
if (baseline)
|
||||
baseline->computeDifference(dbb, *stats, m_info, m_counts);
|
||||
baseline->computeDifference(att, *stats, m_info, m_counts);
|
||||
else
|
||||
{
|
||||
// Report all zero counts for the moment.
|
||||
|
@ -328,7 +328,7 @@ private:
|
||||
class TraceRuntimeStats
|
||||
{
|
||||
public:
|
||||
TraceRuntimeStats(Database* dbb, RuntimeStatistics* baseline, RuntimeStatistics* stats,
|
||||
TraceRuntimeStats(Attachment* att, RuntimeStatistics* baseline, RuntimeStatistics* stats,
|
||||
SINT64 clock, SINT64 records_fetched);
|
||||
|
||||
PerformanceInfo* getPerf() { return &m_info; }
|
||||
|
@ -617,7 +617,7 @@ enum RTN {
|
||||
|
||||
#pragma FB_COMPILER_MESSAGE("This table goes to gds__log and it's not localized")
|
||||
|
||||
static const TEXT msg_table[VAL_MAX_ERROR][66] =
|
||||
static const TEXT msg_table[VAL_MAX_ERROR][80] =
|
||||
{
|
||||
"Page %ld wrong type (expected %d encountered %d)", // 0
|
||||
"Checksum error on page %ld",
|
||||
@ -630,7 +630,7 @@ static const TEXT msg_table[VAL_MAX_ERROR][66] =
|
||||
"Chain for record %ld is broken",
|
||||
"Data page %ld (sequence %ld) is confused",
|
||||
"Data page %ld (sequence %ld), line %ld is bad", // 10
|
||||
"Index %d is corrupt on page %ld level %d. File: %s, line: %d\n\t",
|
||||
"Index %d is corrupt on page %ld level %d at offset %d. File: %s, line: %d\n\t",
|
||||
"Pointer page (sequence %ld) lost",
|
||||
"Pointer page (sequence %ld) inconsistent",
|
||||
"Record %ld is marked as damaged",
|
||||
@ -1174,7 +1174,7 @@ static void walk_database(thread_db* tdbb, vdr* control)
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
|
||||
#ifdef DEBUG_VAL_VERBOSE
|
||||
if (VAL_debug_level)
|
||||
@ -1199,7 +1199,7 @@ static void walk_database(thread_db* tdbb, vdr* control)
|
||||
walk_generators(tdbb, control);
|
||||
|
||||
vec<jrd_rel*>* vector;
|
||||
for (USHORT i = 0; (vector = dbb->dbb_relations) && i < vector->count(); i++)
|
||||
for (USHORT i = 0; (vector = attachment->att_relations) && i < vector->count(); i++)
|
||||
{
|
||||
#ifdef DEBUG_VAL_VERBOSE
|
||||
if (i >= 32 /* rel_MAX */ ) // Why not system flag instead?
|
||||
@ -1487,7 +1487,7 @@ static RTN walk_index(thread_db* tdbb, vdr* control, jrd_rel* relation,
|
||||
(page->btr_header.pag_flags & BTR_FLAG_COPY_MASK) != (flags & BTR_FLAG_COPY_MASK))
|
||||
{
|
||||
corrupt(tdbb, control, VAL_INDEX_PAGE_CORRUPT, relation,
|
||||
id + 1, next, page->btr_level, __FILE__, __LINE__);
|
||||
id + 1, next, page->btr_level, 0, __FILE__, __LINE__);
|
||||
}
|
||||
flags = page->btr_header.pag_flags;
|
||||
const bool leafPage = (page->btr_level == 0);
|
||||
@ -1496,7 +1496,7 @@ static RTN walk_index(thread_db* tdbb, vdr* control, jrd_rel* relation,
|
||||
if (page->btr_relation != relation->rel_id || page->btr_id != (UCHAR) (id % 256))
|
||||
{
|
||||
corrupt(tdbb, control, VAL_INDEX_PAGE_CORRUPT, relation, id + 1,
|
||||
next, page->btr_level, __FILE__, __LINE__);
|
||||
next, page->btr_level, 0, __FILE__, __LINE__);
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
return rtn_corrupt;
|
||||
}
|
||||
@ -1511,7 +1511,7 @@ static RTN walk_index(thread_db* tdbb, vdr* control, jrd_rel* relation,
|
||||
(jumpInfo.firstNodeOffset > page->btr_length))
|
||||
{
|
||||
corrupt(tdbb, control, VAL_INDEX_PAGE_CORRUPT, relation,
|
||||
id + 1, next, page->btr_level, __FILE__, __LINE__);
|
||||
id + 1, next, page->btr_level, pointer - (UCHAR*)page, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
USHORT n = jumpInfo.jumpers;
|
||||
@ -1527,7 +1527,7 @@ static RTN walk_index(thread_db* tdbb, vdr* control, jrd_rel* relation,
|
||||
(jumpNode.offset > page->btr_length))
|
||||
{
|
||||
corrupt(tdbb, control, VAL_INDEX_PAGE_CORRUPT, relation,
|
||||
id + 1, next, page->btr_level, __FILE__, __LINE__);
|
||||
id + 1, next, page->btr_level, pointer - (UCHAR*)page, __FILE__, __LINE__);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1535,7 +1535,7 @@ static RTN walk_index(thread_db* tdbb, vdr* control, jrd_rel* relation,
|
||||
BTreeNode::readNode(&checknode, (UCHAR*) page + jumpNode.offset, leafPage);
|
||||
if ((jumpNode.prefix + jumpNode.length) != checknode.prefix) {
|
||||
corrupt(tdbb, control, VAL_INDEX_PAGE_CORRUPT, relation,
|
||||
id + 1, next, page->btr_level, __FILE__, __LINE__);
|
||||
id + 1, next, page->btr_level, jumpNode.offset, __FILE__, __LINE__);
|
||||
}
|
||||
}
|
||||
n--;
|
||||
@ -1573,7 +1573,7 @@ static RTN walk_index(thread_db* tdbb, vdr* control, jrd_rel* relation,
|
||||
{
|
||||
duplicateNode = false;
|
||||
corrupt(tdbb, control, VAL_INDEX_PAGE_CORRUPT, relation,
|
||||
id + 1, next, page->btr_level, __FILE__, __LINE__);
|
||||
id + 1, next, page->btr_level, q - (UCHAR*)page, __FILE__, __LINE__);
|
||||
}
|
||||
else if (*p < *q)
|
||||
{
|
||||
@ -1598,7 +1598,7 @@ static RTN walk_index(thread_db* tdbb, vdr* control, jrd_rel* relation,
|
||||
(node.recordNumber < lastNode.recordNumber))
|
||||
{
|
||||
corrupt(tdbb, control, VAL_INDEX_PAGE_CORRUPT, relation,
|
||||
id + 1, next, page->btr_level, __FILE__, __LINE__);
|
||||
id + 1, next, page->btr_level, node.nodePointer - (UCHAR*)page, __FILE__, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1658,7 +1658,7 @@ static RTN walk_index(thread_db* tdbb, vdr* control, jrd_rel* relation,
|
||||
if (*p < *q)
|
||||
{
|
||||
corrupt(tdbb, control, VAL_INDEX_PAGE_CORRUPT, relation,
|
||||
id + 1, next, page->btr_level, __FILE__, __LINE__);
|
||||
id + 1, next, page->btr_level, node.nodePointer - (UCHAR*)page, __FILE__, __LINE__);
|
||||
}
|
||||
else if (*p > *q) {
|
||||
break;
|
||||
@ -1679,7 +1679,7 @@ static RTN walk_index(thread_db* tdbb, vdr* control, jrd_rel* relation,
|
||||
(downNode.recordNumber < down_record_number))
|
||||
{
|
||||
corrupt(tdbb, control, VAL_INDEX_PAGE_CORRUPT, relation,
|
||||
id + 1, next, page->btr_level, __FILE__, __LINE__);
|
||||
id + 1, next, page->btr_level, node.nodePointer - (UCHAR*)page, __FILE__, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1687,7 +1687,7 @@ static RTN walk_index(thread_db* tdbb, vdr* control, jrd_rel* relation,
|
||||
if (previous_number != down_page->btr_left_sibling)
|
||||
{
|
||||
corrupt(tdbb, control, VAL_INDEX_PAGE_CORRUPT, relation,
|
||||
id + 1, next, page->btr_level, __FILE__, __LINE__);
|
||||
id + 1, next, page->btr_level, node.nodePointer - (UCHAR*)page, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
BTreeNode::readNode(&downNode, pointer, leafPage);
|
||||
@ -1697,7 +1697,7 @@ static RTN walk_index(thread_db* tdbb, vdr* control, jrd_rel* relation,
|
||||
(next_number != down_page->btr_sibling))
|
||||
{
|
||||
corrupt(tdbb, control, VAL_INDEX_PAGE_CORRUPT, relation,
|
||||
id + 1, next, page->btr_level, __FILE__, __LINE__);
|
||||
id + 1, next, page->btr_level, node.nodePointer - (UCHAR*)page, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
if (downNode.isEndLevel && down_page->btr_sibling) {
|
||||
@ -1712,7 +1712,7 @@ static RTN walk_index(thread_db* tdbb, vdr* control, jrd_rel* relation,
|
||||
if (pointer != endPointer || page->btr_length > dbb->dbb_page_size)
|
||||
{
|
||||
corrupt(tdbb, control, VAL_INDEX_PAGE_CORRUPT, relation, id + 1,
|
||||
next, page->btr_level, __FILE__, __LINE__);
|
||||
next, page->btr_level, pointer - (UCHAR*)page, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
if (next == down)
|
||||
@ -1751,7 +1751,6 @@ static RTN walk_index(thread_db* tdbb, vdr* control, jrd_rel* relation,
|
||||
// have a corrupt index
|
||||
if (control && (control->vdr_flags & vdr_records))
|
||||
{
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
RecordBitmap::Accessor accessor(control->vdr_rel_records);
|
||||
if (accessor.getFirst())
|
||||
do {
|
||||
|
@ -1726,7 +1726,6 @@ void VIO_fini(thread_db* tdbb)
|
||||
dbb->dbb_flags &= ~DBB_garbage_collector;
|
||||
dbb->dbb_gc_sem.release(); // Wake up running thread
|
||||
{ // scope
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
dbb->dbb_gc_fini.enter();
|
||||
}
|
||||
}
|
||||
@ -1866,7 +1865,7 @@ Record* VIO_gc_record(thread_db* tdbb, jrd_rel* relation)
|
||||
// Allocate a vector of garbage collect record blocks for relation.
|
||||
vec<Record*>* vector = relation->rel_gc_rec;
|
||||
if (!vector) {
|
||||
vector = relation->rel_gc_rec = vec<Record*>::newVector(*dbb->dbb_permanent, 1);
|
||||
vector = relation->rel_gc_rec = vec<Record*>::newVector(*relation->rel_pool, 1);
|
||||
}
|
||||
|
||||
// Set the active flag on an inactive garbage collect record block and return it.
|
||||
@ -2098,7 +2097,6 @@ bool VIO_get_current(thread_db* tdbb,
|
||||
VIO_backout(tdbb, rpb, transaction);
|
||||
continue;
|
||||
case tra_precommitted:
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
THREAD_SLEEP(100); // milliseconds
|
||||
continue;
|
||||
}
|
||||
@ -2122,7 +2120,6 @@ bool VIO_get_current(thread_db* tdbb,
|
||||
state = TRA_wait(tdbb, transaction, rpb->rpb_transaction_nr, jrd_tra::tra_probe);
|
||||
|
||||
if (state == tra_active) {
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
THREAD_SLEEP(100); // milliseconds
|
||||
continue;
|
||||
}
|
||||
@ -2235,7 +2232,6 @@ void VIO_init(thread_db* tdbb)
|
||||
}
|
||||
|
||||
{ // scope
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
dbb->dbb_gc_init.enter();
|
||||
}
|
||||
}
|
||||
@ -2312,7 +2308,7 @@ void VIO_merge_proc_sav_points(thread_db* tdbb, jrd_tra* transaction, Savepoint*
|
||||
sav_point_list = &sav_point->sav_next;
|
||||
}
|
||||
|
||||
fb_assert(org_save_point == transaction->tra_save_point);
|
||||
fb_assert(org_save_point == transaction->tra_save_point || !transaction->tra_save_point);
|
||||
}
|
||||
|
||||
|
||||
@ -3177,6 +3173,7 @@ bool VIO_sweep(thread_db* tdbb, jrd_tra* transaction)
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
|
||||
#ifdef VIO_DEBUG
|
||||
if (debug_flag > DEBUG_TRACE) {
|
||||
@ -3203,7 +3200,7 @@ bool VIO_sweep(thread_db* tdbb, jrd_tra* transaction)
|
||||
|
||||
try {
|
||||
|
||||
for (size_t i = 1; (vector = dbb->dbb_relations) && i < vector->count(); i++)
|
||||
for (size_t i = 1; (vector = attachment->att_relations) && i < vector->count(); i++)
|
||||
{
|
||||
if ((relation = (*vector)[i]) && !(relation->rel_flags & (REL_deleted | REL_deleting)) &&
|
||||
relation->getPages(tdbb)->rel_pages)
|
||||
@ -4208,7 +4205,6 @@ static THREAD_ENTRY_DECLARE garbage_collector(THREAD_ENTRY_PARAM arg)
|
||||
**************************************/
|
||||
Database* dbb = (Database*)arg;
|
||||
CHECK_DBB(dbb);
|
||||
Database::SyncGuard dsGuard(dbb);
|
||||
|
||||
ISC_STATUS_ARRAY status_vector;
|
||||
MOVE_CLEAR(status_vector, sizeof(status_vector));
|
||||
@ -4233,7 +4229,7 @@ static THREAD_ENTRY_DECLARE garbage_collector(THREAD_ENTRY_PARAM arg)
|
||||
try {
|
||||
// Pseudo attachment needed for lock owner identification.
|
||||
|
||||
Jrd::Attachment* const attachment = Jrd::Attachment::create(dbb, 0);
|
||||
Jrd::Attachment* const attachment = Jrd::Attachment::create(dbb);
|
||||
tdbb->setAttachment(attachment);
|
||||
attachment->att_filename = dbb->dbb_filename;
|
||||
attachment->att_flags = ATT_garbage_collector;
|
||||
@ -4288,7 +4284,6 @@ static THREAD_ENTRY_DECLARE garbage_collector(THREAD_ENTRY_PARAM arg)
|
||||
while (dbb->dbb_flags & DBB_suspend_bgio)
|
||||
{
|
||||
{ // scope
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
dbb->dbb_gc_sem.tryEnter(10);
|
||||
}
|
||||
if (!(dbb->dbb_flags & DBB_garbage_collector)) {
|
||||
@ -4309,7 +4304,7 @@ static THREAD_ENTRY_DECLARE garbage_collector(THREAD_ENTRY_PARAM arg)
|
||||
// Express interest in the relation to prevent it from being deleted
|
||||
// out from under us while garbage collection is in-progress.
|
||||
|
||||
vec<jrd_rel*>* vector = dbb->dbb_relations;
|
||||
vec<jrd_rel*>* vector = tdbb->getAttachment()->att_relations;
|
||||
for (ULONG id = 0; vector && id < vector->count(); ++id)
|
||||
{
|
||||
relation = (*vector)[id];
|
||||
@ -4457,7 +4452,6 @@ rel_exit:
|
||||
}
|
||||
dbb->dbb_flags &= ~DBB_gc_active;
|
||||
{ // scope
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
dbb->dbb_gc_sem.tryEnter(10);
|
||||
}
|
||||
dbb->dbb_flags |= DBB_gc_active;
|
||||
@ -4760,7 +4754,7 @@ static void notify_garbage_collector(thread_db* tdbb, record_param* rpb, SLONG t
|
||||
// A relation's garbage collect bitmap is allocated
|
||||
// from the database permanent pool.
|
||||
|
||||
Jrd::ContextPoolHolder context(tdbb, dbb->dbb_permanent);
|
||||
Jrd::ContextPoolHolder context(tdbb, relation->rel_pool);
|
||||
const SLONG dp_sequence = rpb->rpb_number.getValue() / dbb->dbb_max_records;
|
||||
|
||||
if (!relation->rel_garbage)
|
||||
@ -5124,7 +5118,6 @@ static int prepare_update( thread_db* tdbb,
|
||||
|
||||
if (state == tra_active)
|
||||
{
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
THREAD_SLEEP(100); // milliseconds
|
||||
continue;
|
||||
}
|
||||
@ -5184,7 +5177,6 @@ static int prepare_update( thread_db* tdbb,
|
||||
|
||||
if (state == tra_precommitted)
|
||||
{
|
||||
Database::Checkout dcoHolder(dbb);
|
||||
THREAD_SLEEP(100); // milliseconds
|
||||
}
|
||||
else {
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "../lock/lock_proto.h"
|
||||
#include "../common/ThreadStart.h"
|
||||
#include "../jrd/jrd.h"
|
||||
#include "../jrd/Attachment.h"
|
||||
#include "gen/iberror.h"
|
||||
#include "../yvalve/gds_proto.h"
|
||||
#include "../common/gdsassert.h"
|
||||
@ -98,7 +99,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef DEV_BUILD
|
||||
#define VALIDATE_LOCK_TABLE
|
||||
//#define VALIDATE_LOCK_TABLE
|
||||
#endif
|
||||
|
||||
#ifdef DEV_BUILD
|
||||
@ -406,7 +407,7 @@ bool LockManager::initializeOwner(Arg::StatusVector& statusVector,
|
||||
}
|
||||
|
||||
|
||||
void LockManager::shutdownOwner(Database* database, SRQ_PTR* owner_offset)
|
||||
void LockManager::shutdownOwner(Attachment* attachment, SRQ_PTR* owner_offset)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -438,7 +439,7 @@ void LockManager::shutdownOwner(Database* database, SRQ_PTR* owner_offset)
|
||||
{
|
||||
m_localMutex.leave();
|
||||
{ // scope
|
||||
Database::Checkout dco(database);
|
||||
Jrd::Attachment::Checkout cout(attachment);
|
||||
THREAD_SLEEP(10);
|
||||
}
|
||||
m_localMutex.enter();
|
||||
@ -456,7 +457,7 @@ void LockManager::shutdownOwner(Database* database, SRQ_PTR* owner_offset)
|
||||
}
|
||||
|
||||
|
||||
SRQ_PTR LockManager::enqueue(Database* database,
|
||||
SRQ_PTR LockManager::enqueue(Attachment* attachment,
|
||||
Arg::StatusVector& statusVector,
|
||||
SRQ_PTR prior_request,
|
||||
SRQ_PTR parent_request,
|
||||
@ -559,7 +560,7 @@ SRQ_PTR LockManager::enqueue(Database* database,
|
||||
|
||||
insert_tail(&lock->lbl_requests, &request->lrq_lbl_requests);
|
||||
request->lrq_data = data;
|
||||
const SRQ_PTR lock_id = grant_or_que(database, request, lock, lck_wait);
|
||||
const SRQ_PTR lock_id = grant_or_que(attachment, request, lock, lck_wait);
|
||||
if (!lock_id)
|
||||
{
|
||||
statusVector << Arg::Gds(lck_wait > 0 ? isc_deadlock :
|
||||
@ -621,7 +622,7 @@ SRQ_PTR LockManager::enqueue(Database* database,
|
||||
}
|
||||
|
||||
|
||||
bool LockManager::convert(Database* database,
|
||||
bool LockManager::convert(Attachment* attachment,
|
||||
Arg::StatusVector& statusVector,
|
||||
SRQ_PTR request_offset,
|
||||
UCHAR type,
|
||||
@ -657,12 +658,12 @@ bool LockManager::convert(Database* database,
|
||||
else
|
||||
++sh_mem_header->lhb_operations[0];
|
||||
|
||||
return internal_convert(database, statusVector, request_offset, type, lck_wait, ast_routine,
|
||||
return internal_convert(attachment, statusVector, request_offset, type, lck_wait, ast_routine,
|
||||
ast_argument);
|
||||
}
|
||||
|
||||
|
||||
UCHAR LockManager::downgrade(Database* database, Arg::StatusVector& statusVector,
|
||||
UCHAR LockManager::downgrade(Attachment* attachment, Arg::StatusVector& statusVector,
|
||||
const SRQ_PTR request_offset)
|
||||
{
|
||||
/**************************************
|
||||
@ -720,7 +721,7 @@ UCHAR LockManager::downgrade(Database* database, Arg::StatusVector& statusVector
|
||||
}
|
||||
else
|
||||
{
|
||||
internal_convert(database, statusVector, request_offset, state, LCK_NO_WAIT,
|
||||
internal_convert(attachment, statusVector, request_offset, state, LCK_NO_WAIT,
|
||||
request->lrq_ast_routine, request->lrq_ast_argument);
|
||||
}
|
||||
|
||||
@ -765,7 +766,7 @@ bool LockManager::dequeue(const SRQ_PTR request_offset)
|
||||
}
|
||||
|
||||
|
||||
void LockManager::repost(Database* database, lock_ast_t ast, void* arg, SRQ_PTR owner_offset)
|
||||
void LockManager::repost(Attachment* attachment, lock_ast_t ast, void* arg, SRQ_PTR owner_offset)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -819,7 +820,7 @@ void LockManager::repost(Database* database, lock_ast_t ast, void* arg, SRQ_PTR
|
||||
|
||||
DEBUG_DELAY;
|
||||
|
||||
signal_owner(database, (own*) SRQ_ABS_PTR(owner_offset), (SRQ_PTR) NULL);
|
||||
signal_owner(attachment, (own*) SRQ_ABS_PTR(owner_offset), (SRQ_PTR) NULL);
|
||||
|
||||
release_shmem(owner_offset);
|
||||
}
|
||||
@ -1392,7 +1393,7 @@ lbl* LockManager::alloc_lock(USHORT length, Arg::StatusVector& statusVector)
|
||||
}
|
||||
|
||||
|
||||
void LockManager::blocking_action(Database* database,
|
||||
void LockManager::blocking_action(Attachment* attachment,
|
||||
SRQ_PTR blocking_owner_offset,
|
||||
SRQ_PTR blocked_owner_offset)
|
||||
{
|
||||
@ -1459,13 +1460,8 @@ void LockManager::blocking_action(Database* database,
|
||||
owner->own_ast_count++;
|
||||
release_shmem(blocked_owner_offset);
|
||||
m_localMutex.leave();
|
||||
if (database)
|
||||
{
|
||||
Database::Checkout dcoHolder(database);
|
||||
(*routine)(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
Jrd::Attachment::Checkout cout(attachment, true);
|
||||
(*routine)(arg);
|
||||
}
|
||||
m_localMutex.enter();
|
||||
@ -1492,7 +1488,7 @@ void LockManager::blocking_action_thread()
|
||||
|
||||
/*
|
||||
* Main thread may be gone releasing our LockManager instance
|
||||
* when AST can't lock appropriate database mutex and therefore does not return.
|
||||
* when AST can't lock appropriate attachment mutex and therefore does not return.
|
||||
*
|
||||
* This causes multiple errors when entering/releasing mutexes/semaphores.
|
||||
* Catch this errors and log them.
|
||||
@ -2235,7 +2231,7 @@ void LockManager::grant(lrq* request, lbl* lock)
|
||||
}
|
||||
|
||||
|
||||
SRQ_PTR LockManager::grant_or_que(Database* database, lrq* request, lbl* lock, SSHORT lck_wait)
|
||||
SRQ_PTR LockManager::grant_or_que(Attachment* attachment, lrq* request, lbl* lock, SSHORT lck_wait)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -2272,7 +2268,7 @@ SRQ_PTR LockManager::grant_or_que(Database* database, lrq* request, lbl* lock, S
|
||||
|
||||
if (lck_wait)
|
||||
{
|
||||
wait_for_request(database, request, lck_wait);
|
||||
wait_for_request(attachment, request, lck_wait);
|
||||
|
||||
// For performance reasons, we're going to look at the
|
||||
// request's status without re-acquiring the lock table.
|
||||
@ -2539,7 +2535,7 @@ void LockManager::insert_tail(SRQ lock_srq, SRQ node)
|
||||
}
|
||||
|
||||
|
||||
bool LockManager::internal_convert(Database* database,
|
||||
bool LockManager::internal_convert(Attachment* attachment,
|
||||
Arg::StatusVector& statusVector,
|
||||
SRQ_PTR request_offset,
|
||||
UCHAR type,
|
||||
@ -2602,7 +2598,7 @@ bool LockManager::internal_convert(Database* database,
|
||||
else
|
||||
new_ast = false;
|
||||
|
||||
if (wait_for_request(database, request, lck_wait))
|
||||
if (wait_for_request(attachment, request, lck_wait))
|
||||
return false;
|
||||
|
||||
request = (lrq*) SRQ_ABS_PTR(request_offset);
|
||||
@ -2693,7 +2689,7 @@ USHORT LockManager::lock_state(const lbl* lock)
|
||||
}
|
||||
|
||||
|
||||
void LockManager::post_blockage(Database* database, lrq* request, lbl* lock)
|
||||
void LockManager::post_blockage(Attachment* attachment, lrq* request, lbl* lock)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -2760,7 +2756,7 @@ void LockManager::post_blockage(Database* database, lrq* request, lbl* lock)
|
||||
while (blocking_owners.getCount())
|
||||
{
|
||||
own* const blocking_owner = (own*) SRQ_ABS_PTR(blocking_owners.pop());
|
||||
if (blocking_owner->own_count && !signal_owner(database, blocking_owner, owner_offset))
|
||||
if (blocking_owner->own_count && !signal_owner(attachment, blocking_owner, owner_offset))
|
||||
{
|
||||
dead_processes.add(blocking_owner->own_process);
|
||||
}
|
||||
@ -3281,7 +3277,7 @@ void LockManager::release_request(lrq* request)
|
||||
}
|
||||
|
||||
|
||||
bool LockManager::signal_owner(Database* database, own* blocking_owner, SRQ_PTR blocked_owner_offset)
|
||||
bool LockManager::signal_owner(Attachment* attachment, own* blocking_owner, SRQ_PTR blocked_owner_offset)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -3323,7 +3319,7 @@ bool LockManager::signal_owner(Database* database, own* blocking_owner, SRQ_PTR
|
||||
if (process->prc_process_id == PID)
|
||||
{
|
||||
DEBUG_DELAY;
|
||||
blocking_action(database, SRQ_REL_PTR(blocking_owner), blocked_owner_offset);
|
||||
blocking_action(attachment, SRQ_REL_PTR(blocking_owner), blocked_owner_offset);
|
||||
DEBUG_DELAY;
|
||||
return true;
|
||||
}
|
||||
@ -3848,7 +3844,7 @@ void LockManager::validate_shb(const SRQ_PTR shb_ptr)
|
||||
}
|
||||
|
||||
|
||||
USHORT LockManager::wait_for_request(Database* database, lrq* request, SSHORT lck_wait)
|
||||
USHORT LockManager::wait_for_request(Attachment* attachment, lrq* request, SSHORT lck_wait)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -3908,7 +3904,7 @@ USHORT LockManager::wait_for_request(Database* database, lrq* request, SSHORT lc
|
||||
// Post blockage. If the blocking owner has disappeared, the blockage
|
||||
// may clear spontaneously.
|
||||
|
||||
post_blockage(database, request, lock);
|
||||
post_blockage(attachment, request, lock);
|
||||
post_history(his_wait, owner_offset, lock_offset, SRQ_REL_PTR(request), true);
|
||||
release_shmem(owner_offset);
|
||||
|
||||
@ -3960,7 +3956,7 @@ USHORT LockManager::wait_for_request(Database* database, lrq* request, SSHORT lc
|
||||
++m_waitingOwners;
|
||||
}
|
||||
{ // scope
|
||||
Database::Checkout dcoHolder(database);
|
||||
Jrd::Attachment::Checkout cout(attachment);
|
||||
ret = ISC_event_wait(&owner->own_wakeup, value, (timeout - current_time) * 1000000);
|
||||
--m_waitingOwners;
|
||||
}
|
||||
@ -4064,7 +4060,7 @@ USHORT LockManager::wait_for_request(Database* database, lrq* request, SSHORT lc
|
||||
// This could happen if the lock was granted to a different request,
|
||||
// we have to tell the new owner of the lock that they are blocking us.
|
||||
|
||||
post_blockage(database, request, lock);
|
||||
post_blockage(attachment, request, lock);
|
||||
release_shmem(owner_offset);
|
||||
continue;
|
||||
}
|
||||
@ -4122,7 +4118,7 @@ USHORT LockManager::wait_for_request(Database* database, lrq* request, SSHORT lc
|
||||
// We need to inform the new owner.
|
||||
|
||||
DEBUG_MSG(0, ("wait_for_request: forcing a resignal of blockers\n"));
|
||||
post_blockage(database, request, lock);
|
||||
post_blockage(attachment, request, lock);
|
||||
#ifdef DEV_BUILD
|
||||
repost_counter++;
|
||||
if (repost_counter % 50 == 0)
|
||||
|
@ -305,7 +305,7 @@ class Config;
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
class Database;
|
||||
class Attachment;
|
||||
|
||||
class LockManager : private Firebird::RefCounted,
|
||||
public Firebird::GlobalStorage,
|
||||
@ -323,15 +323,15 @@ public:
|
||||
static void destroy(LockManager*);
|
||||
|
||||
bool initializeOwner(Firebird::Arg::StatusVector&, LOCK_OWNER_T, UCHAR, SRQ_PTR*);
|
||||
void shutdownOwner(Database*, SRQ_PTR*);
|
||||
void shutdownOwner(Attachment*, SRQ_PTR*);
|
||||
|
||||
SLONG enqueue(Database*, Firebird::Arg::StatusVector&, SRQ_PTR, SRQ_PTR, const USHORT,
|
||||
SLONG enqueue(Attachment*, Firebird::Arg::StatusVector&, SRQ_PTR, SRQ_PTR, const USHORT,
|
||||
const UCHAR*, const USHORT, UCHAR, lock_ast_t, void*, SLONG, SSHORT, SRQ_PTR);
|
||||
bool convert(Database*, Firebird::Arg::StatusVector&, SRQ_PTR, UCHAR, SSHORT, lock_ast_t, void*);
|
||||
UCHAR downgrade(Database*, Firebird::Arg::StatusVector&, const SRQ_PTR);
|
||||
bool convert(Attachment*, Firebird::Arg::StatusVector&, SRQ_PTR, UCHAR, SSHORT, lock_ast_t, void*);
|
||||
UCHAR downgrade(Attachment*, Firebird::Arg::StatusVector&, const SRQ_PTR);
|
||||
bool dequeue(const SRQ_PTR);
|
||||
|
||||
void repost(Database*, lock_ast_t, void*, SRQ_PTR);
|
||||
void repost(Attachment*, lock_ast_t, void*, SRQ_PTR);
|
||||
bool cancelWait(SRQ_PTR);
|
||||
|
||||
SLONG queryData(SRQ_PTR, const USHORT, const USHORT);
|
||||
@ -351,7 +351,7 @@ private:
|
||||
void acquire_shmem(SRQ_PTR);
|
||||
UCHAR* alloc(USHORT, Firebird::Arg::StatusVector*);
|
||||
lbl* alloc_lock(USHORT, Firebird::Arg::StatusVector&);
|
||||
void blocking_action(Database*, SRQ_PTR, SRQ_PTR);
|
||||
void blocking_action(Attachment*, SRQ_PTR, SRQ_PTR);
|
||||
void blocking_action_thread();
|
||||
void bug(Firebird::Arg::StatusVector*, const TEXT*);
|
||||
void bug_assert(const TEXT*, ULONG);
|
||||
@ -364,15 +364,15 @@ private:
|
||||
lbl* find_lock(SRQ_PTR, USHORT, const UCHAR*, USHORT, USHORT*);
|
||||
lrq* get_request(SRQ_PTR);
|
||||
void grant(lrq*, lbl*);
|
||||
SRQ_PTR grant_or_que(Database*, lrq*, lbl*, SSHORT);
|
||||
SRQ_PTR grant_or_que(Attachment*, lrq*, lbl*, SSHORT);
|
||||
void init_owner_block(own*, UCHAR, LOCK_OWNER_T);
|
||||
void insert_data_que(lbl*);
|
||||
void insert_tail(SRQ, SRQ);
|
||||
bool internal_convert(Database* database, Firebird::Arg::StatusVector&, SRQ_PTR, UCHAR, SSHORT,
|
||||
bool internal_convert(Attachment* database, Firebird::Arg::StatusVector&, SRQ_PTR, UCHAR, SSHORT,
|
||||
lock_ast_t, void*);
|
||||
void internal_dequeue(SRQ_PTR);
|
||||
static USHORT lock_state(const lbl*);
|
||||
void post_blockage(Database*, lrq*, lbl*);
|
||||
void post_blockage(Attachment*, lrq*, lbl*);
|
||||
void post_history(USHORT, SRQ_PTR, SRQ_PTR, SRQ_PTR, bool);
|
||||
void post_pending(lbl*);
|
||||
void post_wakeup(own*);
|
||||
@ -384,7 +384,7 @@ private:
|
||||
void release_shmem(SRQ_PTR);
|
||||
void release_mutex();
|
||||
void release_request(lrq*);
|
||||
bool signal_owner(Database*, own*, SRQ_PTR);
|
||||
bool signal_owner(Attachment*, own*, SRQ_PTR);
|
||||
|
||||
void validate_history(const SRQ_PTR history_header);
|
||||
void validate_parent(const lhb*, const SRQ_PTR);
|
||||
@ -394,7 +394,7 @@ private:
|
||||
void validate_request(const SRQ_PTR, USHORT, USHORT);
|
||||
void validate_shb(const SRQ_PTR);
|
||||
|
||||
USHORT wait_for_request(Database*, lrq*, SSHORT);
|
||||
USHORT wait_for_request(Attachment*, lrq*, SSHORT);
|
||||
bool attach_shared_file(Firebird::Arg::StatusVector&);
|
||||
void detach_shared_file(Firebird::Arg::StatusVector&);
|
||||
void get_shared_file_name(Firebird::PathName&, ULONG extend = 0) const;
|
||||
|
@ -84,31 +84,28 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "fb_exception.h"
|
||||
#include "../remote/remote.h"
|
||||
#include "gen/iberror.h"
|
||||
#include "../jrd/license.h"
|
||||
#include "../common/ThreadStart.h"
|
||||
#include "../utilities/install/install_nt.h"
|
||||
#include "../../remote/server/os/win32/cntl_proto.h"
|
||||
#include "../remote/inet_proto.h"
|
||||
#include "../remote/server/serve_proto.h"
|
||||
#include "../../remote/server/os/win32/window_proto.h"
|
||||
#include "../../remote/os/win32/wnet_proto.h"
|
||||
#include "../../remote/server/os/win32/window.rh"
|
||||
#include "../../remote/os/win32/xnet_proto.h"
|
||||
#include "../yvalve/gds_proto.h"
|
||||
#include "../common/os/fbsyslog.h"
|
||||
#include "../common/isc_proto.h"
|
||||
#include "../jrd/jrd_proto.h"
|
||||
#include "../common/os/isc_i_proto.h"
|
||||
#include "../common/isc_s_proto.h"
|
||||
#include "../common/file_params.h"
|
||||
#include "../jrd/thread_proto.h"
|
||||
#include "../common/config/config.h"
|
||||
#include "../common/utils_proto.h"
|
||||
#include "../../../../common/classes/semaphore.h"
|
||||
#include "../../../../common/classes/FpeControl.h"
|
||||
#include "../jrd/ibase.h"
|
||||
#include "../common/classes/semaphore.h"
|
||||
#include "../common/classes/FpeControl.h"
|
||||
#include "../jrd/license.h"
|
||||
#include "../utilities/install/install_nt.h"
|
||||
#include "../remote/remote.h"
|
||||
#include "../remote/server/os/win32/cntl_proto.h"
|
||||
#include "../remote/inet_proto.h"
|
||||
#include "../remote/server/serve_proto.h"
|
||||
#include "../remote/server/os/win32/window_proto.h"
|
||||
#include "../remote/os/win32/wnet_proto.h"
|
||||
#include "../remote/server/os/win32/window.rh"
|
||||
#include "../remote/os/win32/xnet_proto.h"
|
||||
#include "../yvalve/gds_proto.h"
|
||||
|
||||
#include "FirebirdPluginApi.h"
|
||||
#include "../common/classes/ImplementHelper.h"
|
||||
@ -133,6 +130,8 @@ static TEXT instance[MAXPATHLEN];
|
||||
static USHORT server_flag;
|
||||
static bool server_shutdown = false;
|
||||
|
||||
using namespace Firebird;
|
||||
|
||||
class ThreadCounter
|
||||
{
|
||||
public:
|
||||
@ -159,12 +158,12 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static Firebird::AtomicCounter m_count;
|
||||
static Firebird::Semaphore m_semaphore;
|
||||
static AtomicCounter m_count;
|
||||
static Semaphore m_semaphore;
|
||||
};
|
||||
|
||||
Firebird::AtomicCounter ThreadCounter::m_count;
|
||||
Firebird::Semaphore ThreadCounter::m_semaphore;
|
||||
AtomicCounter ThreadCounter::m_count;
|
||||
Semaphore ThreadCounter::m_semaphore;
|
||||
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE /*hPrevInst*/, LPSTR lpszArgs, int nWndMode)
|
||||
@ -188,13 +187,13 @@ int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE /*hPrevInst*/, LPSTR lpszArgs,
|
||||
if (!Config::getBugcheckAbort())
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
|
||||
}
|
||||
catch (Firebird::fatal_exception& e)
|
||||
catch (fatal_exception& e)
|
||||
{
|
||||
MessageBox(NULL, e.what(), "Firebird server failure",
|
||||
MB_OK | MB_ICONHAND | MB_SYSTEMMODAL | MB_DEFAULT_DESKTOP_ONLY);
|
||||
return STARTUP_ERROR; // see /common/common.h
|
||||
}
|
||||
catch (Firebird::status_exception& e)
|
||||
catch (status_exception& e)
|
||||
{
|
||||
TEXT buffer[BUFFER_LARGE];
|
||||
const ISC_STATUS* vector = e.value();
|
||||
@ -208,9 +207,22 @@ int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE /*hPrevInst*/, LPSTR lpszArgs,
|
||||
return STARTUP_ERROR; // see /common/common.h
|
||||
}
|
||||
|
||||
server_flag = Config::getMultiClientServer() ? SRVR_multi_client : 0;
|
||||
// Check for errors/missing firebird.conf
|
||||
const char* anyError = Config::getMessage();
|
||||
if (anyError)
|
||||
{
|
||||
Syslog::Record(Syslog::Error, anyError);
|
||||
MessageBox(NULL, anyError, "Firebird server failure",
|
||||
MB_OK | MB_ICONHAND | MB_SYSTEMMODAL | MB_DEFAULT_DESKTOP_ONLY);
|
||||
return STARTUP_ERROR;
|
||||
}
|
||||
|
||||
SetProcessAffinityMask(GetCurrentProcess(), static_cast<DWORD>(Config::getCpuAffinityMask()));
|
||||
server_flag = 0;
|
||||
|
||||
const DWORD affinity = static_cast<DWORD>(Config::getCpuAffinityMask());
|
||||
if (affinity) {
|
||||
SetProcessAffinityMask(GetCurrentProcess(), affinity);
|
||||
}
|
||||
|
||||
protocol_inet[0] = 0;
|
||||
protocol_wnet[0] = 0;
|
||||
@ -243,14 +255,14 @@ int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE /*hPrevInst*/, LPSTR lpszArgs,
|
||||
// Initialize the service
|
||||
|
||||
ISC_signal_init();
|
||||
Firebird::FpeControl::maskAll();
|
||||
FpeControl::maskAll();
|
||||
|
||||
int nReturnValue = 0;
|
||||
ISC_STATUS_ARRAY status_vector;
|
||||
fb_utils::init_status(status_vector);
|
||||
|
||||
{ // scope for interface ptr
|
||||
Firebird::PluginManagerInterfacePtr pi;
|
||||
PluginManagerInterfacePtr pi;
|
||||
Auth::registerLegacyServer(pi);
|
||||
#ifdef TRUSTED_AUTH
|
||||
Auth::registerTrustedServer(pi);
|
||||
@ -283,7 +295,7 @@ int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE /*hPrevInst*/, LPSTR lpszArgs,
|
||||
if (port)
|
||||
service_connection(port);
|
||||
}
|
||||
catch (const Firebird::Exception& ex)
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
iscLogException("Server error", ex);
|
||||
}
|
||||
@ -292,7 +304,7 @@ int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE /*hPrevInst*/, LPSTR lpszArgs,
|
||||
}
|
||||
else if (!(server_flag & SRVR_non_service))
|
||||
{
|
||||
Firebird::string service_name;
|
||||
string service_name;
|
||||
service_name.printf(REMOTE_SERVICE, instance);
|
||||
|
||||
CNTL_init(start_connections_thread, instance);
|
||||
@ -329,7 +341,7 @@ int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE /*hPrevInst*/, LPSTR lpszArgs,
|
||||
// due to remote access
|
||||
|
||||
//gds_alloc_report(0, __FILE__, __LINE__);
|
||||
Firebird::PathName name = fb_utils::getPrefix(fb_utils::FB_DIR_LOG, "memdebug.log");
|
||||
PathName name = fb_utils::getPrefix(fb_utils::FB_DIR_LOG, "memdebug.log");
|
||||
FILE* file = fopen(name.c_str(), "w+t");
|
||||
if (file)
|
||||
{
|
||||
@ -381,7 +393,7 @@ static THREAD_ENTRY_DECLARE inet_connect_wait_thread(THREAD_ENTRY_PARAM)
|
||||
{
|
||||
port = INET_connect(protocol_inet, NULL, server_flag, 0);
|
||||
}
|
||||
catch (const Firebird::Exception& ex)
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
iscLogException("INET_connect", ex);
|
||||
}
|
||||
@ -399,7 +411,7 @@ static THREAD_ENTRY_DECLARE inet_connect_wait_thread(THREAD_ENTRY_PARAM)
|
||||
{
|
||||
Thread::start(process_connection_thread, port, THREAD_medium);
|
||||
}
|
||||
catch (const Firebird::Exception& )
|
||||
catch (const Exception& )
|
||||
{
|
||||
gds__log("INET: can't start worker thread, connection terminated");
|
||||
port->disconnect(NULL, NULL);
|
||||
@ -431,7 +443,7 @@ static THREAD_ENTRY_DECLARE wnet_connect_wait_thread(THREAD_ENTRY_PARAM)
|
||||
{
|
||||
port = WNET_connect(protocol_wnet, NULL, server_flag);
|
||||
}
|
||||
catch (const Firebird::Exception& ex)
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
ISC_STATUS_ARRAY status_vector;
|
||||
ex.stuff_exception(status_vector);
|
||||
@ -448,7 +460,7 @@ static THREAD_ENTRY_DECLARE wnet_connect_wait_thread(THREAD_ENTRY_PARAM)
|
||||
{
|
||||
Thread::start(process_connection_thread, port, THREAD_medium);
|
||||
}
|
||||
catch (const Firebird::Exception&)
|
||||
catch (const Exception&)
|
||||
{
|
||||
gds__log("WNET: can't start worker thread, connection terminated");
|
||||
port->disconnect(NULL, NULL);
|
||||
@ -482,7 +494,7 @@ static THREAD_ENTRY_DECLARE xnet_connect_wait_thread(THREAD_ENTRY_PARAM)
|
||||
{
|
||||
port = XNET_connect(NULL, server_flag);
|
||||
}
|
||||
catch (const Firebird::Exception& ex)
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
ISC_STATUS_ARRAY status_vector;
|
||||
|
||||
@ -500,7 +512,7 @@ static THREAD_ENTRY_DECLARE xnet_connect_wait_thread(THREAD_ENTRY_PARAM)
|
||||
{
|
||||
Thread::start(process_connection_thread, port, THREAD_medium);
|
||||
}
|
||||
catch (const Firebird::Exception&)
|
||||
catch (const Exception&)
|
||||
{
|
||||
gds__log("XNET: can't start worker thread, connection terminated");
|
||||
port->disconnect(NULL, NULL);
|
||||
@ -545,7 +557,7 @@ static THREAD_ENTRY_DECLARE start_connections_thread(THREAD_ENTRY_PARAM)
|
||||
try {
|
||||
Thread::start(inet_connect_wait_thread, 0, THREAD_medium);
|
||||
}
|
||||
catch (const Firebird::Exception& ex) {
|
||||
catch (const Exception& ex) {
|
||||
iscLogException("INET: can't start listener thread", ex);
|
||||
}
|
||||
}
|
||||
@ -554,7 +566,7 @@ static THREAD_ENTRY_DECLARE start_connections_thread(THREAD_ENTRY_PARAM)
|
||||
try {
|
||||
Thread::start(wnet_connect_wait_thread, 0, THREAD_medium);
|
||||
}
|
||||
catch (const Firebird::Exception& ex) {
|
||||
catch (const Exception& ex) {
|
||||
iscLogException("WNET: can't start listener thread", ex);
|
||||
}
|
||||
}
|
||||
@ -563,7 +575,7 @@ static THREAD_ENTRY_DECLARE start_connections_thread(THREAD_ENTRY_PARAM)
|
||||
try {
|
||||
Thread::start(xnet_connect_wait_thread, 0, THREAD_medium);
|
||||
}
|
||||
catch (const Firebird::Exception& ex) {
|
||||
catch (const Exception& ex) {
|
||||
iscLogException("XNET: can't start listener thread", ex);
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,6 @@
|
||||
#include "../remote/remote.h"
|
||||
#include "../common/ThreadStart.h"
|
||||
#include "../jrd/license.h"
|
||||
#include "../common/file_params.h"
|
||||
#include "../common/classes/timestamp.h"
|
||||
#include "../remote/merge_proto.h"
|
||||
#include "../remote/parse_proto.h"
|
||||
@ -51,9 +50,7 @@
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "../yvalve/gds_proto.h"
|
||||
#include "../common/isc_proto.h"
|
||||
#include "../common/isc_s_proto.h"
|
||||
#include "../jrd/thread_proto.h"
|
||||
#include "../yvalve/why_proto.h"
|
||||
#include "../jrd/constants.h"
|
||||
@ -70,7 +67,6 @@
|
||||
#include "../common/classes/DbImplementation.h"
|
||||
#include "../common/Auth.h"
|
||||
#include "../common/classes/GetPlugins.h"
|
||||
#include "../common/os/fbsyslog.h"
|
||||
#include "../common/db_alias.h"
|
||||
|
||||
using namespace Firebird;
|
||||
@ -866,14 +862,6 @@ void SRVR_multi_thread( rem_port* main_port, USHORT flags)
|
||||
* Multi-threaded flavor of server.
|
||||
*
|
||||
**************************************/
|
||||
// Check for errors/missing firebird.conf
|
||||
const char* anyError = Config::getMessage();
|
||||
if (anyError)
|
||||
{
|
||||
Syslog::Record(Syslog::Error, anyError);
|
||||
return;
|
||||
}
|
||||
|
||||
server_req_t* request = NULL;
|
||||
RemPortPtr port; // Was volatile PORT port = NULL;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user