mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-31 06:43:02 +01:00
6ae3e2cbaf
2) Applied the same approach to temporary GC records. 3) Refactored the Record class to avoid reallocations, to improve encapsulation and to simplify the code. 4) Slightly refactored UndoItem to isolate its logic from the Record class. 5) Reduced the in-memory size of the undo log. 6) Slightly better alternative to the legacy NULL reporting for outer joins. 7) Minor fixes and adjustments in BufferedStream.
657 lines
18 KiB
C++
657 lines
18 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/sort.h"
|
|
|
|
#include "../jrd/Monitoring.h"
|
|
#include "../jrd/TempSpace.h"
|
|
#include "../jrd/obj.h"
|
|
#include "../jrd/EngineInterface.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 DeferredJob;
|
|
class dsql_opn;
|
|
class UserManagement;
|
|
class MappingList;
|
|
class DbCreatorsList;
|
|
class thread_db;
|
|
|
|
class SecDbContext
|
|
{
|
|
public:
|
|
SecDbContext(Firebird::IAttachment* a, Firebird::ITransaction* t);
|
|
~SecDbContext();
|
|
|
|
Firebird::IAttachment* att;
|
|
Firebird::ITransaction* tra;
|
|
int savePoint;
|
|
};
|
|
|
|
//Moved to fb_types.h
|
|
//typedef ULONG TraNumber;
|
|
|
|
// Moved to constants.h
|
|
//const TraNumber MAX_TRA_NUMBER = ~TraNumber(0);
|
|
|
|
// 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
|
|
|
|
struct CallerName
|
|
{
|
|
CallerName(int aType, const Firebird::MetaName& aName)
|
|
: type(aType),
|
|
name(aName)
|
|
{
|
|
}
|
|
|
|
CallerName()
|
|
: type(obj_type_MAX)
|
|
{
|
|
}
|
|
|
|
CallerName(const CallerName& o)
|
|
: type(o.type),
|
|
name(o.name)
|
|
{
|
|
}
|
|
|
|
void operator =(const CallerName& o)
|
|
{
|
|
if (&o != this)
|
|
{
|
|
type = o.type;
|
|
name = o.name;
|
|
}
|
|
}
|
|
|
|
int type;
|
|
Firebird::MetaName name;
|
|
};
|
|
|
|
const int DEFAULT_LOCK_TIMEOUT = -1; // infinite
|
|
const char* const TRA_BLOB_SPACE = "fb_blob_";
|
|
const char* const TRA_UNDO_SPACE = "fb_undo_";
|
|
|
|
class jrd_tra : public pool_alloc<type_tra>
|
|
{
|
|
typedef Firebird::GenericMap<Firebird::Pair<Firebird::NonPooled<USHORT, SINT64> > > GenIdCache;
|
|
|
|
static const size_t MAX_UNDO_RECORDS = 2;
|
|
typedef Firebird::HalfStaticArray<Record*, MAX_UNDO_RECORDS> UndoRecordList;
|
|
|
|
public:
|
|
enum wait_t {
|
|
tra_no_wait,
|
|
tra_probe,
|
|
tra_wait
|
|
};
|
|
|
|
jrd_tra(MemoryPool* p, Firebird::MemoryStats* parent_stats,
|
|
Attachment* attachment, jrd_tra* outer)
|
|
: tra_attachment(attachment),
|
|
tra_pool(p),
|
|
tra_memory_stats(parent_stats),
|
|
tra_blobs_tree(p),
|
|
tra_blobs(outer ? outer->tra_blobs : &tra_blobs_tree),
|
|
tra_arrays(NULL),
|
|
tra_deferred_job(NULL),
|
|
tra_resources(*p),
|
|
tra_context_vars(*p),
|
|
tra_lock_timeout(DEFAULT_LOCK_TIMEOUT),
|
|
tra_timestamp(Firebird::TimeStamp::getCurrentTimeStamp()),
|
|
tra_stats(*p),
|
|
tra_open_cursors(*p),
|
|
tra_outer(outer),
|
|
tra_transactions(*p),
|
|
tra_sorts(*p),
|
|
tra_public_interface(NULL),
|
|
tra_gen_ids(NULL),
|
|
tra_interface(NULL),
|
|
tra_blob_space(NULL),
|
|
tra_undo_space(NULL),
|
|
tra_undo_records(*p),
|
|
tra_user_management(NULL),
|
|
tra_sec_db_context(NULL),
|
|
tra_mapping_list(NULL),
|
|
tra_autonomous_pool(NULL),
|
|
tra_autonomous_cnt(0)
|
|
{
|
|
}
|
|
|
|
~jrd_tra();
|
|
|
|
static jrd_tra* create(MemoryPool* pool, Attachment* attachment, jrd_tra* outer)
|
|
{
|
|
jrd_tra* const transaction =
|
|
FB_NEW(*pool) jrd_tra(pool, &attachment->att_memory_stats, attachment, outer);
|
|
|
|
if (!outer)
|
|
{
|
|
pool->setStatsGroup(transaction->tra_memory_stats);
|
|
}
|
|
|
|
return transaction;
|
|
}
|
|
|
|
static void destroy(Attachment* const attachment, jrd_tra* const transaction)
|
|
{
|
|
if (transaction)
|
|
{
|
|
if (!attachment)
|
|
delete transaction;
|
|
else if (transaction->tra_outer)
|
|
{
|
|
jrd_tra* outer = transaction->tra_outer;
|
|
MemoryPool* const pool = transaction->tra_pool;
|
|
delete transaction;
|
|
outer->releaseAutonomousPool(pool);
|
|
}
|
|
else
|
|
{
|
|
MemoryPool* const pool = transaction->tra_pool;
|
|
Firebird::MemoryStats temp_stats;
|
|
pool->setStatsGroup(temp_stats);
|
|
delete transaction;
|
|
attachment->deletePool(pool);
|
|
}
|
|
}
|
|
}
|
|
|
|
Attachment* getAttachment()
|
|
{
|
|
return tra_attachment;
|
|
}
|
|
|
|
dsql_dbb* getDsqlAttachment()
|
|
{
|
|
return tra_attachment->att_dsql_instance;
|
|
}
|
|
|
|
JTransaction* getInterface();
|
|
void setInterface(JTransaction* jt);
|
|
|
|
FB_API_HANDLE tra_public_handle; // Public handle
|
|
Attachment* tra_attachment; // database attachment
|
|
TraNumber tra_number; // transaction number
|
|
TraNumber tra_top; // highest transaction in snapshot
|
|
TraNumber tra_oldest; // oldest interesting transaction
|
|
TraNumber tra_oldest_active; // record versions older than this can be
|
|
// gargage-collected by this tx
|
|
TraNumber tra_att_oldest_active; // oldest active transaction in the same attachment
|
|
jrd_tra* tra_next; // next transaction in attachment
|
|
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
|
|
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;
|
|
DeferredJob* tra_deferred_job; // 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
|
|
MonitoringSnapshot* tra_mon_snapshot; // Database state snapshot (for monitoring purposes)
|
|
RuntimeStatistics tra_stats;
|
|
Firebird::Array<DsqlCursor*> tra_open_cursors;
|
|
bool tra_in_use; // transaction in use (can't be committed or rolled back)
|
|
jrd_tra* const tra_outer; // outer transaction of an autonomous transaction
|
|
CallerName tra_caller_name; // caller object name
|
|
Firebird::Array<UCHAR> tra_transactions;
|
|
SortOwner tra_sorts;
|
|
|
|
EDS::Transaction *tra_ext_common;
|
|
//Transaction *tra_ext_two_phase;
|
|
Firebird::ITransaction* tra_public_interface;
|
|
GenIdCache* tra_gen_ids;
|
|
|
|
private:
|
|
JTransaction* tra_interface;
|
|
TempSpace* tra_blob_space; // temp blob storage
|
|
TempSpace* tra_undo_space; // undo log storage
|
|
|
|
UndoRecordList tra_undo_records; // temporary records used for the undo purposes
|
|
UserManagement* tra_user_management;
|
|
SecDbContext* tra_sec_db_context;
|
|
MappingList* tra_mapping_list;
|
|
DbCreatorsList* tra_dbcreators_list;
|
|
MemoryPool* tra_autonomous_pool;
|
|
USHORT tra_autonomous_cnt;
|
|
static const USHORT TRA_AUTONOMOUS_PER_POOL = 64;
|
|
|
|
public:
|
|
MemoryPool* getAutonomousPool();
|
|
void releaseAutonomousPool(MemoryPool* toRelease);
|
|
jrd_tra* getOuter();
|
|
|
|
SSHORT getLockWait() const
|
|
{
|
|
return -tra_lock_timeout;
|
|
}
|
|
|
|
TempSpace* getBlobSpace()
|
|
{
|
|
if (tra_outer)
|
|
return tra_outer->getBlobSpace();
|
|
|
|
if (!tra_blob_space)
|
|
{
|
|
fb_assert(!tra_outer);
|
|
tra_blob_space = FB_NEW(*tra_pool) TempSpace(*tra_pool, TRA_BLOB_SPACE);
|
|
}
|
|
|
|
return tra_blob_space;
|
|
}
|
|
|
|
TempSpace* getUndoSpace()
|
|
{
|
|
if (!tra_undo_space)
|
|
{
|
|
tra_undo_space = FB_NEW(*tra_pool) TempSpace(*tra_pool, TRA_UNDO_SPACE);
|
|
}
|
|
|
|
return tra_undo_space;
|
|
}
|
|
|
|
Record* getUndoRecord(const Format* format)
|
|
{
|
|
for (Record** iter = tra_undo_records.begin(); iter != tra_undo_records.end(); ++iter)
|
|
{
|
|
Record* const record = *iter;
|
|
fb_assert(record);
|
|
|
|
if (!record->checkFlags(REC_undo_active))
|
|
{
|
|
// initialize record for reuse
|
|
record->reset(format, REC_undo_active);
|
|
return record;
|
|
}
|
|
}
|
|
|
|
fb_assert(tra_undo_records.getCount() < MAX_UNDO_RECORDS);
|
|
|
|
Record* const record = FB_NEW(*tra_pool) Record(*tra_pool, format, REC_undo_active);
|
|
tra_undo_records.add(record);
|
|
|
|
return record;
|
|
}
|
|
|
|
UserManagement* getUserManagement();
|
|
SecDbContext* getSecDbContext();
|
|
SecDbContext* setSecDbContext(Firebird::IAttachment* att, Firebird::ITransaction* tra);
|
|
void eraseSecDbContext();
|
|
MappingList* getMappingList();
|
|
DbCreatorsList* getDbCreatorsList();
|
|
|
|
GenIdCache* getGenIdCache()
|
|
{
|
|
if (!tra_gen_ids)
|
|
tra_gen_ids = FB_NEW(*tra_pool) GenIdCache(*tra_pool);
|
|
|
|
return tra_gen_ids;
|
|
}
|
|
};
|
|
|
|
// System transaction is always transaction 0.
|
|
const TraNumber TRA_system_transaction = 0;
|
|
|
|
// Flag definitions for tra_flags.
|
|
|
|
const ULONG TRA_system = 0x1L; // system transaction
|
|
const ULONG TRA_prepared = 0x2L; // transaction is in limbo
|
|
const ULONG TRA_reconnected = 0x4L; // reconnect in progress
|
|
const ULONG TRA_degree3 = 0x8L; // serializeable transaction
|
|
const ULONG TRA_write = 0x10L; // transaction has written
|
|
const ULONG TRA_readonly = 0x20L; // transaction is readonly
|
|
const ULONG TRA_prepare2 = 0x40L; // transaction has updated RDB$TRANSACTIONS
|
|
const ULONG TRA_ignore_limbo = 0x80L; // ignore transactions in limbo
|
|
const ULONG TRA_invalidated = 0x100L; // transaction invalidated by failed write
|
|
const ULONG TRA_deferred_meta = 0x200L; // deferred meta work posted
|
|
const ULONG TRA_read_committed = 0x400L; // can see latest committed records
|
|
const ULONG TRA_autocommit = 0x800L; // autocommits all updates
|
|
const ULONG TRA_perform_autocommit = 0x1000L; // indicates autocommit is necessary
|
|
const ULONG TRA_rec_version = 0x2000L; // don't wait for uncommitted versions
|
|
const ULONG TRA_restart_requests = 0x4000L; // restart all requests in attachment
|
|
const ULONG TRA_no_auto_undo = 0x8000L; // don't start a savepoint in TRA_start
|
|
const ULONG TRA_precommitted = 0x10000L; // transaction committed at startup
|
|
const ULONG TRA_own_interface = 0x20000L; // tra_interface was created for internal needs
|
|
|
|
// flags derived from TPB, see also transaction_options() at tra.cpp
|
|
const ULONG TRA_OPTIONS_MASK = (TRA_degree3 | TRA_readonly | TRA_ignore_limbo | TRA_read_committed |
|
|
TRA_autocommit | TRA_rec_version | TRA_no_auto_undo | TRA_restart_requests);
|
|
|
|
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:
|
|
~Savepoint()
|
|
{
|
|
deleteActions(sav_verb_actions);
|
|
deleteActions(sav_verb_free);
|
|
}
|
|
|
|
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[MAX_SQL_IDENTIFIER_SIZE]; // Savepoint name
|
|
|
|
private:
|
|
void deleteActions(VerbAction* list);
|
|
};
|
|
|
|
// Savepoint block flags.
|
|
|
|
const int SAV_trans_level = 1; // savepoint was started by TRA_start
|
|
const int SAV_force_dfw = 2; // DFW is present even if savepoint is empty
|
|
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_create_function,
|
|
dfw_modify_function,
|
|
dfw_delete_function,
|
|
dfw_add_difference,
|
|
dfw_delete_difference,
|
|
dfw_begin_backup,
|
|
dfw_end_backup,
|
|
dfw_user_management,
|
|
dfw_drop_package_header,
|
|
dfw_drop_package_body,
|
|
dfw_check_not_null,
|
|
dfw_store_view_context_type,
|
|
dfw_set_generator,
|
|
|
|
// 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
|
|
dfw_arg_new_name, // new name
|
|
dfw_arg_field_not_null, // set domain to not nullable
|
|
dfw_db_crypt, // change database encryption status
|
|
dfw_set_linger, // set database linger
|
|
dfw_clear_mapping // clear user mapping cache
|
|
};
|
|
|
|
// Verb actions
|
|
|
|
class UndoItem
|
|
{
|
|
static const UCHAR FLAG_SAME_TX = 1; // record inserted/updated and deleted by same tx
|
|
static const UCHAR FLAG_NEW_VER = 2; // savepoint created new record version and deleted it
|
|
|
|
public:
|
|
static const SINT64& generate(const void* /*sender*/, const UndoItem& item)
|
|
{
|
|
return item.m_number;
|
|
}
|
|
|
|
UndoItem() {}
|
|
|
|
UndoItem(RecordNumber recordNumber, bool sameTx, bool newVersion)
|
|
: m_number(recordNumber.getValue()), m_offset(0), m_format(NULL)
|
|
{
|
|
m_flags = (sameTx ? FLAG_SAME_TX : 0) | (newVersion ? FLAG_NEW_VER : 0);
|
|
}
|
|
|
|
UndoItem(jrd_tra* transaction, RecordNumber recordNumber, const Record* record,
|
|
bool sameTx, bool newVersion)
|
|
: m_number(recordNumber.getValue()), m_format(record->getFormat())
|
|
{
|
|
m_flags = (sameTx ? FLAG_SAME_TX : 0) | (newVersion ? FLAG_NEW_VER : 0);
|
|
m_offset = transaction->getUndoSpace()->allocateSpace(m_format->fmt_length);
|
|
transaction->getUndoSpace()->write(m_offset, record->getData(), record->getLength());
|
|
}
|
|
|
|
Record* setupRecord(jrd_tra* transaction) const
|
|
{
|
|
if (m_format)
|
|
{
|
|
Record* const record = transaction->getUndoRecord(m_format);
|
|
transaction->getUndoSpace()->read(m_offset, record->getData(), record->getLength());
|
|
return record;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void release(jrd_tra* transaction)
|
|
{
|
|
if (m_format)
|
|
{
|
|
transaction->getUndoSpace()->releaseSpace(m_offset, m_format->fmt_length);
|
|
m_format = NULL;
|
|
}
|
|
}
|
|
|
|
void markSameTx()
|
|
{
|
|
m_flags |= FLAG_SAME_TX;
|
|
}
|
|
|
|
const bool isSameTx() const
|
|
{
|
|
return (m_flags & FLAG_SAME_TX);
|
|
}
|
|
|
|
const bool isNewVersion() const
|
|
{
|
|
return (m_flags & FLAG_NEW_VER);
|
|
}
|
|
|
|
bool hasData() const
|
|
{
|
|
return (m_format != NULL);
|
|
}
|
|
|
|
bool isEmpty() const
|
|
{
|
|
return (m_format == NULL);
|
|
}
|
|
|
|
private:
|
|
SINT64 m_number;
|
|
offset_t m_offset;
|
|
const Format* m_format;
|
|
UCHAR m_flags;
|
|
};
|
|
|
|
typedef Firebird::BePlusTree<UndoItem, SINT64, MemoryPool, UndoItem> UndoItemTree;
|
|
|
|
class VerbAction : public pool_alloc<type_vct>
|
|
{
|
|
public:
|
|
~VerbAction()
|
|
{
|
|
delete vct_records;
|
|
delete vct_undo;
|
|
}
|
|
|
|
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
|
|
};
|
|
|
|
|
|
inline void Savepoint::deleteActions(VerbAction* list)
|
|
{
|
|
while (list)
|
|
{
|
|
VerbAction* next = list->vct_next;
|
|
delete list;
|
|
list = next;
|
|
}
|
|
};
|
|
|
|
} //namespace Jrd
|
|
|
|
#endif // JRD_TRA_H
|