8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-27 05:23:02 +01:00
firebird-mirror/src/jrd/Database.h
dimitr 0a9e8c8382 Implemented CORE-1751. The changes include:
1) Make memory counters aggregated.
2) Add attachment pool and allocate appropriate resources out of this pool.
3) Always release attachments explicitly (via destructor).
4) Always delete user requests prior to attachment deletion.
5) Introduce memory usage counters per every monitoring object.
6) Misc refactoring.
Some pieces are still incomplete (although everything basically works), but I'd like to get feedback and testing sooner rather than later.
2008-05-06 08:46:39 +00:00

545 lines
15 KiB
C++

/*
* PROGRAM: JRD access method
* MODULE: Database.h
* DESCRIPTION: Common descriptions
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
* 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "DecOSF" port
*
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
* Claudio Valderrama C.
*
*/
#ifndef JRD_DATABASE_H
#define JRD_DATABASE_H
#include "firebird.h"
#include "../jrd/cch.h"
#include "../jrd/que.h"
#include "../jrd/gdsassert.h"
#include "../jrd/common.h"
#include "../jrd/dsc.h"
#include "../jrd/all.h"
#include "../jrd/btn.h"
#include "../jrd/all.h"
#include "../jrd/jrd_proto.h"
#include "../jrd/val.h"
#include "../jrd/irq.h"
#include "../jrd/drq.h"
#include "../include/gen/iberror.h"
#include "../common/classes/fb_atomic.h"
#include "../common/classes/fb_string.h"
#include "../common/classes/MetaName.h"
#include "../common/classes/array.h"
#include "../common/classes/objects_array.h"
#include "../common/classes/stack.h"
#include "../common/classes/timestamp.h"
#include "../common/classes/GenericMap.h"
#include "../common/classes/RefCounted.h"
#include "../common/classes/PublicHandle.h"
#include "../jrd/RandomGenerator.h"
#include "../jrd/os/guid.h"
#include "../jrd/sbm.h"
#include "../jrd/flu.h"
#include "../jrd/RuntimeStatistics.h"
class CharSetContainer;
namespace Jrd
{
class Trigger;
template <typename T> class vec;
class jrd_prc;
class jrd_rel;
class Shadow;
class BlobFilter;
class TxPageCache;
class BackupManager;
class vcl;
typedef Firebird::ObjectsArray<Trigger> trig_vec;
class Database : public pool_alloc<type_dbb>, public Firebird::PublicHandle
{
class Sync : public Firebird::RefCounted
{
public:
Sync()
: threadId(0), isAst(false), astInhibits(0)
{}
void lock(bool ast = false)
{
const FB_THREAD_ID currentId = getThreadId();
stateMutex.enter();
if (threadId != currentId)
{
stateMutex.leave();
++waiters;
syncMutex.enter();
while (ast && astInhibits)
{
syncMutex.leave();
THREAD_SLEEP(1);
syncMutex.enter();
}
--waiters;
stateMutex.enter();
threadId = currentId;
isAst = ast;
}
stateMutex.leave();
}
void unlock(bool checkout = false)
{
Firebird::MutexLockGuard guard(stateMutex);
fb_assert(threadId == getThreadId());
if (!(isAst && checkout))
{
threadId = 0;
syncMutex.leave();
}
}
bool hasContention() const
{
return (waiters.value() > 0);
}
void disableAsts()
{
++astInhibits;
}
void enableAsts()
{
--astInhibits;
}
private:
~Sync()
{
if (threadId)
{
syncMutex.leave();
threadId = 0;
}
}
// copying is prohibited
Sync(const Sync&);
Sync& operator=(const Sync&);
Firebird::Mutex syncMutex;
Firebird::Mutex stateMutex;
Firebird::AtomicCounter waiters;
FB_THREAD_ID threadId;
bool isAst;
int astInhibits;
};
public:
class AstInhibit
{
public:
explicit AstInhibit(Database* dbb)
: sync(*dbb->dbb_sync)
{
sync.disableAsts();
}
~AstInhibit()
{
sync.enableAsts();
}
Sync& sync;
};
class SyncGuard
{
public:
explicit SyncGuard(Database* dbb, bool ast = false)
: sync(*dbb->dbb_sync)
{
if (!dbb->checkHandle())
{
Firebird::status_exception::raise(isc_bad_db_handle, 0);
}
sync.addRef();
sync.lock(ast);
if (!dbb->checkHandle())
{
sync.unlock();
sync.release();
Firebird::status_exception::raise(isc_bad_db_handle, 0);
}
}
~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, bool io_flag = false)
: sync(*dbb->dbb_sync), io(io_flag)
{
#ifndef SUPERSERVER
if (!io)
#endif
sync.unlock(true);
}
~Checkout()
{
#ifndef SUPERSERVER
if (!io)
#endif
sync.lock();
}
private:
// copying is prohibited
Checkout(const Checkout&);
Checkout& operator=(const Checkout&);
Sync& sync;
const bool io;
};
class CheckoutLockGuard
{
public:
CheckoutLockGuard(Database* dbb, Firebird::Mutex& m)
: mutex(m)
{
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;
};
typedef int (*crypt_routine) (const char*, void*, int, void*);
static Database* create()
{
Firebird::MemoryStats temp_stats;
MemoryPool* const pool = MemoryPool::createPool(NULL, temp_stats);
Database* const dbb = FB_NEW(*pool) Database(pool);
pool->setStatsGroup(dbb->dbb_memory_stats);
return dbb;
}
// The destroy() function MUST be used to delete a Database object.
// The function hides some tricky order of operations. Since the
// memory for the vectors in the Database is allocated out of the Database's
// permanent memory pool, the entire delete() operation needs
// to complete _before_ the permanent pool is deleted, or else
// risk an aborted engine.
static void destroy(Database* const toDelete)
{
if (!toDelete)
return;
MemoryPool* const perm = toDelete->dbb_permanent;
// Memory pool destruction below decrements memory statistics
// situated in database block we are about to deallocate right now
Firebird::MemoryStats temp_stats;
perm->setStatsGroup(temp_stats);
delete toDelete;
MemoryPool::deletePool(perm);
}
static ULONG getLockOwnerId()
{
static Firebird::AtomicCounter counter;
return ++counter;
}
bool checkHandle() const
{
if (!isKnownHandle())
{
return false;
}
return TypedHandle<type_dbb>::checkHandle();
}
mutable Sync* dbb_sync; // Database sync primitive
Firebird::Reference dbb_sync_ref; // Database reference to dbb_sync
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
FB_GUID dbb_guid; // dbb instance identifier
Lock* dbb_instance_lock; // dbb instance lock
Lock* dbb_lock; // granddaddy lock
jrd_tra* dbb_sys_trans; // system transaction
// jrd_file* dbb_file; // files for I/O operations
Shadow* dbb_shadow; // shadow control block
Lock* dbb_shadow_lock; // lock for synchronizing addition of shadows
//SLONG dbb_shadow_sync_count; // to synchronize changes to 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];
DatabaseModules dbb_modules; // external function/filter modules
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;
//SLONG dbb_sort_size; // Size of sort space per sort, unused for now
UATOM dbb_ast_flags; // flags modified at AST level
ULONG dbb_flags;
USHORT dbb_ods_version; // major ODS version number
USHORT dbb_minor_version; // minor ODS version number
USHORT dbb_minor_original; // minor ODS version at creation
USHORT dbb_page_size; // page size
USHORT dbb_dp_per_pp; // data pages per pointer page
USHORT dbb_max_records; // max record per data page
USHORT dbb_max_idx; // max number of indexes on a root page
USHORT dbb_use_count; // active count of threads
USHORT dbb_shutdown_delay; // seconds until forced shutdown.
// Set in shut.cpp but not tested yet.
#ifdef SUPERSERVER_V2
USHORT dbb_prefetch_sequence; // sequence to pace frequency of prefetch requests
USHORT dbb_prefetch_pages; // prefetch pages per request
#endif
Firebird::PathName dbb_filename; // filename string
Firebird::PathName dbb_database_name; // database ID (file name or alias)
Firebird::string dbb_encrypt_key; // encryption key
MemoryPool* dbb_permanent;
MemoryPool* dbb_bufferpool;
Firebird::Array<MemoryPool*> dbb_pools; // pools
Firebird::Array<jrd_req*> dbb_internal; // internal requests
Firebird::Array<jrd_req*> dbb_dyn_req; // internal dyn requests
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
event_t dbb_writer_event[1]; // Event to wake up cache writer
event_t dbb_writer_event_init[1]; // Event for initialization cache writer
event_t dbb_writer_event_fini[1]; // Event for finalization cache writer
#ifdef SUPERSERVER_V2
event_t dbb_reader_event[1]; // Event to wake up cache reader
#endif
#ifdef GARBAGE_THREAD
event_t dbb_gc_event[1]; // Event to wake up garbage collector
event_t dbb_gc_event_init[1]; // Event for initialization garbage collector
event_t dbb_gc_event_fini[1]; // Event for finalization garbage collector
#endif
Firebird::MemoryStats dbb_memory_stats;
SLONG dbb_reads;
SLONG dbb_writes;
SLONG dbb_fetches;
SLONG dbb_marks;
RuntimeStatistics dbb_stats;
SLONG dbb_last_header_write; // Transaction id of last header page physical write
SLONG dbb_flush_cycle; // Current flush cycle
SLONG dbb_sweep_interval; // Transactions between sweep
const ULONG dbb_lock_owner_id; // ID for the lock manager
SLONG dbb_lock_owner_handle; // Handle for the lock manager
USHORT unflushed_writes; // unflushed writes
time_t last_flushed_write; // last flushed write time
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
vcl* dbb_pc_transactions; // active precommitted transactions
BackupManager* dbb_backup_manager; // physical backup manager
Firebird::TimeStamp dbb_creation_date; // creation date
Firebird::GenericMap<Firebird::Pair<Firebird::Left<
Firebird::MetaName, UserFunction*> > > dbb_functions; // User defined functions
// returns true if primary file is located on raw device
bool onRawDevice() const;
MemoryPool* createPool()
{
MemoryPool* const pool = MemoryPool::createPool(dbb_permanent, dbb_memory_stats);
dbb_pools.add(pool);
return pool;
}
void deletePool(MemoryPool* pool);
private:
explicit Database(MemoryPool* p)
: dbb_sync(FB_NEW(*getDefaultMemoryPool()) Sync),
dbb_sync_ref(*dbb_sync),
dbb_page_manager(*p),
dbb_modules(*p),
dbb_filename(*p),
dbb_database_name(*p),
dbb_encrypt_key(*p),
dbb_permanent(p),
dbb_pools(*p, 4),
dbb_internal(*p),
dbb_dyn_req(*p),
dbb_lock_owner_id(getLockOwnerId()),
dbb_charsets(*p),
dbb_creation_date(Firebird::TimeStamp::getCurrentTimeStamp()),
dbb_functions(*p)
{
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 destroyIntlObjects(); // defined in intl.cpp
private:
// The delete operators are no-oped because the Database memory is allocated from the
// Database's own permanent pool. That pool has already been released by the Database
// destructor, so the memory has already been released. Hence the operator
// delete no-op.
void operator delete(void *mem) {}
void operator delete[](void *mem) {}
Database(const Database&); // no impl.
const Database& operator =(const Database&) { return *this; }
};
//
// bit values for dbb_flags
//
const ULONG DBB_damaged = 0x1L;
const ULONG DBB_exclusive = 0x2L; // Database is accessed in exclusive mode
const ULONG DBB_bugcheck = 0x4L; // Bugcheck has occurred
#ifdef GARBAGE_THREAD
const ULONG DBB_garbage_collector = 0x8L; // garbage collector thread exists
const ULONG DBB_gc_active = 0x10L; // ... and is actively working.
const ULONG DBB_gc_pending = 0x20L; // garbage collection requested
#endif
const ULONG DBB_force_write = 0x40L; // Database is forced write
const ULONG DBB_no_reserve = 0x80L; // No reserve space for versions
const ULONG DBB_DB_SQL_dialect_3 = 0x100L; // database SQL dialect 3
const ULONG DBB_read_only = 0x200L; // DB is ReadOnly (RO). If not set, DB is RW
const ULONG DBB_being_opened_read_only = 0x400L; // DB is being opened RO. If unset, opened as RW
const ULONG DBB_not_in_use = 0x800L; // Database to be ignored while attaching
const ULONG DBB_lck_init_done = 0x1000L; // LCK_init() called for the database
const ULONG DBB_sweep_in_progress = 0x2000L; // A database sweep operation is in progress
const ULONG DBB_security_db = 0x4000L; // ISC security database
const ULONG DBB_suspend_bgio = 0x8000L; // Suspend I/O by background threads
const ULONG DBB_being_opened = 0x10000L; // database is being attached to
const ULONG DBB_gc_cooperative = 0x20000L; // cooperative garbage collection
const ULONG DBB_gc_background = 0x40000L; // background garbage collection by gc_thread
const ULONG DBB_no_fs_cache = 0x80000L; // Not using file system cache
//
// dbb_ast_flags
//
const UATOM DBB_blocking = 0x1L; // Exclusive mode is blocking
const UATOM DBB_get_shadows = 0x2L; // Signal received to check for new shadows
const UATOM DBB_assert_locks = 0x4L; // Locks are to be asserted
const UATOM DBB_shutdown = 0x8L; // Database is shutdown
const UATOM DBB_shut_attach = 0x10L; // no new attachments accepted
const UATOM DBB_shut_tran = 0x20L; // no new transactions accepted
const UATOM DBB_shut_force = 0x40L; // forced shutdown in progress
const UATOM DBB_shutdown_locks = 0x80L; // Database locks release by shutdown
const UATOM DBB_shutdown_full = 0x100L; // Database fully shut down
const UATOM DBB_shutdown_single = 0x200L; // Database is in single-user maintenance mode
const UATOM DBB_monitor_off = 0x400L; // Database has the monitoring lock released
} // namespace Jrd
#endif // JRD_DATABASE_H