mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-31 10:43:02 +01:00
0a9e8c8382
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.
420 lines
13 KiB
C++
420 lines
13 KiB
C++
/*
|
|
* PROGRAM: JRD Access Method
|
|
* MODULE: tra.h
|
|
* DESCRIPTION: Transaction block definitions
|
|
*
|
|
* 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): ______________________________________.
|
|
* 2001.6.25 Claudio Valderrama: add dfw_delete_generator and dfw_delete_udf
|
|
* to the dfw_t enumeration.
|
|
* 2002.10.29 Nickolay Samofatov: Added support for savepoints
|
|
*/
|
|
|
|
#ifndef JRD_TRA_H
|
|
#define JRD_TRA_H
|
|
|
|
/*
|
|
* TMN: Fix this header! It should include any header it needs
|
|
* to define the types this header uses.
|
|
*/
|
|
|
|
#include "../include/fb_blk.h"
|
|
#include "../common/classes/tree.h"
|
|
#include "../common/classes/GenericMap.h"
|
|
#include "../jrd/exe.h"
|
|
#include "../jrd/rpb_chain.h"
|
|
#include "../jrd/blb.h" // For bid structure
|
|
#include "../jrd/sbm.h" // For bid structure
|
|
|
|
#include "../jrd/DatabaseSnapshot.h"
|
|
#include "../jrd/TempSpace.h"
|
|
|
|
namespace EDS {
|
|
class Transaction;
|
|
}
|
|
|
|
namespace Jrd {
|
|
|
|
class blb;
|
|
class Lock;
|
|
class jrd_rel;
|
|
template <typename T> class vec;
|
|
class Savepoint;
|
|
class Record;
|
|
class VerbAction;
|
|
class ArrayField;
|
|
class Attachment;
|
|
class DeferredWork;
|
|
class dsql_opn;
|
|
|
|
// Blobs active in transaction identified by bli_temp_id. Please keep this
|
|
// structure small as there can be huge amount of them floating in memory.
|
|
struct BlobIndex
|
|
{
|
|
ULONG bli_temp_id;
|
|
bool bli_materialized;
|
|
jrd_req* bli_request;
|
|
union
|
|
{
|
|
bid bli_blob_id; // ID of materialized blob
|
|
blb* bli_blob_object; // Blob object
|
|
};
|
|
static const ULONG& generate(const void *sender, const BlobIndex& item)
|
|
{
|
|
return item.bli_temp_id;
|
|
}
|
|
// Empty default constructor to make it behave like POD structure
|
|
BlobIndex() {}
|
|
BlobIndex(ULONG temp_id, blb* blob_object) :
|
|
bli_temp_id(temp_id), bli_materialized(false), bli_request(NULL),
|
|
bli_blob_object(blob_object)
|
|
{ }
|
|
};
|
|
|
|
typedef Firebird::BePlusTree<BlobIndex, ULONG, MemoryPool, BlobIndex> BlobIndexTree;
|
|
|
|
/* Transaction block */
|
|
|
|
const int DEFAULT_LOCK_TIMEOUT = -1; // infinite
|
|
const char* const TRA_TEMP_SPACE = "fb_trans_";
|
|
|
|
class jrd_tra : public pool_alloc<type_tra>
|
|
{
|
|
public:
|
|
enum wait_t {
|
|
tra_no_wait,
|
|
tra_probe,
|
|
tra_wait
|
|
};
|
|
|
|
jrd_tra(MemoryPool* p, Firebird::MemoryStats* parent_stats,
|
|
Attachment* attachment, jrd_tra* outer, size_t length = 0)
|
|
: tra_pool(p),
|
|
tra_memory_stats(parent_stats),
|
|
tra_attachment(attachment),
|
|
tra_blobs_tree(p),
|
|
tra_blobs(&tra_blobs_tree),
|
|
tra_resources(*p),
|
|
tra_context_vars(*p),
|
|
tra_lock_timeout(DEFAULT_LOCK_TIMEOUT),
|
|
tra_timestamp(Firebird::TimeStamp::getCurrentTimeStamp()),
|
|
tra_open_cursors(*p),
|
|
tra_outer(outer),
|
|
tra_transactions(*p)
|
|
{
|
|
if (outer)
|
|
{
|
|
fb_assert(p == outer->tra_pool);
|
|
tra_arrays = outer->tra_arrays;
|
|
tra_blobs = outer->tra_blobs;
|
|
}
|
|
|
|
tra_transactions.resize(length);
|
|
}
|
|
|
|
~jrd_tra()
|
|
{
|
|
if (!tra_outer)
|
|
{
|
|
delete tra_temp_space;
|
|
}
|
|
}
|
|
|
|
static jrd_tra* create(MemoryPool* pool, Attachment* attachment, jrd_tra* outer, size_t length = 0)
|
|
{
|
|
jrd_tra* const transaction =
|
|
FB_NEW(*pool) jrd_tra(pool, &attachment->att_memory_stats, attachment, outer, length);
|
|
|
|
if (!outer)
|
|
{
|
|
pool->setStatsGroup(transaction->tra_memory_stats);
|
|
}
|
|
|
|
return transaction;
|
|
}
|
|
|
|
static void destroy(Database* const dbb, jrd_tra* const transaction)
|
|
{
|
|
if (transaction)
|
|
{
|
|
if (transaction->tra_outer)
|
|
{
|
|
delete transaction;
|
|
}
|
|
else
|
|
{
|
|
MemoryPool* const pool = transaction->tra_pool;
|
|
Firebird::MemoryStats temp_stats;
|
|
pool->setStatsGroup(temp_stats);
|
|
delete transaction;
|
|
dbb->deletePool(pool);
|
|
}
|
|
}
|
|
}
|
|
|
|
Attachment* tra_attachment; /* database attachment */
|
|
SLONG tra_number; /* transaction number */
|
|
SLONG tra_top; /* highest transaction in snapshot */
|
|
SLONG tra_oldest; /* oldest interesting transaction */
|
|
SLONG tra_oldest_active; /* record versions older than this can be
|
|
gargage-collected by this tx */
|
|
jrd_tra* tra_next; /* next transaction in database */
|
|
jrd_tra* tra_sibling; /* next transaction in group */
|
|
MemoryPool* const tra_pool; /* pool for transaction */
|
|
Firebird::MemoryStats tra_memory_stats;
|
|
BlobIndexTree tra_blobs_tree; // list of active blobs
|
|
BlobIndexTree* tra_blobs; // pointer to actual list of active blobs
|
|
ArrayField* tra_arrays; /* Linked list of active arrays */
|
|
Lock* tra_lock; /* lock for transaction */
|
|
Lock* tra_cancel_lock; /* lock to cancel the active request */
|
|
vec<Lock*>* tra_relation_locks; /* locks for relations */
|
|
UInt32Bitmap* tra_commit_sub_trans; /* commited sub-transactions */
|
|
Savepoint* tra_save_point; /* list of savepoints */
|
|
Savepoint* tra_save_free; /* free savepoints */
|
|
SLONG tra_save_point_number; /* next save point number to use */
|
|
ULONG tra_flags;
|
|
DeferredWork* tra_deferred_work; /* work deferred to commit time */
|
|
ResourceList tra_resources; /* resource existence list */
|
|
Firebird::StringMap tra_context_vars; // Context variables for the transaction
|
|
traRpbList* tra_rpblist; /* active record_param's of given transaction */
|
|
UCHAR tra_use_count; /* use count for safe AST delivery */
|
|
UCHAR tra_callback_count; /* callback count for 'execute statement' */
|
|
SSHORT tra_lock_timeout; /* in seconds, -1 means infinite, 0 means NOWAIT */
|
|
ULONG tra_next_blob_id; // ID of the previous blob or array created in this transaction
|
|
const Firebird::TimeStamp tra_timestamp; // transaction start time
|
|
jrd_req* tra_requests; // Doubly linked list of requests active in this transaction
|
|
DatabaseSnapshot* tra_db_snapshot; // Database state snapshot (for monitoring purposes)
|
|
RuntimeStatistics tra_stats;
|
|
Firebird::Array<dsql_req*> tra_open_cursors;
|
|
jrd_tra* const tra_outer; // outer transaction of an autonomous transaction
|
|
Firebird::Array<UCHAR> tra_transactions;
|
|
|
|
EDS::Transaction *tra_ext_common;
|
|
//Transaction *tra_ext_two_phase;
|
|
|
|
private:
|
|
TempSpace* tra_temp_space; // temp space storage
|
|
|
|
public:
|
|
SSHORT getLockWait() const
|
|
{
|
|
return -tra_lock_timeout;
|
|
}
|
|
|
|
TempSpace* getTempSpace()
|
|
{
|
|
if (tra_outer)
|
|
return tra_outer->getTempSpace();
|
|
|
|
if (!tra_temp_space)
|
|
tra_temp_space = FB_NEW(*tra_pool) TempSpace(*tra_pool, TRA_TEMP_SPACE);
|
|
|
|
return tra_temp_space;
|
|
}
|
|
};
|
|
|
|
// System transaction is always transaction 0.
|
|
const SLONG TRA_system_transaction = 0;
|
|
|
|
// Flag definitions for tra_flags.
|
|
|
|
const ULONG TRA_system = 1L; /* system transaction */
|
|
//const ULONG TRA_update = 2L; // update is permitted
|
|
const ULONG TRA_prepared = 4L; /* transaction is in limbo */
|
|
const ULONG TRA_reconnected = 8L; /* reconnect in progress */
|
|
//const ULONG TRA_reserving = 16L; // relations explicityly locked
|
|
const ULONG TRA_degree3 = 32L; /* serializeable transaction */
|
|
//const ULONG TRA_committing = 64L; // commit in progress
|
|
const ULONG TRA_write = 128L; /* transaction has written */
|
|
const ULONG TRA_readonly = 256L; /* transaction is readonly */
|
|
//const ULONG TRA_nowait = 512L; // don't wait on relations, give up
|
|
const ULONG TRA_prepare2 = 1024L; /* transaction has updated RDB$TRANSACTIONS */
|
|
const ULONG TRA_ignore_limbo = 2048L; /* ignore transactions in limbo */
|
|
const ULONG TRA_invalidated = 4096L; /* transaction invalidated by failed write */
|
|
const ULONG TRA_deferred_meta = 8192L; /* deferred meta work posted */
|
|
//const ULONG TRA_add_log = 16384L; // write ahead log file was added
|
|
//const ULONG TRA_delete_log = 32768L; // write ahead log file was deleted
|
|
const ULONG TRA_read_committed = 65536L; /* can see latest committed records */
|
|
const ULONG TRA_autocommit = 131072L; /* autocommits all updates */
|
|
const ULONG TRA_perform_autocommit = 262144L; /* indicates autocommit is necessary */
|
|
const ULONG TRA_rec_version = 524288L; /* don't wait for uncommitted versions */
|
|
const ULONG TRA_restart_requests = 1048576L; /* restart all requests in attachment */
|
|
const ULONG TRA_no_auto_undo = 2097152L; /* don't start a savepoint in TRA_start */
|
|
const ULONG TRA_cancel_request = 4194304L; // cancel active request, if any
|
|
const ULONG TRA_precommitted = 8388608L; /* transaction committed at startup */
|
|
|
|
const int TRA_MASK = 3;
|
|
//const int TRA_BITS_PER_TRANS = 2;
|
|
//const int TRA_TRANS_PER_BYTE = 4;
|
|
const int TRA_SHIFT = 2;
|
|
|
|
#define TRANS_SHIFT(number) (((number) & TRA_MASK) << 1)
|
|
#define TRANS_OFFSET(number) ((number) >> TRA_SHIFT)
|
|
|
|
/* Transaction cleanup. If a database is never quiescent, look
|
|
for "dead" active transactions every so often at transaction
|
|
startup */
|
|
|
|
const int TRA_ACTIVE_CLEANUP = 100;
|
|
|
|
/* Transaction states. The first four are states found
|
|
in the transaction inventory page; the last two are
|
|
returned internally */
|
|
|
|
const int tra_active = 0; /* Transaction is active */
|
|
const int tra_limbo = 1;
|
|
const int tra_dead = 2;
|
|
const int tra_committed = 3;
|
|
const int tra_us = 4; /* Transaction is us */
|
|
const int tra_precommitted = 5; /* Transaction is precommitted */
|
|
|
|
// The highest transaction number possible. This is 0x7fffffff if SLONG is 32 bits.
|
|
//#define MAX_TRA_NUMBER (~(1L << (BITS_PER_LONG - 1)))
|
|
|
|
/* Savepoint block */
|
|
|
|
class Savepoint : public pool_alloc<type_sav>
|
|
{
|
|
public:
|
|
VerbAction* sav_verb_actions; /* verb action list */
|
|
VerbAction* sav_verb_free; /* free verb actions */
|
|
USHORT sav_verb_count; /* Active verb count */
|
|
SLONG sav_number; /* save point number */
|
|
Savepoint* sav_next;
|
|
USHORT sav_flags;
|
|
TEXT sav_name[32]; /* Savepoint name */
|
|
};
|
|
|
|
/* Savepoint block flags. */
|
|
|
|
const int SAV_trans_level = 1; /* savepoint was started by TRA_start */
|
|
const int SAV_event_post = 2; /* event posted in the save point */
|
|
const int SAV_user = 4; /* named user savepoint as opposed to system ones */
|
|
|
|
/* Maximum size in bytes of transaction-level savepoint data.
|
|
When transaction-level savepoint gets past this size we drop it and use GC
|
|
mechanisms to clean out changes done in transaction */
|
|
const IPTR SAV_LARGE = 1024 * 32;
|
|
|
|
/* Deferred work blocks are used by the meta data handler to keep track
|
|
of work deferred to commit time. This are usually used to perform
|
|
meta data updates */
|
|
|
|
enum dfw_t {
|
|
dfw_null,
|
|
dfw_create_relation,
|
|
dfw_delete_relation,
|
|
dfw_update_format,
|
|
dfw_create_index,
|
|
dfw_delete_index,
|
|
dfw_compute_security,
|
|
dfw_add_file,
|
|
dfw_add_shadow,
|
|
dfw_delete_shadow,
|
|
dfw_modify_file,
|
|
dfw_erase_file,
|
|
dfw_create_field,
|
|
dfw_delete_field,
|
|
dfw_modify_field,
|
|
dfw_delete_global,
|
|
dfw_delete_rfr,
|
|
dfw_post_event,
|
|
dfw_create_trigger,
|
|
dfw_delete_trigger,
|
|
dfw_modify_trigger,
|
|
//dfw_load_triggers,
|
|
dfw_grant,
|
|
dfw_revoke,
|
|
dfw_scan_relation,
|
|
dfw_create_expression_index,
|
|
dfw_delete_expression_index,
|
|
dfw_create_procedure,
|
|
dfw_modify_procedure,
|
|
dfw_delete_procedure,
|
|
dfw_delete_prm,
|
|
dfw_create_collation,
|
|
dfw_delete_collation,
|
|
dfw_delete_exception,
|
|
//dfw_unlink_file,
|
|
dfw_delete_generator,
|
|
dfw_modify_generator,
|
|
dfw_delete_udf,
|
|
dfw_add_difference,
|
|
dfw_delete_difference,
|
|
dfw_begin_backup,
|
|
dfw_end_backup,
|
|
|
|
// deferred works argument types
|
|
dfw_arg_index_name, // index name for dfw_delete_expression_index, mandatory
|
|
dfw_arg_partner_rel_id, // partner relation id for dfw_delete_index if index is FK, optional
|
|
dfw_arg_proc_name, // procedure name for dfw_delete_prm, mandatory
|
|
dfw_arg_force_computed, // we need to drop dependencies from a field that WAS computed
|
|
dfw_arg_check_blr, // check if BLR is still compilable
|
|
dfw_arg_rel_name, // relation name of a trigger
|
|
dfw_arg_trg_type // trigger type
|
|
};
|
|
|
|
class DeferredWork : public pool_alloc<type_dfw>
|
|
{
|
|
public:
|
|
enum dfw_t dfw_type; /* type of work deferred */
|
|
DeferredWork* dfw_next; /* next block in transaction */
|
|
Lock* dfw_lock; /* relation creation lock */
|
|
DeferredWork* dfw_args; /* arguments */
|
|
SLONG dfw_sav_number; /* save point number */
|
|
USHORT dfw_id; /* object id, if appropriate */
|
|
USHORT dfw_count; /* count of block posts */
|
|
Firebird::string dfw_name; /* name of object */
|
|
public:
|
|
explicit DeferredWork(MemoryPool& p) : dfw_name(p) { }
|
|
};
|
|
|
|
/* Verb actions */
|
|
|
|
class UndoItem
|
|
{
|
|
public:
|
|
SINT64 rec_number;
|
|
Record* rec_data;
|
|
static const SINT64& generate(const void *sender, const UndoItem& item)
|
|
{
|
|
return item.rec_number;
|
|
}
|
|
UndoItem() {}
|
|
UndoItem(SINT64 rec_numberL, Record* rec_dataL)
|
|
{
|
|
this->rec_number = rec_numberL;
|
|
this->rec_data = rec_dataL;
|
|
}
|
|
};
|
|
|
|
typedef Firebird::BePlusTree<UndoItem, SINT64, MemoryPool, UndoItem> UndoItemTree;
|
|
|
|
class VerbAction : public pool_alloc<type_vct>
|
|
{
|
|
public:
|
|
VerbAction* vct_next; /* Next action within verb */
|
|
jrd_rel* vct_relation; /* Relation involved */
|
|
RecordBitmap* vct_records; /* Record involved */
|
|
UndoItemTree* vct_undo; /* Data for undo records */
|
|
};
|
|
|
|
} //namespace Jrd
|
|
|
|
#endif // JRD_TRA_H
|
|
|