"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/jrd/tra.cpp" between
Firebird-3.0.2.32703-0.tar.bz2 and Firebird-3.0.4.33054-0.tar.bz2

About: Firebird is a relational database offering many ANSI SQL standard features.

tra.cpp  (Firebird-3.0.2.32703-0.tar.bz2):tra.cpp  (Firebird-3.0.4.33054-0.tar.bz2)
skipping to change at line 63 skipping to change at line 63
#include "../common/isc_proto.h" #include "../common/isc_proto.h"
#include "../jrd/lck_proto.h" #include "../jrd/lck_proto.h"
#include "../jrd/met_proto.h" #include "../jrd/met_proto.h"
#include "../jrd/mov_proto.h" #include "../jrd/mov_proto.h"
#include "../jrd/pag_proto.h" #include "../jrd/pag_proto.h"
#include "../jrd/rlck_proto.h" #include "../jrd/rlck_proto.h"
#include "../jrd/tpc_proto.h" #include "../jrd/tpc_proto.h"
#include "../jrd/tra_proto.h" #include "../jrd/tra_proto.h"
#include "../jrd/vio_proto.h" #include "../jrd/vio_proto.h"
#include "../jrd/jrd_proto.h" #include "../jrd/jrd_proto.h"
#include "../jrd/scl_proto.h"
#include "../common/classes/ClumpletWriter.h" #include "../common/classes/ClumpletWriter.h"
#include "../common/classes/TriState.h" #include "../common/classes/TriState.h"
#include "../common/utils_proto.h" #include "../common/utils_proto.h"
#include "../lock/lock_proto.h" #include "../lock/lock_proto.h"
#include "../dsql/dsql.h" #include "../dsql/dsql.h"
#include "../dsql/dsql_proto.h" #include "../dsql/dsql_proto.h"
#include "../common/StatusArg.h" #include "../common/StatusArg.h"
#include "../jrd/trace/TraceManager.h" #include "../jrd/trace/TraceManager.h"
#include "../jrd/trace/TraceJrdHelpers.h" #include "../jrd/trace/TraceJrdHelpers.h"
#include "../jrd/Function.h" #include "../jrd/Function.h"
#include "../jrd/Collation.h" #include "../jrd/Collation.h"
#include "../jrd/Mapping.h" #include "../jrd/Mapping.h"
#include "../jrd/DbCreators.h" #include "../jrd/DbCreators.h"
#include "../common/os/fbsyslog.h"
const int DYN_MSG_FAC = 8; const int DYN_MSG_FAC = 8;
using namespace Jrd; using namespace Jrd;
using namespace Ods; using namespace Ods;
using namespace Firebird; using namespace Firebird;
typedef Firebird::GenericMap<Firebird::Pair<Firebird::NonPooled<USHORT, UCHAR> > > RelationLockTypeMap; typedef Firebird::GenericMap<Firebird::Pair<Firebird::NonPooled<USHORT, UCHAR> > > RelationLockTypeMap;
#ifdef SUPERSERVER_V2 #ifdef SUPERSERVER_V2
skipping to change at line 97 skipping to change at line 99
#else #else
static header_page* bump_transaction_id(thread_db*, WIN*, bool); static header_page* bump_transaction_id(thread_db*, WIN*, bool);
#endif #endif
static void retain_context(thread_db* tdbb, jrd_tra* transaction, bool commit, i nt state); static void retain_context(thread_db* tdbb, jrd_tra* transaction, bool commit, i nt state);
static void expand_view_lock(thread_db* tdbb, jrd_tra*, jrd_rel*, UCHAR lock_typ e, static void expand_view_lock(thread_db* tdbb, jrd_tra*, jrd_rel*, UCHAR lock_typ e,
const char* option_name, RelationLockTypeMap& lockmap, const int level); const char* option_name, RelationLockTypeMap& lockmap, const int level);
static tx_inv_page* fetch_inventory_page(thread_db*, WIN* window, ULONG sequence , USHORT lock_level); static tx_inv_page* fetch_inventory_page(thread_db*, WIN* window, ULONG sequence , USHORT lock_level);
static const char* get_lockname_v3(const UCHAR lock); static const char* get_lockname_v3(const UCHAR lock);
static ULONG inventory_page(thread_db*, ULONG); static ULONG inventory_page(thread_db*, ULONG);
static int limbo_transaction(thread_db*, TraNumber id); static int limbo_transaction(thread_db*, TraNumber id);
static void link_transaction(thread_db*, jrd_tra*);
static void restart_requests(thread_db*, jrd_tra*); static void restart_requests(thread_db*, jrd_tra*);
static void start_sweeper(thread_db*); static void start_sweeper(thread_db*);
static THREAD_ENTRY_DECLARE sweep_database(THREAD_ENTRY_PARAM); static THREAD_ENTRY_DECLARE sweep_database(THREAD_ENTRY_PARAM);
static void transaction_flush(thread_db* tdbb, USHORT flush_flag, TraNumber tra_ number); static void transaction_flush(thread_db* tdbb, USHORT flush_flag, TraNumber tra_ number);
static void transaction_options(thread_db*, jrd_tra*, const UCHAR*, USHORT); static void transaction_options(thread_db*, jrd_tra*, const UCHAR*, USHORT);
static void transaction_start(thread_db* tdbb, jrd_tra* temp); static void transaction_start(thread_db* tdbb, jrd_tra* temp);
static const UCHAR sweep_tpb[] = static const UCHAR sweep_tpb[] =
{ {
isc_tpb_version1, isc_tpb_read, isc_tpb_version1, isc_tpb_read,
skipping to change at line 247 skipping to change at line 248
const ULONG last = ceiling / trans_per_tip; const ULONG last = ceiling / trans_per_tip;
ULONG number = active % trans_per_tip; ULONG number = active % trans_per_tip;
TraNumber limbo = 0; TraNumber limbo = 0;
for (ULONG sequence = active / trans_per_tip; sequence <= last; sequence+ +, number = 0) for (ULONG sequence = active / trans_per_tip; sequence <= last; sequence+ +, number = 0)
{ {
window.win_page = inventory_page(tdbb, sequence); window.win_page = inventory_page(tdbb, sequence);
tx_inv_page* tip = (tx_inv_page*) CCH_FETCH(tdbb, &window, LCK_wr ite, pag_transactions); tx_inv_page* tip = (tx_inv_page*) CCH_FETCH(tdbb, &window, LCK_wr ite, pag_transactions);
TraNumber max = ceiling - (TraNumber) sequence * trans_per_tip; TraNumber max = ceiling - (TraNumber) sequence * trans_per_tip;
if (max > trans_per_tip) if (max >= trans_per_tip)
max = trans_per_tip - 1; max = trans_per_tip - 1;
for (; number <= max; number++) for (; number <= max; number++)
{ {
const ULONG trans_offset = TRANS_OFFSET(number); const ULONG trans_offset = TRANS_OFFSET(number);
UCHAR* byte = tip->tip_transactions + trans_offset; UCHAR* byte = tip->tip_transactions + trans_offset;
const USHORT shift = TRANS_SHIFT(number); const USHORT shift = TRANS_SHIFT(number);
const int state = (*byte >> shift) & TRA_MASK; const int state = (*byte >> shift) & TRA_MASK;
if (state == tra_limbo && limbo == 0) if (state == tra_limbo && limbo == 0)
limbo = (TraNumber) sequence * trans_per_tip + nu mber; limbo = (TraNumber) sequence * trans_per_tip + nu mber;
else if (state == tra_active) else if (state == tra_active)
skipping to change at line 809 skipping to change at line 810
if (!dbb || dbb->dbb_flags & DBB_read_only || dbb->dbb_flags & DBB_new || if (!dbb || dbb->dbb_flags & DBB_read_only || dbb->dbb_flags & DBB_new ||
dbb->dbb_oldest_transaction == 0) dbb->dbb_oldest_transaction == 0)
{ {
return; return;
} }
WIN window(HEADER_PAGE_NUMBER); WIN window(HEADER_PAGE_NUMBER);
header_page* header = (header_page*)CCH_FETCH(tdbb, &window, LCK_write, p ag_header); header_page* header = (header_page*)CCH_FETCH(tdbb, &window, LCK_write, p ag_header);
if (dbb->dbb_oldest_active > header->hdr_oldest_active || const TraNumber next_transaction = Ods::getNT(header);
dbb->dbb_oldest_transaction > header->hdr_oldest_transaction || const TraNumber oldest_transaction = Ods::getOIT(header);
dbb->dbb_oldest_snapshot > header->hdr_oldest_snapshot) const TraNumber oldest_active = Ods::getOAT(header);
const TraNumber oldest_snapshot = Ods::getOST(header);
fb_assert(dbb->dbb_next_transaction <= next_transaction);
if (dbb->dbb_oldest_active > oldest_active ||
dbb->dbb_oldest_transaction > oldest_transaction ||
dbb->dbb_oldest_snapshot > oldest_snapshot ||
dbb->dbb_next_transaction > next_transaction)
{ {
CCH_MARK_MUST_WRITE(tdbb, &window); CCH_MARK_MUST_WRITE(tdbb, &window);
if (dbb->dbb_oldest_active > header->hdr_oldest_active) if (dbb->dbb_oldest_active > oldest_active)
header->hdr_oldest_active = dbb->dbb_oldest_active; Ods::writeOAT(header, dbb->dbb_oldest_active);
if (dbb->dbb_oldest_transaction > header->hdr_oldest_transaction) if (dbb->dbb_oldest_transaction > oldest_transaction)
header->hdr_oldest_transaction = dbb->dbb_oldest_transact Ods::writeOIT(header, dbb->dbb_oldest_transaction);
ion;
if (dbb->dbb_oldest_snapshot > header->hdr_oldest_snapshot) if (dbb->dbb_oldest_snapshot > oldest_snapshot)
header->hdr_oldest_snapshot = dbb->dbb_oldest_snapshot; Ods::writeOST(header, dbb->dbb_oldest_snapshot);
if (dbb->dbb_next_transaction > next_transaction)
Ods::writeNT(header, dbb->dbb_next_transaction);
} }
CCH_RELEASE(tdbb, &window); CCH_RELEASE(tdbb, &window);
} }
void TRA_post_resources(thread_db* tdbb, jrd_tra* transaction, ResourceList& res ources) void TRA_post_resources(thread_db* tdbb, jrd_tra* transaction, ResourceList& res ources)
{ {
/************************************** /**************************************
* *
* T R A _ p o s t _ r e s o u r c e s * T R A _ p o s t _ r e s o u r c e s
skipping to change at line 1115 skipping to change at line 1127
ERR_post(Arg::Gds(isc_no_recon) << ERR_post(Arg::Gds(isc_no_recon) <<
Arg::Gds(isc_tra_state) << Arg::Num(number) << A rg::Str(text)); Arg::Gds(isc_tra_state) << Arg::Num(number) << A rg::Str(text));
} }
MemoryPool* const pool = attachment->createPool(); MemoryPool* const pool = attachment->createPool();
Jrd::ContextPoolHolder context(tdbb, pool); Jrd::ContextPoolHolder context(tdbb, pool);
jrd_tra* const trans = jrd_tra::create(pool, attachment, NULL); jrd_tra* const trans = jrd_tra::create(pool, attachment, NULL);
trans->tra_number = number; trans->tra_number = number;
trans->tra_flags |= TRA_prepared | TRA_reconnected | TRA_write; trans->tra_flags |= TRA_prepared | TRA_reconnected | TRA_write;
link_transaction(tdbb, trans); trans->linkToAttachment(attachment);
return trans; return trans;
} }
void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction, Jrd::TraceTr ansactionEnd* trace) void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction, Jrd::TraceTr ansactionEnd* trace)
{ {
/************************************** /**************************************
* *
* T R A _ r e l e a s e _ t r a n s a c t i o n * T R A _ r e l e a s e _ t r a n s a c t i o n
* *
skipping to change at line 1210 skipping to change at line 1222
jrd_rel* relation = rels[i]; jrd_rel* relation = rels[i];
if (relation && (relation->rel_flags & REL_temp_tran)) if (relation && (relation->rel_flags & REL_temp_tran))
relation->delPages(tdbb, transaction->tra_number) ; relation->delPages(tdbb, transaction->tra_number) ;
} }
} // end scope } // end scope
// Release the locks associated with the transaction // Release the locks associated with the transaction
if (transaction->tra_alter_db_lock)
LCK_release(tdbb, transaction->tra_alter_db_lock);
vec<Lock*>* vector = transaction->tra_relation_locks; vec<Lock*>* vector = transaction->tra_relation_locks;
if (vector) if (vector)
{ {
vec<Lock*>::iterator lock = vector->begin(); vec<Lock*>::iterator lock = vector->begin();
for (ULONG i = 0; i < vector->count(); ++i, ++lock) for (ULONG i = 0; i < vector->count(); ++i, ++lock)
{ {
if (*lock) if (*lock)
LCK_release(tdbb, *lock); LCK_release(tdbb, *lock);
} }
} }
skipping to change at line 1238 skipping to change at line 1253
delete transaction->tra_commit_sub_trans; delete transaction->tra_commit_sub_trans;
if (transaction->tra_flags & TRA_precommitted) if (transaction->tra_flags & TRA_precommitted)
TRA_precommited(tdbb, transaction->tra_number, 0); TRA_precommited(tdbb, transaction->tra_number, 0);
if (trace) if (trace)
trace->finish(ITracePlugin::RESULT_SUCCESS); trace->finish(ITracePlugin::RESULT_SUCCESS);
// Unlink the transaction from the attachment block // Unlink the transaction from the attachment block
for (jrd_tra** ptr = &attachment->att_transactions; *ptr; ptr = &(*ptr)-> transaction->unlinkFromAttachment();
tra_next)
{
if (*ptr == transaction)
{
*ptr = transaction->tra_next;
break;
}
}
// Release transaction's under-modification-rpb list // Release transaction's under-modification-rpb list
delete transaction->tra_rpblist; delete transaction->tra_rpblist;
// Release the database snapshot, if any // Release the database snapshot, if any
delete transaction->tra_mon_snapshot; delete transaction->tra_mon_snapshot;
// Close all open DSQL cursors // Close all open DSQL cursors
while (transaction->tra_open_cursors.hasData()) while (transaction->tra_open_cursors.hasData())
DsqlCursor::close(tdbb, transaction->tra_open_cursors.pop()); DsqlCursor::close(tdbb, transaction->tra_open_cursors.pop());
// Release the transaction and its pool // Release the transaction and its pool
tdbb->setTransaction(NULL); tdbb->setTransaction(NULL);
JTransaction* jTra = transaction->getInterface(); JTransaction* jTra = transaction->getInterface(true); // ASF: maybe it' s better to pass false?
if (jTra) if (jTra)
{ {
jTra->setHandle(NULL); jTra->setHandle(NULL);
} }
jrd_tra::destroy(attachment, transaction); jrd_tra::destroy(attachment, transaction);
} }
void TRA_rollback(thread_db* tdbb, jrd_tra* transaction, const bool retaining_fl ag, void TRA_rollback(thread_db* tdbb, jrd_tra* transaction, const bool retaining_fl ag,
const bool force_flag) const bool force_flag)
{ {
skipping to change at line 1762 skipping to change at line 1770
Jrd::Attachment* const attachment = tdbb->getAttachment(); Jrd::Attachment* const attachment = tdbb->getAttachment();
jrd_tra* const tdbb_old_trans = tdbb->getTransaction(); jrd_tra* const tdbb_old_trans = tdbb->getTransaction();
jrd_tra* transaction = NULL; jrd_tra* transaction = NULL;
// Clean up the temporary locks we've gotten in case anything goes wrong // Clean up the temporary locks we've gotten in case anything goes wrong
try { try {
// Identify ourselves as a sweeper thread. This accomplishes two goals: // Identify ourselves as a sweeper thread. This accomplishes two
// 1) Sweep transaction is started "precommitted" and goals:
// 2) Execution is throttled in JRD_reschedule() by // 1) Sweep transaction is started "precommitted" and
// yielding the processor when our quantum expires. // 2) Execution is throttled in JRD_reschedule() by
// yielding the processor when our quantum expires.
tdbb->tdbb_flags |= TDBB_sweeper;
TraceSweepEvent traceSweep(tdbb);
// Start a transaction, if necessary, to perform the sweep.
// Save the transaction's oldest snapshot as it is refreshed
// during the course of the database sweep. Since it is used
// below to advance the OIT we must save it before it changes.
transaction = TRA_start(tdbb, sizeof(sweep_tpb), sweep_tpb);
TraNumber transaction_oldest_active = transaction->tra_oldest_active;
tdbb->setTransaction(transaction);
// The garbage collector runs asynchronously with respect to
// our database sweep. This isn't good enough since we must
// be absolutely certain that all dead transactions have been
// swept from the database before advancing the OIT. Turn off
// the "notify garbage collector" flag for the attachment and
// synchronously perform the garbage collection ourselves.
attachment->att_flags &= ~ATT_notify_gc;
if (VIO_sweep(tdbb, transaction, &traceSweep))
{
// At this point, we know that no record versions belonging to de
ad
// transactions remain anymore. However, there may still be limbo
// transactions, so we need to find the oldest one between tra_ol
dest and tra_top.
// As our transaction is read-committed (see sweep_tpb), we have
to scan
// the global TIP cache.
int oldest_state = 0;
const TraNumber oldest_limbo =
TPC_find_states(tdbb, transaction->tra_oldest, transactio
n->tra_top - 1,
1 << tra_limbo, oldest_st
ate);
const TraNumber active = oldest_limbo ? oldest_limbo : transactio
n->tra_top;
// Flush page buffers to insure that no dangling records from
// dead transactions are left on-disk. This must be done before
// the OIT is advanced and the header page is written to disk.
// If the header page was written before flushing the page buffer
s
// and there was a server crash, the dead records would appear
// committed since their TID would now be less than the OIT recor
ded
// in the database.
CCH_flush(tdbb, FLUSH_SWEEP, 0); tdbb->tdbb_flags |= TDBB_sweeper;
WIN window(HEADER_PAGE_NUMBER); TraceSweepEvent traceSweep(tdbb);
header_page* const header = (header_page*) CCH_FETCH(tdbb, &windo
w, LCK_write, pag_header); // Start a transaction, if necessary, to perform the sweep.
// Save the transaction's oldest snapshot as it is refreshed
// during the course of the database sweep. Since it is used
// below to advance the OIT we must save it before it changes.
transaction = TRA_start(tdbb, sizeof(sweep_tpb), sweep_tpb);
if (Ods::getOIT(header) < --transaction_oldest_active) TraNumber transaction_oldest_active = transaction->tra_oldest_act
ive;
tdbb->setTransaction(transaction);
// The garbage collector runs asynchronously with respect to
// our database sweep. This isn't good enough since we must
// be absolutely certain that all dead transactions have been
// swept from the database before advancing the OIT. Turn off
// the "notify garbage collector" flag for the attachment and
// synchronously perform the garbage collection ourselves.
attachment->att_flags &= ~ATT_notify_gc;
if (VIO_sweep(tdbb, transaction, &traceSweep))
{ {
CCH_MARK_MUST_WRITE(tdbb, &window); // At this point, we know that no record versions belongi
Ods::writeOIT(header, MIN(active, transaction_oldest_acti ng to dead
ve)); // transactions remain anymore. However, there may still
} be limbo
// transactions, so we need to find the oldest one betwee
n tra_oldest and tra_top.
// As our transaction is read-committed (see sweep_tpb),
we have to scan
// the global TIP cache.
traceSweep.update(header); int oldest_state = 0;
const TraNumber oldest_limbo =
TPC_find_states(tdbb, transaction->tra_oldest, tr
ansaction->tra_top - 1,
1 << tra_limbo, o
ldest_state);
CCH_RELEASE(tdbb, &window); const TraNumber active = oldest_limbo ? oldest_limbo : tr ansaction->tra_top;
traceSweep.finish(); // Flush page buffers to insure that no dangling records
} from
// dead transactions are left on-disk. This must be done
before
// the OIT is advanced and the header page is written to
disk.
// If the header page was written before flushing the pag
e buffers
// and there was a server crash, the dead records would a
ppear
// committed since their TID would now be less than the O
IT recorded
// in the database.
TRA_commit(tdbb, transaction, false); CCH_flush(tdbb, FLUSH_SWEEP, 0);
tdbb->tdbb_flags &= ~TDBB_sweeper; WIN window(HEADER_PAGE_NUMBER);
tdbb->setTransaction(tdbb_old_trans); header_page* const header = (header_page*) CCH_FETCH(tdbb
dbb->clearSweepFlags(tdbb); , &window, LCK_write, pag_header);
} // try
if (Ods::getOIT(header) < --transaction_oldest_active)
{
CCH_MARK_MUST_WRITE(tdbb, &window);
Ods::writeOIT(header, MIN(active, transaction_old
est_active));
}
traceSweep.update(header);
CCH_RELEASE(tdbb, &window);
traceSweep.finish();
}
TRA_commit(tdbb, transaction, false);
tdbb->tdbb_flags &= ~TDBB_sweeper;
tdbb->setTransaction(tdbb_old_trans);
dbb->clearSweepFlags(tdbb);
}
catch (const Firebird::Exception& ex) catch (const Firebird::Exception& ex)
{ {
iscLogException("Error during sweep:", ex); PathName message = "Error during sweep of ";
message += dbb->dbb_database_name;
message += ':';
iscLogException(message.c_str(), ex);
ex.stuffException(tdbb->tdbb_status_vector); ex.stuffException(tdbb->tdbb_status_vector);
if (transaction) if (transaction)
{ {
try try
{ {
TRA_commit(tdbb, transaction, false); TRA_commit(tdbb, transaction, false);
} }
catch (const Firebird::Exception& ex2) catch (const Firebird::Exception& ex2)
skipping to change at line 2334 skipping to change at line 2345
const ULONG trans_offset = TRANS_OFFSET(number); const ULONG trans_offset = TRANS_OFFSET(number);
const UCHAR* byte = tip->tip_transactions + trans_offset; const UCHAR* byte = tip->tip_transactions + trans_offset;
const USHORT shift = TRANS_SHIFT(number); const USHORT shift = TRANS_SHIFT(number);
const int state = (*byte >> shift) & TRA_MASK; const int state = (*byte >> shift) & TRA_MASK;
CCH_RELEASE(tdbb, &window); CCH_RELEASE(tdbb, &window);
return state; return state;
} }
static void link_transaction(thread_db* tdbb, jrd_tra* transaction) void jrd_tra::unlinkFromAttachment()
{
for (jrd_tra** ptr = &tra_attachment->att_transactions; *ptr; ptr = &(*pt
r)->tra_next)
{
if (*ptr == this)
{
*ptr = tra_next;
return;
}
}
tra_abort("transaction to unlink is missing in the attachment");
}
void jrd_tra::linkToAttachment(Attachment* attachment)
{ {
/************************************** /**************************************
* *
* l i n k _ t r a n s a c t i o n * l i n k _ t r a n s a c t i o n
* *
************************************** **************************************
* *
* Functional description * Functional description
* Link transaction block into database attachment. * Link transaction block into database attachment.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); tra_next = attachment->att_transactions;
attachment->att_transactions = this;
}
Jrd::Attachment* attachment = tdbb->getAttachment(); void jrd_tra::tra_abort(const char* reason)
transaction->tra_next = attachment->att_transactions; {
attachment->att_transactions = transaction; string buff;
buff.printf("Failure working with transactions list: %s", reason);
Syslog::Record(Syslog::Error, buff.c_str());
gds__log(buff.c_str());
#ifdef DEV_BUILD
abort();
#endif
} }
static void restart_requests(thread_db* tdbb, jrd_tra* trans) static void restart_requests(thread_db* tdbb, jrd_tra* trans)
{ {
/************************************** /**************************************
* *
* r e s t a r t _ r e q u e s t s * r e s t a r t _ r e q u e s t s
* *
************************************** **************************************
* *
skipping to change at line 3160 skipping to change at line 3193
#endif // SUPERSERVER_V2 #endif // SUPERSERVER_V2
// Allocate pool and transactions block. Since, by policy, // Allocate pool and transactions block. Since, by policy,
// all transactions older than the oldest are either committed // all transactions older than the oldest are either committed
// or cleaned up, they can be all considered as committed. To // or cleaned up, they can be all considered as committed. To
// make everything simpler, round down the oldest to a multiple // make everything simpler, round down the oldest to a multiple
// of four, which puts the transaction on a byte boundary. // of four, which puts the transaction on a byte boundary.
TraNumber base = oldest & ~TRA_MASK; TraNumber base = oldest & ~TRA_MASK;
const ULONG top = (dbb->dbb_flags & DBB_read_only) ? const TraNumber top = (dbb->dbb_flags & DBB_read_only) ?
dbb->dbb_next_transaction : number; dbb->dbb_next_transaction : number;
if (!(trans->tra_flags & TRA_read_committed) && (top >= oldest)) if (!(trans->tra_flags & TRA_read_committed) && (top >= oldest))
{ {
const FB_SIZE_T length = (top + 1 - base + TRA_MASK) / 4; const FB_SIZE_T length = (top + 1 - base + TRA_MASK) / 4;
trans->tra_transactions.resize(length); trans->tra_transactions.resize(length);
} }
trans->tra_number = number; trans->tra_number = number;
trans->tra_top = top; trans->tra_top = top;
skipping to change at line 3199 skipping to change at line 3232
#ifndef SUPERSERVER_V2 #ifndef SUPERSERVER_V2
if (!dbb->readOnly()) if (!dbb->readOnly())
CCH_RELEASE(tdbb, &window); CCH_RELEASE(tdbb, &window);
#endif #endif
ERR_post(Arg::Gds(isc_lock_conflict)); ERR_post(Arg::Gds(isc_lock_conflict));
} }
// Link the transaction to the attachment block before releasing // Link the transaction to the attachment block before releasing
// header page for handling signals. // header page for handling signals.
link_transaction(tdbb, trans); trans->linkToAttachment(attachment);
try
{
#ifndef SUPERSERVER_V2 #ifndef SUPERSERVER_V2
if (!dbb->readOnly()) if (!dbb->readOnly())
CCH_RELEASE(tdbb, &window); CCH_RELEASE(tdbb, &window);
#endif #endif
if (dbb->readOnly()) if (dbb->readOnly())
{ {
// Set transaction flags to TRA_precommitted, TRA_readonly // Set transaction flags to TRA_precommitted, TRA_readonl
trans->tra_flags |= (TRA_readonly | TRA_precommitted); y
} trans->tra_flags |= (TRA_readonly | TRA_precommitted);
}
// Next, take a snapshot of all transactions between the oldest interesti
ng
// transaction and the current. Don't bother to get a snapshot for
// read-committed transactions; they use the snapshot off the dbb block
// since they need to know what is currently committed.
if (trans->tra_flags & TRA_read_committed) // Next, take a snapshot of all transactions between the oldest i
TPC_initialize_tpc(tdbb, top); nteresting
else if (top > base) // transaction and the current. Don't bother to get a snapshot f
TRA_get_inventory(tdbb, trans->tra_transactions.begin(), base, to or
p); // read-committed transactions; they use the snapshot off the dbb
block
// Next task is to find the oldest active transaction on the system. Thi // since they need to know what is currently committed.
s
// is needed for garbage collection. Things are made ever so slightly
// more complicated by the fact that existing transaction may have oldest
// actives older than they are.
Lock temp_lock(tdbb, sizeof(TraNumber), LCK_tra, trans);
trans->tra_oldest_active = number;
base = oldest & ~TRA_MASK;
oldest_active = number;
bool cleanup = !(number % TRA_ACTIVE_CLEANUP);
int oldest_state;
for (; active < top; active++)
{
if (trans->tra_flags & TRA_read_committed) if (trans->tra_flags & TRA_read_committed)
TPC_initialize_tpc(tdbb, top);
else if (top > base)
TRA_get_inventory(tdbb, trans->tra_transactions.begin(),
base, top);
// Next task is to find the oldest active transaction on the syst
em. This
// is needed for garbage collection. Things are made ever so sli
ghtly
// more complicated by the fact that existing transaction may hav
e oldest
// actives older than they are.
Lock temp_lock(tdbb, sizeof(TraNumber), LCK_tra, trans);
trans->tra_oldest_active = number;
base = oldest & ~TRA_MASK;
oldest_active = number;
bool cleanup = !(number % TRA_ACTIVE_CLEANUP);
int oldest_state;
for (; active < top; active++)
{ {
const ULONG mask = (1 << tra_active); if (trans->tra_flags & TRA_read_committed)
active = TPC_find_states(tdbb, active, top, mask, oldest_
state);
if (!active)
{ {
active = number; const ULONG mask = (1 << tra_active);
break; active = TPC_find_states(tdbb, active, top, mask,
oldest_state);
if (!active)
{
active = number;
break;
}
fb_assert(oldest_state == tra_active);
}
else
{
const ULONG byte = TRANS_OFFSET(active - base);
const USHORT shift = TRANS_SHIFT(active);
oldest_state = (trans->tra_transactions[byte] >>
shift) & TRA_MASK;
} }
fb_assert(oldest_state == tra_active);
}
else
{
const ULONG byte = TRANS_OFFSET(active - base);
const USHORT shift = TRANS_SHIFT(active);
oldest_state = (trans->tra_transactions[byte] >> shift) &
TRA_MASK;
}
if (oldest_state == tra_active) if (oldest_state == tra_active)
{
temp_lock.lck_key.lck_long = active;
TraNumber data = LCK_read_data(tdbb, &temp_lock);
if (!data)
{ {
if (cleanup) temp_lock.lck_key.lck_long = active;
TraNumber data = LCK_read_data(tdbb, &temp_lock);
if (!data)
{ {
if (TRA_wait(tdbb, trans, active, jrd_tra if (cleanup)
::tra_no_wait) == tra_committed) {
cleanup = false; if (TRA_wait(tdbb, trans, active,
continue; jrd_tra::tra_no_wait) == tra_committed)
} cleanup = false;
continue;
}
data = active; data = active;
} }
oldest_active = MIN(oldest_active, active); oldest_active = MIN(oldest_active, active);
// Find the oldest record version that cannot be garbage // Find the oldest record version that cannot be
collected yet garbage collected yet
// by taking the minimum of all all versions needed by al // by taking the minimum of all all versions need
l active transactions. ed by all active transactions.
if (data < trans->tra_oldest_active) if (data < trans->tra_oldest_active)
trans->tra_oldest_active = data; trans->tra_oldest_active = data;
// If the lock data for any active transaction matches a // If the lock data for any active transaction ma
previously tches a previously
// computed value then there is no need to continue. Ther // computed value then there is no need to contin
e can't be ue. There can't be
// an older lock data in the remaining active transaction // an older lock data in the remaining active tra
s. nsactions.
if (trans->tra_oldest_active == oldest_snapshot) if (trans->tra_oldest_active == oldest_snapshot)
break; break;
// Query the minimum lock data for all active transaction // Query the minimum lock data for all active tra
locks. nsaction locks.
// This will be the oldest active snapshot used for regul // This will be the oldest active snapshot used f
ating garbage collection. or regulating garbage collection.
data = LCK_query_data(tdbb, LCK_tra, LCK_MIN); data = LCK_query_data(tdbb, LCK_tra, LCK_MIN);
if (data && data < trans->tra_oldest_active) if (data && data < trans->tra_oldest_active)
trans->tra_oldest_active = data; trans->tra_oldest_active = data;
break; break;
}
} }
}
// Calculate attachment-local oldest active and oldest snapshot numbers // Calculate attachment-local oldest active and oldest snapshot n
// looking at current attachment's transactions only. Calculated values umbers
// are used to determine garbage collection threshold for attachment-loca // looking at current attachment's transactions only. Calculated
l values
// data such as temporary tables (GTT's). // are used to determine garbage collection threshold for attachm
ent-local
// data such as temporary tables (GTT's).
trans->tra_att_oldest_active = number; trans->tra_att_oldest_active = number;
TraNumber att_oldest_active = number; TraNumber att_oldest_active = number;
TraNumber att_oldest_snapshot = number; TraNumber att_oldest_snapshot = number;
for (jrd_tra* tx_att = attachment->att_transactions; tx_att; tx_att = tx_ for (jrd_tra* tx_att = attachment->att_transactions; tx_att; tx_a
att->tra_next) tt = tx_att->tra_next)
{ {
att_oldest_active = MIN(att_oldest_active, tx_att->tra_number); att_oldest_active = MIN(att_oldest_active, tx_att->tra_nu
att_oldest_snapshot = MIN(att_oldest_snapshot, tx_att->tra_att_ol mber);
dest_active); att_oldest_snapshot = MIN(att_oldest_snapshot, tx_att->tr
} a_att_oldest_active);
}
trans->tra_att_oldest_active = (trans->tra_flags & TRA_read_committed) ? number : att_oldest_active; trans->tra_att_oldest_active = (trans->tra_flags & TRA_read_commi tted) ? number : att_oldest_active;
if (attachment->att_oldest_snapshot < att_oldest_snapshot) if (attachment->att_oldest_snapshot < att_oldest_snapshot)
attachment->att_oldest_snapshot = att_oldest_snapshot; attachment->att_oldest_snapshot = att_oldest_snapshot;
// Put the TID of the oldest active transaction (just calculated) // Put the TID of the oldest active transaction (just calculated)
// in the new transaction's lock. // in the new transaction's lock.
// hvlad: for read-committed transaction put tra_number to prevent // hvlad: for read-committed transaction put tra_number to preven
// unnecessary blocking of garbage collection by read-committed t
// transactions // unnecessary blocking of garbage collection by read-committed
// transactions
const TraNumber lck_data = (trans->tra_flags & TRA_read_committed) ? numb er : oldest_active; const TraNumber lck_data = (trans->tra_flags & TRA_read_committed ) ? number : oldest_active;
//fb_assert(sizeof(lock->lck_data) == sizeof(lck_data)); //fb_assert(sizeof(lock->lck_data) == sizeof(lck_data));
if (lock->lck_data != (SLONG) lck_data) if (lock->lck_data != (SLONG) lck_data)
LCK_write_data(tdbb, lock, lck_data); LCK_write_data(tdbb, lock, lck_data);
// Finally, scan transactions looking for the oldest interesting transact // Finally, scan transactions looking for the oldest interesting
ion -- the oldest transaction -- the oldest
// non-commited transaction. This will not be updated immediately, but s // non-commited transaction. This will not be updated immediatel
aved until the y, but saved until the
// next update access to the header page // next update access to the header page
oldest_state = tra_committed; oldest_state = tra_committed;
for (oldest = trans->tra_oldest; oldest < top; oldest++) for (oldest = trans->tra_oldest; oldest < top; oldest++)
{
if (trans->tra_flags & TRA_read_committed)
{ {
const ULONG mask = ~((1 << tra_committed) | (1 << tra_pre if (trans->tra_flags & TRA_read_committed)
committed));
oldest = TPC_find_states(tdbb, trans->tra_oldest, top, ma
sk, oldest_state);
if (!oldest)
{ {
oldest = top; const ULONG mask = ~((1 << tra_committed) | (1 <<
break; tra_precommitted));
oldest = TPC_find_states(tdbb, trans->tra_oldest,
top, mask, oldest_state);
if (!oldest)
{
oldest = top;
break;
}
fb_assert(oldest_state != tra_committed && oldest
_state != tra_precommitted);
} }
fb_assert(oldest_state != tra_committed && oldest_state ! else
= tra_precommitted); {
} const ULONG byte = TRANS_OFFSET(oldest - base);
else const USHORT shift = TRANS_SHIFT(oldest);
{ oldest_state = (trans->tra_transactions[byte] >>
const ULONG byte = TRANS_OFFSET(oldest - base); shift) & TRA_MASK;
const USHORT shift = TRANS_SHIFT(oldest); }
oldest_state = (trans->tra_transactions[byte] >> shift) &
TRA_MASK; if (oldest_state != tra_committed && oldest_state != tra_
precommitted)
break;
} }
if (oldest_state != tra_committed && oldest_state != tra_precommi if (oldest >= top && dbb->dbb_flags & DBB_read_only)
tted) oldest = number;
break;
}
if (oldest >= top && dbb->dbb_flags & DBB_read_only) if (--oldest > dbb->dbb_oldest_transaction)
oldest = number; dbb->dbb_oldest_transaction = oldest;
if (--oldest > dbb->dbb_oldest_transaction) if (oldest_active > dbb->dbb_oldest_active)
dbb->dbb_oldest_transaction = oldest; dbb->dbb_oldest_active = oldest_active;
if (oldest_active > dbb->dbb_oldest_active) if (trans->tra_oldest_active > dbb->dbb_oldest_snapshot)
dbb->dbb_oldest_active = oldest_active; {
dbb->dbb_oldest_snapshot = trans->tra_oldest_active;
if (trans->tra_oldest_active > dbb->dbb_oldest_snapshot) if (!(dbb->dbb_flags & DBB_gc_active) && (dbb->dbb_flags
{ & DBB_gc_background))
dbb->dbb_oldest_snapshot = trans->tra_oldest_active; {
dbb->dbb_flags |= DBB_gc_pending;
dbb->dbb_gc_sem.release();
}
}
// If the transaction block is getting out of hand, force a sweep
if (!(dbb->dbb_flags & DBB_gc_active) && (dbb->dbb_flags & DBB_gc if (dbb->dbb_sweep_interval &&
_background)) (trans->tra_oldest_active > oldest) &&
(trans->tra_oldest_active - oldest > dbb->dbb_sweep_inter
val) &&
oldest_state != tra_limbo)
{ {
dbb->dbb_flags |= DBB_gc_pending; start_sweeper(tdbb);
dbb->dbb_gc_sem.release();
} }
}
// If the transaction block is getting out of hand, force a sweep // Start a 'transaction-level' savepoint, unless this is the
// system transaction, or unless the transactions doesn't want
// a savepoint to be started. This savepoint will be used to
// undo the transaction if it rolls back.
if (dbb->dbb_sweep_interval && if (trans != attachment->getSysTransaction() && !(trans->tra_flag
(trans->tra_oldest_active > oldest) && s & TRA_no_auto_undo))
(trans->tra_oldest_active - oldest > dbb->dbb_sweep_interval) && {
oldest_state != tra_limbo) VIO_start_save_point(tdbb, trans);
{ trans->tra_save_point->sav_flags |= SAV_trans_level;
start_sweeper(tdbb); }
}
// Start a 'transaction-level' savepoint, unless this is the
// system transaction, or unless the transactions doesn't want
// a savepoint to be started. This savepoint will be used to
// undo the transaction if it rolls back.
if (trans != attachment->getSysTransaction() && !(trans->tra_flags & TRA_ // if the user asked us to restart all requests in this attachmen
no_auto_undo)) t,
{ // do so now using the new transaction
VIO_start_save_point(tdbb, trans);
trans->tra_save_point->sav_flags |= SAV_trans_level;
}
// if the user asked us to restart all requests in this attachment, if (trans->tra_flags & TRA_restart_requests)
// do so now using the new transaction restart_requests(tdbb, trans);
if (trans->tra_flags & TRA_restart_requests) // If the transaction is read-only and read committed, it can be
restart_requests(tdbb, trans); // precommitted because it can't modify any records and doesn't
// need a snapshot preserved. This transaction type can run
// forever without impacting garbage collection or causing
// transaction bitmap growth.
// If the transaction is read-only and read committed, it can be if ((trans->tra_flags & TRA_readonly) && (trans->tra_flags & TRA_
// precommitted because it can't modify any records and doesn't read_committed))
// need a snapshot preserved. This transaction type can run {
// forever without impacting garbage collection or causing TRA_set_state(tdbb, trans, trans->tra_number, tra_committ
// transaction bitmap growth. ed);
LCK_release(tdbb, lock);
if ((trans->tra_flags & TRA_readonly) && (trans->tra_flags & TRA_read_com lock->lck_type = LCK_tra_pc; // note, LCK_tra_
mitted)) pc belongs to the same owner as LCK_tra
{ lock->lck_data = 0;
TRA_set_state(tdbb, trans, trans->tra_number, tra_committed); if (!LCK_lock(tdbb, lock, LCK_write, LCK_WAIT))
LCK_release(tdbb, lock); ERR_post(Arg::Gds(isc_lock_conflict));
lock->lck_type = LCK_tra_pc; // note, LCK_tra_pc belon trans->tra_flags |= TRA_precommitted;
gs to the same owner as LCK_tra }
lock->lck_data = 0;
if (!LCK_lock(tdbb, lock, LCK_write, LCK_WAIT))
ERR_post(Arg::Gds(isc_lock_conflict));
trans->tra_flags |= TRA_precommitted; if (trans->tra_flags & TRA_precommitted)
TRA_precommited(tdbb, 0, trans->tra_number);
}
catch (const Firebird::Exception&)
{
trans->unlinkFromAttachment();
throw;
} }
if (trans->tra_flags & TRA_precommitted)
TRA_precommited(tdbb, 0, trans->tra_number);
} }
jrd_tra::~jrd_tra() jrd_tra::~jrd_tra()
{ {
while (tra_undo_records.hasData()) while (tra_undo_records.hasData())
delete tra_undo_records.pop(); delete tra_undo_records.pop();
delete tra_undo_space; delete tra_undo_space;
delete tra_user_management; delete tra_user_management;
delete tra_mapping_list; delete tra_mapping_list;
skipping to change at line 3457 skipping to change at line 3499
tra_interface->setHandle(NULL); tra_interface->setHandle(NULL);
tra_interface->release(); tra_interface->release();
} }
if (tra_autonomous_pool) if (tra_autonomous_pool)
MemoryPool::deletePool(tra_autonomous_pool); MemoryPool::deletePool(tra_autonomous_pool);
delete tra_sec_db_context; delete tra_sec_db_context;
} }
JTransaction* jrd_tra::getInterface() JTransaction* jrd_tra::getInterface(bool create)
{ {
if (!tra_interface) if (!tra_interface && create)
{ {
tra_flags |= TRA_own_interface; tra_flags |= TRA_own_interface;
tra_interface = FB_NEW JTransaction(this, tra_attachment->getStab le()); tra_interface = FB_NEW JTransaction(this, tra_attachment->getStab le());
tra_interface->addRef(); tra_interface->addRef();
} }
return tra_interface; return tra_interface;
} }
void jrd_tra::setInterface(JTransaction* jt) void jrd_tra::setInterface(JTransaction* jt)
skipping to change at line 3537 skipping to change at line 3579
void jrd_tra::releaseAutonomousPool(MemoryPool* toRelease) void jrd_tra::releaseAutonomousPool(MemoryPool* toRelease)
{ {
fb_assert(tra_autonomous_pool == toRelease); fb_assert(tra_autonomous_pool == toRelease);
if (++tra_autonomous_cnt > TRA_AUTONOMOUS_PER_POOL) if (++tra_autonomous_cnt > TRA_AUTONOMOUS_PER_POOL)
{ {
MemoryPool::deletePool(tra_autonomous_pool); MemoryPool::deletePool(tra_autonomous_pool);
tra_autonomous_pool = NULL; tra_autonomous_pool = NULL;
} }
} }
void jrd_tra::checkBlob(thread_db* tdbb, const bid* blob_id, bool punt)
{
USHORT rel_id = blob_id->bid_internal.bid_relation_id;
if ((tra_attachment->isGbak()) ||
tra_attachment->att_flags & ATT_garbage_collector ||
tra_attachment->att_user->locksmith() ||
rel_id == 0)
{
return;
}
if (!tra_blobs->locate(blob_id->bid_temp_id()) &&
!tra_fetched_blobs.locate(*blob_id))
{
vec<jrd_rel*>* vector = tra_attachment->att_relations;
jrd_rel* blb_relation;
if (rel_id < vector->count() && (blb_relation = (*vector)[rel_id]
))
{
if (blb_relation->rel_security_name.isEmpty())
MET_scan_relation(tdbb, blb_relation);
SecurityClass* s_class = SCL_get_class(tdbb, blb_relation
->rel_security_name.c_str());
if (!s_class)
return;
switch (s_class->scl_blb_access)
{
case SecurityClass::BA_UNKNOWN:
// Relation has not been checked for access right
s
try
{
ThreadStatusGuard status_vector(tdbb);
SCL_check_access(tdbb, s_class, 0, 0, NUL
L, SCL_select, SCL_object_table, false,
blb_relation->rel_name);
s_class->scl_blb_access = SecurityClass::
BA_SUCCESS;
}
catch (const Exception& ex)
{
StaticStatusVector status;
ex.stuffException(status);
if (status[1] != isc_no_priv)
throw;
// We don't have access to this relation
s_class->scl_blb_access = SecurityClass::
BA_FAILURE;
if (punt)
throw;
// but someone else has (SP, view)
// store Blob ID as allowed in this trans
action
tra_fetched_blobs.add(*blob_id);
}
break;
case SecurityClass::BA_FAILURE:
// Relation has been checked earlier and check wa
s failed
if (punt)
ERR_post(Arg::Gds(isc_no_priv) << Arg::St
r("SELECT") <<
Arg::Str("TABLE") <<
Arg::Str(blb_relation->rel_name))
;
else
tra_fetched_blobs.add(*blob_id);
break;
case SecurityClass::BA_SUCCESS:
// do nothing
break;
default:
fb_assert(false);
}
}
}
}
/// class TraceSweepEvent /// class TraceSweepEvent
TraceSweepEvent::TraceSweepEvent(thread_db* tdbb) TraceSweepEvent::TraceSweepEvent(thread_db* tdbb)
{ {
m_tdbb = tdbb; m_tdbb = tdbb;
WIN window(HEADER_PAGE_NUMBER); WIN window(HEADER_PAGE_NUMBER);
Ods::header_page* header = (Ods::header_page*) CCH_FETCH(m_tdbb, &window, LCK_read, pag_header); Ods::header_page* header = (Ods::header_page*) CCH_FETCH(m_tdbb, &window, LCK_read, pag_header);
m_sweep_info.update(header); m_sweep_info.update(header);
 End of changes. 83 change blocks. 
307 lines changed or deleted 453 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)