vio.cpp (Firebird-3.0.2.32703-0.tar.bz2) | : | vio.cpp (Firebird-3.0.4.33054-0.tar.bz2) | ||
---|---|---|---|---|
skipping to change at line 115 | skipping to change at line 115 | |||
static void expunge(thread_db*, record_param*, const jrd_tra*, ULONG); | static void expunge(thread_db*, record_param*, const jrd_tra*, ULONG); | |||
static bool dfw_should_know(record_param* org_rpb, record_param* new_rpb, | static bool dfw_should_know(record_param* org_rpb, record_param* new_rpb, | |||
USHORT irrelevant_field, bool void_update_is_relevant = false); | USHORT irrelevant_field, bool void_update_is_relevant = false); | |||
static void garbage_collect(thread_db*, record_param*, ULONG, RecordStack&); | static void garbage_collect(thread_db*, record_param*, ULONG, RecordStack&); | |||
static void garbage_collect_idx(thread_db*, record_param*, Record*, Record*); | static void garbage_collect_idx(thread_db*, record_param*, Record*, Record*); | |||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
#include <stdio.h> | #include <stdio.h> | |||
#include <stdarg.h> | #include <stdarg.h> | |||
int vio_debug_flag = 0; | int vio_debug_flag = DEBUG_TRACE_ALL_INFO; | |||
void VIO_trace(int level, const char* format, ...) | void VIO_trace(int level, const char* format, ...) | |||
{ | { | |||
if (vio_debug_flag <= level) | if (vio_debug_flag <= level) | |||
return; | return; | |||
Firebird::string buffer; | Firebird::string buffer; | |||
va_list params; | va_list params; | |||
va_start(params, format); | va_start(params, format); | |||
buffer.vprintf(format, params); | buffer.vprintf(format, params); | |||
skipping to change at line 168 | skipping to change at line 168 | |||
record_param*, record_param*, PageStack&, bool); | record_param*, record_param*, PageStack&, bool); | |||
static void protect_system_table_insert(thread_db* tdbb, const jrd_req* req, con st jrd_rel* relation, | static void protect_system_table_insert(thread_db* tdbb, const jrd_req* req, con st jrd_rel* relation, | |||
bool force_flag = false); | bool force_flag = false); | |||
static void protect_system_table_delupd(thread_db* tdbb, const jrd_rel* relation , const char* operation, | static void protect_system_table_delupd(thread_db* tdbb, const jrd_rel* relation , const char* operation, | |||
bool force_flag = false); | bool force_flag = false); | |||
static void purge(thread_db*, record_param*); | static void purge(thread_db*, record_param*); | |||
static void replace_record(thread_db*, record_param*, PageStack*, const jrd_tra* ); | static void replace_record(thread_db*, record_param*, PageStack*, const jrd_tra* ); | |||
static void refresh_fk_fields(thread_db*, Record*, record_param*, record_param*) ; | static void refresh_fk_fields(thread_db*, Record*, record_param*, record_param*) ; | |||
static SSHORT set_metadata_id(thread_db*, Record*, USHORT, drq_type_t, const cha r*); | static SSHORT set_metadata_id(thread_db*, Record*, USHORT, drq_type_t, const cha r*); | |||
static void set_nbackup_id(thread_db*, Record*, USHORT, drq_type_t, const char*) ; | ||||
static void set_owner_name(thread_db*, Record*, USHORT); | static void set_owner_name(thread_db*, Record*, USHORT); | |||
static bool set_security_class(thread_db*, Record*, USHORT); | static bool set_security_class(thread_db*, Record*, USHORT); | |||
static void set_system_flag(thread_db*, Record*, USHORT); | static void set_system_flag(thread_db*, Record*, USHORT); | |||
static void update_in_place(thread_db*, jrd_tra*, record_param*, record_param*); | static void update_in_place(thread_db*, jrd_tra*, record_param*, record_param*); | |||
static void verb_post(thread_db*, jrd_tra*, record_param*, Record*, const bool, const bool); | static void verb_post(thread_db*, jrd_tra*, record_param*, Record*, const bool, const bool); | |||
static bool assert_gc_enabled(const jrd_tra* transaction, const jrd_rel* relatio n) | static bool assert_gc_enabled(const jrd_tra* transaction, const jrd_rel* relatio n) | |||
{ | { | |||
/************************************** | /************************************** | |||
* | * | |||
skipping to change at line 426 | skipping to change at line 427 | |||
* But this record is doomed, and if we don't get it somebody | * But this record is doomed, and if we don't get it somebody | |||
* will. | * will. | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
Database* dbb = tdbb->getDatabase(); | Database* dbb = tdbb->getDatabase(); | |||
CHECK_DBB(dbb); | CHECK_DBB(dbb); | |||
fb_assert(assert_gc_enabled(transaction, rpb->rpb_relation)); | fb_assert(assert_gc_enabled(transaction, rpb->rpb_relation)); | |||
jrd_rel* const relation = rpb->rpb_relation; | ||||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
VIO_trace(DEBUG_WRITES, | VIO_trace(DEBUG_WRITES, | |||
"VIO_backout (record_param %" QUADFORMAT"d, transaction %" SQUADF | "VIO_backout (rel_id %u, record_param %" SQUADFORMAT", transactio | |||
ORMAT")\n", | n %" SQUADFORMAT")\n", | |||
rpb->rpb_number.getValue(), transaction ? transaction->tra_number | relation->rel_id, rpb->rpb_number.getValue(), transaction ? trans | |||
: 0); | action->tra_number : 0); | |||
#endif | #endif | |||
jrd_rel* const relation = rpb->rpb_relation; | ||||
// If there is data in the record, fetch it now. If the old version | // If there is data in the record, fetch it now. If the old version | |||
// is a differences record, we will need it sooner. In any case, we | // is a differences record, we will need it sooner. In any case, we | |||
// will need it eventually to clean up blobs and indices. If the record | // will need it eventually to clean up blobs and indices. If the record | |||
// has changed in between, stop now before things get worse. | // has changed in between, stop now before things get worse. | |||
record_param temp = *rpb; | record_param temp = *rpb; | |||
if (!DPM_get(tdbb, &temp, LCK_read)) | if (!DPM_get(tdbb, &temp, LCK_read)) | |||
return; | return; | |||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
skipping to change at line 552 | skipping to change at line 553 | |||
} | } | |||
} | } | |||
// Re-fetch the record. | // Re-fetch the record. | |||
if (!DPM_get(tdbb, rpb, LCK_write)) | if (!DPM_get(tdbb, rpb, LCK_write)) | |||
return; | return; | |||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
if (temp2.rpb_b_page != rpb->rpb_b_page || temp.rpb_b_line != rpb->rpb_b_ line || | if (temp2.rpb_b_page != rpb->rpb_b_page || temp.rpb_b_line != rpb->rpb_b_ line || | |||
temp.rpb_transaction_nr != rpb->rpb_transaction_nr) | temp.rpb_transaction_nr != rpb->rpb_transaction_nr) | |||
{ | { | |||
VIO_trace(DEBUG_WRITES_INFO, | VIO_trace(DEBUG_WRITES_INFO, | |||
" record changed!)\n"); | " record changed!)\n"); | |||
} | } | |||
#endif | #endif | |||
// If the record is in any way suspicious, release the record and give up . | // If the record is in any way suspicious, release the record and give up . | |||
if (rpb->rpb_b_page != temp2.rpb_b_page || rpb->rpb_b_line != temp2.rpb_b _line || | if (rpb->rpb_b_page != temp2.rpb_b_page || rpb->rpb_b_line != temp2.rpb_b _line || | |||
rpb->rpb_transaction_nr != temp2.rpb_transaction_nr) | rpb->rpb_transaction_nr != temp2.rpb_transaction_nr) | |||
skipping to change at line 612 | skipping to change at line 613 | |||
fb_assert(rpb->rpb_flags & rpb_gc_active); | fb_assert(rpb->rpb_flags & rpb_gc_active); | |||
rpb->rpb_flags &= ~rpb_gc_active; | rpb->rpb_flags &= ~rpb_gc_active; | |||
temp2 = *rpb; | temp2 = *rpb; | |||
rpb->rpb_undo = old_data; | rpb->rpb_undo = old_data; | |||
if (rpb->rpb_flags & rpb_delta) | if (rpb->rpb_flags & rpb_delta) | |||
rpb->rpb_prior = data; | rpb->rpb_prior = data; | |||
} | } | |||
gcLockGuard.release(); | ||||
delete_record(tdbb, rpb, 0, NULL); | delete_record(tdbb, rpb, 0, NULL); | |||
tdbb->bumpRelStats(RuntimeStatistics::RECORD_BACKOUTS, relation-> rel_id); | tdbb->bumpRelStats(RuntimeStatistics::RECORD_BACKOUTS, relation-> rel_id); | |||
return; | return; | |||
} | } | |||
// If both record versions are on the same page, things are a little simp ler | // If both record versions are on the same page, things are a little simp ler | |||
samePage = (rpb->rpb_page == temp.rpb_page && !rpb->rpb_prior); | samePage = (rpb->rpb_page == temp.rpb_page && !rpb->rpb_prior); | |||
deleted = (temp2.rpb_flags & rpb_deleted); | deleted = (temp2.rpb_flags & rpb_deleted); | |||
skipping to change at line 738 | skipping to change at line 739 | |||
Jrd::Attachment* const attachment = transaction->tra_attachment; | Jrd::Attachment* const attachment = transaction->tra_attachment; | |||
jrd_rel* const relation = rpb->rpb_relation; | jrd_rel* const relation = rpb->rpb_relation; | |||
const bool gcPolicyCooperative = dbb->dbb_flags & DBB_gc_cooperative; | const bool gcPolicyCooperative = dbb->dbb_flags & DBB_gc_cooperative; | |||
const bool gcPolicyBackground = dbb->dbb_flags & DBB_gc_background; | const bool gcPolicyBackground = dbb->dbb_flags & DBB_gc_background; | |||
const TraNumber oldest_snapshot = relation->isTemporary() ? | const TraNumber oldest_snapshot = relation->isTemporary() ? | |||
attachment->att_oldest_snapshot : transaction->tra_oldest_active; | attachment->att_oldest_snapshot : transaction->tra_oldest_active; | |||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
VIO_trace(DEBUG_TRACE_ALL, | VIO_trace(DEBUG_TRACE_ALL, | |||
"VIO_chase_record_version (record_param %" QUADFORMAT"d, transact ion %" | "VIO_chase_record_version (rel_id %u, record_param %" QUADFORMAT" d, transaction %" | |||
SQUADFORMAT", pool %p)\n", | SQUADFORMAT", pool %p)\n", | |||
relation->rel_id, | ||||
rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0, | rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0, | |||
(void*) pool); | (void*) pool); | |||
VIO_trace(DEBUG_TRACE_ALL_INFO, | VIO_trace(DEBUG_TRACE_ALL_INFO, | |||
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | |||
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | |||
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | |||
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | |||
rpb->rpb_f_page, rpb->rpb_f_line); | rpb->rpb_f_page, rpb->rpb_f_line); | |||
#endif | #endif | |||
skipping to change at line 763 | skipping to change at line 765 | |||
// Reset (if appropriate) the garbage collect active flag to reattempt th e backout | // Reset (if appropriate) the garbage collect active flag to reattempt th e backout | |||
if (rpb->rpb_flags & rpb_gc_active) | if (rpb->rpb_flags & rpb_gc_active) | |||
checkGCActive(tdbb, rpb, state); | checkGCActive(tdbb, rpb, state); | |||
// Take care about modifications performed by our own transaction | // Take care about modifications performed by our own transaction | |||
rpb->rpb_runtime_flags &= ~RPB_UNDO_FLAGS; | rpb->rpb_runtime_flags &= ~RPB_UNDO_FLAGS; | |||
int forceBack = 0; | int forceBack = 0; | |||
if (rpb->rpb_stream_flags & RPB_s_unstable) | ||||
noundo = true; | ||||
if (state == tra_us && !noundo && !(transaction->tra_flags & TRA_system)) | if (state == tra_us && !noundo && !(transaction->tra_flags & TRA_system)) | |||
{ | { | |||
switch (get_undo_data(tdbb, transaction, rpb, pool)) | switch (get_undo_data(tdbb, transaction, rpb, pool)) | |||
{ | { | |||
case udExists: | case udExists: | |||
return true; | return true; | |||
case udForceBack: | case udForceBack: | |||
forceBack = 1; | forceBack = 1; | |||
break; | break; | |||
case udForceTwice: | case udForceTwice: | |||
skipping to change at line 1281 | skipping to change at line 1286 | |||
{ | { | |||
DSC org_desc, new_desc; | DSC org_desc, new_desc; | |||
for (USHORT i = 0; i < new_record->getFormat()->fmt_count; i++) | for (USHORT i = 0; i < new_record->getFormat()->fmt_count; i++) | |||
{ | { | |||
new_record->clearNull(i); | new_record->clearNull(i); | |||
if (EVL_field(new_rpb->rpb_relation, new_record, i, &new_ desc)) | if (EVL_field(new_rpb->rpb_relation, new_record, i, &new_ desc)) | |||
{ | { | |||
if (EVL_field(org_rpb->rpb_relation, org_record, i, &org_desc)) | if (EVL_field(org_rpb->rpb_relation, org_record, i, &org_desc)) | |||
MOV_move(tdbb, &org_desc, &new_desc); | { | |||
if (DTYPE_IS_BLOB_OR_QUAD(org_desc.dsc_dt | ||||
ype) || DTYPE_IS_BLOB_OR_QUAD(new_desc.dsc_dtype)) | ||||
Jrd::blb::move(tdbb, &org_desc, & | ||||
new_desc, new_rpb, i); | ||||
else | ||||
MOV_move(tdbb, &org_desc, &new_de | ||||
sc); | ||||
} | ||||
else | else | |||
{ | { | |||
new_record->setNull(i); | new_record->setNull(i); | |||
if (new_desc.dsc_dtype) | if (new_desc.dsc_dtype) | |||
memset(new_desc.dsc_address, 0, n ew_desc.dsc_length); | memset(new_desc.dsc_address, 0, n ew_desc.dsc_length); | |||
} | } | |||
} | } | |||
} | } | |||
} | } | |||
skipping to change at line 1312 | skipping to change at line 1322 | |||
* Functional description | * Functional description | |||
* Given an active record parameter block, fetch the full record. | * Given an active record parameter block, fetch the full record. | |||
* | * | |||
* This routine is called with an active record_param and exits with | * This routine is called with an active record_param and exits with | |||
* an INactive record_param. Yes, Virginia, getting the data for a | * an INactive record_param. Yes, Virginia, getting the data for a | |||
* record means losing control of the record. This turns out | * record means losing control of the record. This turns out | |||
* to matter a lot. | * to matter a lot. | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
jrd_rel* const relation = rpb->rpb_relation; | ||||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
VIO_trace(DEBUG_READS, | VIO_trace(DEBUG_READS, | |||
"VIO_data (record_param %" QUADFORMAT"d, pool %p)\n", | "VIO_data (rel_id %u, record_param %" QUADFORMAT"d, pool %p)\n", | |||
rpb->rpb_number.getValue(), (void*) pool); | relation->rel_id, rpb->rpb_number.getValue(), (void*)pool); | |||
VIO_trace(DEBUG_READS_INFO, | VIO_trace(DEBUG_READS_INFO, | |||
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | |||
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | |||
rpb->rpb_page, rpb->rpb_line, | rpb->rpb_page, rpb->rpb_line, | |||
rpb->rpb_transaction_nr, rpb->rpb_flags, | rpb->rpb_transaction_nr, rpb->rpb_flags, | |||
rpb->rpb_b_page, rpb->rpb_b_line, | rpb->rpb_b_page, rpb->rpb_b_line, | |||
rpb->rpb_f_page, rpb->rpb_f_line); | rpb->rpb_f_page, rpb->rpb_f_line); | |||
#endif | #endif | |||
// If we're not already set up for this format version number, find | // If we're not already set up for this format version number, find | |||
// the format block and set up the record block. This is a performance | // the format block and set up the record block. This is a performance | |||
// optimization. | // optimization. | |||
jrd_rel* const relation = rpb->rpb_relation; | ||||
Record* const record = VIO_record(tdbb, rpb, NULL, pool); | Record* const record = VIO_record(tdbb, rpb, NULL, pool); | |||
const Format* const format = record->getFormat(); | const Format* const format = record->getFormat(); | |||
// If the record is a delta version, start with data from prior record. | // If the record is a delta version, start with data from prior record. | |||
UCHAR* tail; | UCHAR* tail; | |||
const UCHAR* tail_end; | const UCHAR* tail_end; | |||
UCHAR differences[MAX_DIFFERENCES]; | UCHAR differences[MAX_DIFFERENCES]; | |||
// Primary record version not uses prior version | // Primary record version not uses prior version | |||
Record* prior = (rpb->rpb_flags & rpb_chained) ? rpb->rpb_prior : NULL; | Record* prior = (rpb->rpb_flags & rpb_chained) ? rpb->rpb_prior : NULL; | |||
skipping to change at line 1438 | skipping to change at line 1449 | |||
* | * | |||
* This routine is entered with an inactive | * This routine is entered with an inactive | |||
* record_param and leaves having created an erased | * record_param and leaves having created an erased | |||
* stub. | * stub. | |||
* | * | |||
**************************************/ | **************************************/ | |||
MetaName object_name, package_name; | MetaName object_name, package_name; | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
jrd_req* request = tdbb->getRequest(); | jrd_req* request = tdbb->getRequest(); | |||
jrd_rel* relation = rpb->rpb_relation; | ||||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
VIO_trace(DEBUG_WRITES, | VIO_trace(DEBUG_WRITES, | |||
"VIO_erase (record_param %" QUADFORMAT"d, transaction %" SQUADFOR | "VIO_erase (rel_id %u, record_param %" QUADFORMAT"d, transaction | |||
MAT")\n", | %" SQUADFORMAT")\n", | |||
rpb->rpb_number.getValue(), transaction->tra_number); | relation->rel_id, rpb->rpb_number.getValue(), transaction->tra_nu | |||
mber); | ||||
VIO_trace(DEBUG_WRITES_INFO, | VIO_trace(DEBUG_WRITES_INFO, | |||
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | |||
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | |||
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | |||
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | |||
rpb->rpb_f_page, rpb->rpb_f_line); | rpb->rpb_f_page, rpb->rpb_f_line); | |||
#endif | #endif | |||
skipping to change at line 1477 | skipping to change at line 1489 | |||
if (transaction->tra_flags & TRA_system) | if (transaction->tra_flags & TRA_system) | |||
{ | { | |||
// hvlad: what if record was created\modified by user tx also, | // hvlad: what if record was created\modified by user tx also, | |||
// i.e. if there is backversion ??? | // i.e. if there is backversion ??? | |||
VIO_backout(tdbb, rpb, transaction); | VIO_backout(tdbb, rpb, transaction); | |||
return; | return; | |||
} | } | |||
transaction->tra_flags |= TRA_write; | transaction->tra_flags |= TRA_write; | |||
jrd_rel* relation = rpb->rpb_relation; | ||||
check_gbak_cheating_delete(tdbb, relation); | check_gbak_cheating_delete(tdbb, relation); | |||
// If we're about to erase a system relation, check to make sure | // If we're about to erase a system relation, check to make sure | |||
// everything is completely kosher. | // everything is completely kosher. | |||
DSC desc, desc2; | DSC desc, desc2; | |||
if (needDfw(tdbb, transaction)) | if (needDfw(tdbb, transaction)) | |||
{ | { | |||
skipping to change at line 1638 | skipping to change at line 1649 | |||
EVL_field(0, rpb->rpb_record, f_fun_id, &desc2); | EVL_field(0, rpb->rpb_record, f_fun_id, &desc2); | |||
id = MOV_get_long(&desc2, 0); | id = MOV_get_long(&desc2, 0); | |||
DFW_post_work(transaction, dfw_delete_function, &desc, id , package_name); | DFW_post_work(transaction, dfw_delete_function, &desc, id , package_name); | |||
Function::lookup(tdbb, id, false, true, 0); | Function::lookup(tdbb, id, false, true, 0); | |||
break; | break; | |||
case rel_indices: | case rel_indices: | |||
protect_system_table_delupd(tdbb, relation, "DELETE"); | protect_system_table_delupd(tdbb, relation, "DELETE"); | |||
EVL_field(0, rpb->rpb_record, f_idx_relation, &desc); | EVL_field(0, rpb->rpb_record, f_idx_relation, &desc); | |||
SCL_check_relation(tdbb, &desc, SCL_control); | EVL_field(0, rpb->rpb_record, f_idx_sys_flag, &desc2); | |||
SCL_check_relation(tdbb, &desc, SCL_control, MOV_get_long | ||||
(&desc2, 0) == 1); | ||||
EVL_field(0, rpb->rpb_record, f_idx_id, &desc2); | EVL_field(0, rpb->rpb_record, f_idx_id, &desc2); | |||
if ( (id = MOV_get_long(&desc2, 0)) ) | if ( (id = MOV_get_long(&desc2, 0)) ) | |||
{ | { | |||
MetaName relation_name; | MetaName relation_name; | |||
MOV_get_metaname(&desc, relation_name); | MOV_get_metaname(&desc, relation_name); | |||
r2 = MET_lookup_relation(tdbb, relation_name); | r2 = MET_lookup_relation(tdbb, relation_name); | |||
fb_assert(r2); | fb_assert(r2); | |||
DSC idx_name; | DSC idx_name; | |||
EVL_field(0, rpb->rpb_record, f_idx_name, &idx_na me); | EVL_field(0, rpb->rpb_record, f_idx_name, &idx_na me); | |||
skipping to change at line 1974 | skipping to change at line 1986 | |||
* record. This is called during index creation to avoid | * record. This is called during index creation to avoid | |||
* unnecessary work as well as false duplicate records. | * unnecessary work as well as false duplicate records. | |||
* | * | |||
* If the record complete goes away, return false. | * If the record complete goes away, return false. | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
Jrd::Attachment* attachment = transaction->tra_attachment; | Jrd::Attachment* attachment = transaction->tra_attachment; | |||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
jrd_rel* relation = rpb->rpb_relation; | ||||
VIO_trace(DEBUG_TRACE, | VIO_trace(DEBUG_TRACE, | |||
"VIO_garbage_collect (record_param %" QUADFORMAT"d, transaction % " | "VIO_garbage_collect (rel_id %u, record_param %" QUADFORMAT"d, tr ansaction %" | |||
SQUADFORMAT")\n", | SQUADFORMAT")\n", | |||
rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0); | relation->rel_id, rpb->rpb_number.getValue(), transaction ? trans action->tra_number : 0); | |||
VIO_trace(DEBUG_TRACE_INFO, | VIO_trace(DEBUG_TRACE_INFO, | |||
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | |||
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | |||
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | |||
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | |||
rpb->rpb_f_page, rpb->rpb_f_line); | rpb->rpb_f_page, rpb->rpb_f_line); | |||
#endif | #endif | |||
jrd_rel::GCShared gcGuard(tdbb, rpb->rpb_relation); | jrd_rel::GCShared gcGuard(tdbb, rpb->rpb_relation); | |||
skipping to change at line 2107 | skipping to change at line 2120 | |||
* | * | |||
************************************** | ************************************** | |||
* | * | |||
* Functional description | * Functional description | |||
* Get a specific record from a relation. | * Get a specific record from a relation. | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
jrd_rel* relation = rpb->rpb_relation; | ||||
VIO_trace(DEBUG_READS, | VIO_trace(DEBUG_READS, | |||
"VIO_get (record_param %" QUADFORMAT"d, transaction %" SQUADFORMA | "VIO_get (rel_id %u, record_param %" QUADFORMAT"d, transaction %" | |||
T", pool %p)\n", | SQUADFORMAT", pool %p)\n", | |||
rpb->rpb_number.getValue(), transaction ? transaction->tra_number | relation->rel_id, rpb->rpb_number.getValue(), transaction ? trans | |||
: 0, | action->tra_number : 0, | |||
(void*) pool); | (void*) pool); | |||
#endif | #endif | |||
// Fetch data page from a modify/erase input stream with a write | // Fetch data page from a modify/erase input stream with a write | |||
// lock. This saves an upward conversion to a write lock when | // lock. This saves an upward conversion to a write lock when | |||
// refetching the page in the context of the output stream. | // refetching the page in the context of the output stream. | |||
const USHORT lock_type = (rpb->rpb_stream_flags & RPB_s_update) ? LCK_wri te : LCK_read; | const USHORT lock_type = (rpb->rpb_stream_flags & RPB_s_update) ? LCK_wri te : LCK_read; | |||
if (!DPM_get(tdbb, rpb, lock_type) || | if (!DPM_get(tdbb, rpb, lock_type) || | |||
skipping to change at line 2185 | skipping to change at line 2199 | |||
* looking to see if a primary key/unique key exists. For a | * looking to see if a primary key/unique key exists. For a | |||
* no wait transaction, if state of transaction inserting primary key | * no wait transaction, if state of transaction inserting primary key | |||
* record is tra_active, we should not see the uncommitted record | * record is tra_active, we should not see the uncommitted record | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
Attachment* const attachment = tdbb->getAttachment(); | Attachment* const attachment = tdbb->getAttachment(); | |||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
jrd_rel* relation = rpb->rpb_relation; | ||||
VIO_trace(DEBUG_TRACE, | VIO_trace(DEBUG_TRACE, | |||
"VIO_get_current (record_param %" QUADFORMAT"d, transaction %" SQ | "VIO_get_current (rel_id %u, record_param %" QUADFORMAT"d, transa | |||
UADFORMAT", pool %p)\n", | ction %" SQUADFORMAT", pool %p)\n", | |||
rpb->rpb_number.getValue(), transaction ? transaction->tra_number | relation->rel_id, rpb->rpb_number.getValue(), transaction ? trans | |||
: 0, | action->tra_number : 0, | |||
(void*) pool); | (void*) pool); | |||
#endif | #endif | |||
rec_tx_active = false; | rec_tx_active = false; | |||
bool counted = false; | bool counted = false; | |||
while (true) | while (true) | |||
{ | { | |||
// If the record doesn't exist, no problem. | // If the record doesn't exist, no problem. | |||
skipping to change at line 2320 | skipping to change at line 2335 | |||
if (rpb->rpb_flags & rpb_deleted) | if (rpb->rpb_flags & rpb_deleted) | |||
{ | { | |||
CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); | CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); | |||
return false; | return false; | |||
} | } | |||
VIO_data(tdbb, rpb, pool); | VIO_data(tdbb, rpb, pool); | |||
return true; | return true; | |||
case tra_limbo: | ||||
if (!(transaction->tra_flags & TRA_ignore_limbo)) | ||||
ERR_post(Arg::Gds(isc_rec_in_limbo) << Arg::Num(r | ||||
pb->rpb_transaction_nr)); | ||||
// fall thru | ||||
case tra_active: | case tra_active: | |||
// clear lock error from status vector | // clear lock error from status vector | |||
fb_utils::init_status(tdbb->tdbb_status_vector); | fb_utils::init_status(tdbb->tdbb_status_vector); | |||
rec_tx_active = true; | rec_tx_active = true; | |||
// 1. if record just inserted | // 1. if record just inserted | |||
// then FK can't reference it but PK must check it 's new value | // then FK can't reference it but PK must check it 's new value | |||
// 2. if record just deleted | // 2. if record just deleted | |||
// then FK can't reference it but PK must check it's o ld value | // then FK can't reference it but PK must check it's o ld value | |||
// 3. if record just modified | // 3. if record just modified | |||
skipping to change at line 2364 | skipping to change at line 2384 | |||
{ | { | |||
jrd_rel::GCShared gcGuard(tdbb, rpb->rpb_relation ); | jrd_rel::GCShared gcGuard(tdbb, rpb->rpb_relation ); | |||
if (!gcGuard.gcEnabled()) | if (!gcGuard.gcEnabled()) | |||
return !foreign_key; | return !foreign_key; | |||
VIO_backout(tdbb, rpb, transaction); | VIO_backout(tdbb, rpb, transaction); | |||
} | } | |||
break; | break; | |||
case tra_limbo: | ||||
BUGCHECK(184); // limbo impossible | ||||
break; | ||||
default: | default: | |||
fb_assert(false); | fb_assert(false); | |||
} | } | |||
} | } | |||
return !(rpb->rpb_flags & rpb_deleted); | return !(rpb->rpb_flags & rpb_deleted); | |||
} | } | |||
void VIO_init(thread_db* tdbb) | void VIO_init(thread_db* tdbb) | |||
{ | { | |||
skipping to change at line 2500 | skipping to change at line 2516 | |||
* | * | |||
************************************** | ************************************** | |||
* | * | |||
* Functional description | * Functional description | |||
* Modify an existing record. | * Modify an existing record. | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
MetaName object_name, package_name; | MetaName object_name, package_name; | |||
jrd_rel* relation = org_rpb->rpb_relation; | ||||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
VIO_trace(DEBUG_WRITES, | VIO_trace(DEBUG_WRITES, | |||
"VIO_modify (org_rpb %" QUADFORMAT"d, new_rpb %" QUADFORMAT"d, " | "VIO_modify (rel_id %u, org_rpb %" QUADFORMAT"d, new_rpb %" QUADF ORMAT"d, " | |||
"transaction %" SQUADFORMAT")\n", | "transaction %" SQUADFORMAT")\n", | |||
org_rpb->rpb_number.getValue(), new_rpb->rpb_number.getValue(), | relation->rel_id, org_rpb->rpb_number.getValue(), new_rpb->rpb_nu mber.getValue(), | |||
transaction ? transaction->tra_number : 0); | transaction ? transaction->tra_number : 0); | |||
VIO_trace(DEBUG_WRITES_INFO, | VIO_trace(DEBUG_WRITES_INFO, | |||
" old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | " old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | |||
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | |||
org_rpb->rpb_page, org_rpb->rpb_line, org_rpb->rpb_transaction_nr , | org_rpb->rpb_page, org_rpb->rpb_line, org_rpb->rpb_transaction_nr , | |||
org_rpb->rpb_flags, org_rpb->rpb_b_page, org_rpb->rpb_b_line, | org_rpb->rpb_flags, org_rpb->rpb_b_page, org_rpb->rpb_b_line, | |||
org_rpb->rpb_f_page, org_rpb->rpb_f_line); | org_rpb->rpb_f_page, org_rpb->rpb_f_line); | |||
#endif | #endif | |||
jrd_rel* relation = org_rpb->rpb_relation; | ||||
transaction->tra_flags |= TRA_write; | transaction->tra_flags |= TRA_write; | |||
new_rpb->rpb_transaction_nr = transaction->tra_number; | new_rpb->rpb_transaction_nr = transaction->tra_number; | |||
new_rpb->rpb_flags = 0; | new_rpb->rpb_flags = 0; | |||
new_rpb->getWindow(tdbb).win_flags = WIN_secondary; | new_rpb->getWindow(tdbb).win_flags = WIN_secondary; | |||
// If the stream was sorted, the various fields in the rpb are | // If the stream was sorted, the various fields in the rpb are | |||
// probably junk. Just to make sure that everything is cool, | // probably junk. Just to make sure that everything is cool, | |||
// refetch and release the record. | // refetch and release the record. | |||
if (org_rpb->rpb_runtime_flags & (RPB_refetch | RPB_undo_read)) | if (org_rpb->rpb_runtime_flags & (RPB_refetch | RPB_undo_read)) | |||
skipping to change at line 2983 | skipping to change at line 2999 | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
// Fetch data page from a modify/erase input stream with a write | // Fetch data page from a modify/erase input stream with a write | |||
// lock. This saves an upward conversion to a write lock when | // lock. This saves an upward conversion to a write lock when | |||
// refetching the page in the context of the output stream. | // refetching the page in the context of the output stream. | |||
const USHORT lock_type = (rpb->rpb_stream_flags & RPB_s_update) ? LCK_wri te : LCK_read; | const USHORT lock_type = (rpb->rpb_stream_flags & RPB_s_update) ? LCK_wri te : LCK_read; | |||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
jrd_rel* relation = rpb->rpb_relation; | ||||
VIO_trace(DEBUG_TRACE, | VIO_trace(DEBUG_TRACE, | |||
"VIO_next_record (record_param %" QUADFORMAT"d, transaction %" SQ | "VIO_next_record (rel_id %u, record_param %" QUADFORMAT"d, transa | |||
UADFORMAT", pool %p)\n", | ction %" SQUADFORMAT", pool %p)\n", | |||
rpb->rpb_number.getValue(), transaction ? transaction->tra_number | relation->rel_id, rpb->rpb_number.getValue(), transaction ? trans | |||
: 0, | action->tra_number : 0, | |||
(void*) pool); | (void*) pool); | |||
VIO_trace(DEBUG_TRACE_INFO, | VIO_trace(DEBUG_TRACE_INFO, | |||
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | |||
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | |||
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | |||
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | |||
rpb->rpb_f_page, rpb->rpb_f_line); | rpb->rpb_f_page, rpb->rpb_f_line); | |||
#endif | #endif | |||
skipping to change at line 3049 | skipping to change at line 3066 | |||
* | * | |||
************************************** | ************************************** | |||
* | * | |||
* Functional description | * Functional description | |||
* Allocate a record block big enough for a given format. | * Allocate a record block big enough for a given format. | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
jrd_rel* relation = rpb->rpb_relation; | ||||
VIO_trace(DEBUG_TRACE, | VIO_trace(DEBUG_TRACE, | |||
"VIO_record (record_param %" QUADFORMAT"d, format %d, pool %p)\n" | "VIO_record (rel_id %u, record_param %" QUADFORMAT"d, format %d, | |||
, | pool %p)\n", | |||
rpb->rpb_number.getValue(), format ? format->fmt_version : 0, | relation->rel_id, rpb->rpb_number.getValue(), format ? format->fm | |||
t_version : 0, | ||||
(void*) pool); | (void*) pool); | |||
#endif | #endif | |||
// If format wasn't given, look one up | // If format wasn't given, look one up | |||
if (!format) | if (!format) | |||
format = MET_format(tdbb, rpb->rpb_relation, rpb->rpb_format_numb er); | format = MET_format(tdbb, rpb->rpb_relation, rpb->rpb_format_numb er); | |||
Record* record = rpb->rpb_record; | Record* record = rpb->rpb_record; | |||
skipping to change at line 3090 | skipping to change at line 3108 | |||
* V I O _ r e f e t c h _ r e c o r d | * V I O _ r e f e t c h _ r e c o r d | |||
* | * | |||
************************************** | ************************************** | |||
* | * | |||
* Functional description | * Functional description | |||
* Refetch & release the record, if we unsure, | * Refetch & release the record, if we unsure, | |||
* whether information about it is still valid. | * whether information about it is still valid. | |||
* | * | |||
**************************************/ | **************************************/ | |||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
jrd_rel* relation = rpb->rpb_relation; | ||||
VIO_trace(DEBUG_READS, | VIO_trace(DEBUG_READS, | |||
"VIO_refetch_record (record_param %" QUADFORMAT"d, transaction %" | "VIO_refetch_record (rel_id %u, record_param %" QUADFORMAT"d, tra | |||
SQUADFORMAT")\n", | nsaction %" SQUADFORMAT")\n", | |||
rpb->rpb_number.getValue(), transaction ? transaction->tra_number | relation->rel_id, rpb->rpb_number.getValue(), transaction ? trans | |||
: 0); | action->tra_number : 0); | |||
#endif | #endif | |||
const TraNumber tid_fetch = rpb->rpb_transaction_nr; | const TraNumber tid_fetch = rpb->rpb_transaction_nr; | |||
if (!DPM_get(tdbb, rpb, LCK_read) || | if (!DPM_get(tdbb, rpb, LCK_read) || | |||
!VIO_chase_record_version(tdbb, rpb, transaction, tdbb->getDefaul tPool(), writelock, noundo)) | !VIO_chase_record_version(tdbb, rpb, transaction, tdbb->getDefaul tPool(), writelock, noundo)) | |||
{ | { | |||
if (writelock) | if (writelock) | |||
return false; | return false; | |||
skipping to change at line 3182 | skipping to change at line 3201 | |||
* V I O _ s t o r e | * V I O _ s t o r e | |||
* | * | |||
************************************** | ************************************** | |||
* | * | |||
* Functional description | * Functional description | |||
* Store a new record. | * Store a new record. | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
jrd_req* const request = tdbb->getRequest(); | jrd_req* const request = tdbb->getRequest(); | |||
jrd_rel* relation = rpb->rpb_relation; | ||||
DeferredWork* work = NULL; | DeferredWork* work = NULL; | |||
MetaName package_name; | MetaName package_name; | |||
USHORT object_id; | USHORT object_id; | |||
MetaName object_name; | MetaName object_name; | |||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
VIO_trace(DEBUG_WRITES, | VIO_trace(DEBUG_WRITES, | |||
"VIO_store (record_param %" QUADFORMAT"d, transaction %" SQUADFOR | "VIO_store (rel_id %u, record_param %" QUADFORMAT"d, transaction | |||
MAT | %" SQUADFORMAT | |||
")\n", rpb->rpb_number.getValue(), | ")\n", relation->rel_id, rpb->rpb_number.getValue(), | |||
transaction ? transaction->tra_number : 0); | transaction ? transaction->tra_number : 0); | |||
#endif | #endif | |||
transaction->tra_flags |= TRA_write; | transaction->tra_flags |= TRA_write; | |||
jrd_rel* relation = rpb->rpb_relation; | ||||
DSC desc, desc2; | DSC desc, desc2; | |||
check_gbak_cheating_insupd(tdbb, relation, "INSERT"); | check_gbak_cheating_insupd(tdbb, relation, "INSERT"); | |||
if (needDfw(tdbb, transaction)) | if (needDfw(tdbb, transaction)) | |||
{ | { | |||
switch ((RIDS) relation->rel_id) | switch ((RIDS) relation->rel_id) | |||
{ | { | |||
case rel_pages: | case rel_pages: | |||
case rel_formats: | case rel_formats: | |||
skipping to change at line 3338 | skipping to change at line 3357 | |||
if (package_name.isEmpty()) | if (package_name.isEmpty()) | |||
{ | { | |||
if (set_security_class(tdbb, rpb->rpb_record, f_f un_class)) | if (set_security_class(tdbb, rpb->rpb_record, f_f un_class)) | |||
DFW_post_work(transaction, dfw_grant, &de sc, obj_udf); | DFW_post_work(transaction, dfw_grant, &de sc, obj_udf); | |||
} | } | |||
break; | break; | |||
case rel_indices: | case rel_indices: | |||
protect_system_table_insert(tdbb, request, relation); | protect_system_table_insert(tdbb, request, relation); | |||
EVL_field(0, rpb->rpb_record, f_idx_relation, &desc); | EVL_field(0, rpb->rpb_record, f_idx_relation, &desc); | |||
SCL_check_relation(tdbb, &desc, SCL_control); | EVL_field(0, rpb->rpb_record, f_idx_sys_flag, &desc2); | |||
SCL_check_relation(tdbb, &desc, SCL_control, MOV_get_long | ||||
(&desc2, 0) == 1); | ||||
EVL_field(0, rpb->rpb_record, f_idx_name, &desc); | EVL_field(0, rpb->rpb_record, f_idx_name, &desc); | |||
if (EVL_field(0, rpb->rpb_record, f_idx_exp_blr, &desc2)) | if (EVL_field(0, rpb->rpb_record, f_idx_exp_blr, &desc2)) | |||
{ | { | |||
DFW_post_work(transaction, dfw_create_expression_ index, &desc, | DFW_post_work(transaction, dfw_create_expression_ index, &desc, | |||
tdbb->getDatabase()->db b_max_idx); | tdbb->getDatabase()->db b_max_idx); | |||
} | } | |||
else { | else { | |||
DFW_post_work(transaction, dfw_create_index, &des c, tdbb->getDatabase()->dbb_max_idx); | DFW_post_work(transaction, dfw_create_index, &des c, tdbb->getDatabase()->dbb_max_idx); | |||
} | } | |||
set_system_flag(tdbb, rpb->rpb_record, f_idx_sys_flag); | set_system_flag(tdbb, rpb->rpb_record, f_idx_sys_flag); | |||
skipping to change at line 3508 | skipping to change at line 3528 | |||
f_xcp_number, drq_g_nxt_x cp_id, "RDB$EXCEPTIONS"); | f_xcp_number, drq_g_nxt_x cp_id, "RDB$EXCEPTIONS"); | |||
set_system_flag(tdbb, rpb->rpb_record, f_xcp_sys_flag); | set_system_flag(tdbb, rpb->rpb_record, f_xcp_sys_flag); | |||
set_owner_name(tdbb, rpb->rpb_record, f_xcp_owner); | set_owner_name(tdbb, rpb->rpb_record, f_xcp_owner); | |||
if (set_security_class(tdbb, rpb->rpb_record, f_xcp_class )) | if (set_security_class(tdbb, rpb->rpb_record, f_xcp_class )) | |||
DFW_post_work(transaction, dfw_grant, &desc, obj_ exception); | DFW_post_work(transaction, dfw_grant, &desc, obj_ exception); | |||
break; | break; | |||
case rel_backup_history: | case rel_backup_history: | |||
if (!tdbb->getAttachment()->locksmith()) | if (!tdbb->getAttachment()->locksmith()) | |||
protect_system_table_insert(tdbb, request, relati on); | protect_system_table_insert(tdbb, request, relati on); | |||
set_metadata_id(tdbb, rpb->rpb_record, | set_nbackup_id(tdbb, rpb->rpb_record, | |||
f_backup_id, drq_g_nxt_nb akhist_id, "RDB$BACKUP_HISTORY"); | f_backup_id, drq_g_nxt_nb akhist_id, "RDB$BACKUP_HISTORY"); | |||
break; | break; | |||
default: // Shut up compiler warnings | default: // Shut up compiler warnings | |||
break; | break; | |||
} | } | |||
} | } | |||
// this should be scheduled even in database creation (system transaction ) | // this should be scheduled even in database creation (system transaction ) | |||
switch ((RIDS) relation->rel_id) | switch ((RIDS) relation->rel_id) | |||
skipping to change at line 3547 | skipping to change at line 3567 | |||
rpb->rpb_b_page = 0; | rpb->rpb_b_page = 0; | |||
rpb->rpb_b_line = 0; | rpb->rpb_b_line = 0; | |||
rpb->rpb_flags = 0; | rpb->rpb_flags = 0; | |||
rpb->rpb_transaction_nr = transaction->tra_number; | rpb->rpb_transaction_nr = transaction->tra_number; | |||
rpb->getWindow(tdbb).win_flags = 0; | rpb->getWindow(tdbb).win_flags = 0; | |||
rpb->rpb_record->pushPrecedence(PageNumber(TRANS_PAGE_SPACE, rpb->rpb_tra nsaction_nr)); | rpb->rpb_record->pushPrecedence(PageNumber(TRANS_PAGE_SPACE, rpb->rpb_tra nsaction_nr)); | |||
DPM_store(tdbb, rpb, rpb->rpb_record->getPrecedence(), DPM_primary); | DPM_store(tdbb, rpb, rpb->rpb_record->getPrecedence(), DPM_primary); | |||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
VIO_trace(DEBUG_WRITES_INFO, | VIO_trace(DEBUG_WRITES_INFO, | |||
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | |||
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFO | ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d | |||
RMAT":%d\n", | \n", | |||
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | |||
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | |||
rpb->rpb_f_page, rpb->rpb_f_line); | rpb->rpb_f_page, rpb->rpb_f_line); | |||
#endif | #endif | |||
if (!(transaction->tra_flags & TRA_system) && | if (!(transaction->tra_flags & TRA_system) && | |||
transaction->tra_save_point && transaction->tra_save_point->sav_v erb_count) | transaction->tra_save_point && transaction->tra_save_point->sav_v erb_count) | |||
{ | { | |||
verb_post(tdbb, transaction, rpb, NULL, false, false); | verb_post(tdbb, transaction, rpb, NULL, false, false); | |||
} | } | |||
tdbb->bumpRelStats(RuntimeStatistics::RECORD_INSERTS, relation->rel_id); | tdbb->bumpRelStats(RuntimeStatistics::RECORD_INSERTS, relation->rel_id); | |||
skipping to change at line 3743 | skipping to change at line 3763 | |||
* All changes made by the transaction are kept in one bitmap per | * All changes made by the transaction are kept in one bitmap per | |||
* relation. A second bitmap per relation tracks records for which | * relation. A second bitmap per relation tracks records for which | |||
* we have old data. The actual data is kept in a linked list stack. | * we have old data. The actual data is kept in a linked list stack. | |||
* Note that although a record may be changed several times, it will | * Note that although a record may be changed several times, it will | |||
* have only ONE old value -- the value it had before this verb | * have only ONE old value -- the value it had before this verb | |||
* started. | * started. | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
#ifdef VIO_DEBUG | ||||
VIO_trace(DEBUG_TRACE, | ||||
"VIO_verb_cleanup (transaction %" SQUADFORMAT")\n", | ||||
transaction ? transaction->tra_number : 0); | ||||
#endif | ||||
if (transaction->tra_flags & TRA_system) | if (transaction->tra_flags & TRA_system) | |||
return; | return; | |||
Savepoint* sav_point = transaction->tra_save_point; | Savepoint* sav_point = transaction->tra_save_point; | |||
if (!sav_point) | if (!sav_point) | |||
return; | return; | |||
Jrd::ContextPoolHolder context(tdbb, transaction->tra_pool); | Jrd::ContextPoolHolder context(tdbb, transaction->tra_pool); | |||
// If the current to-be-cleaned-up savepoint is very big, and the next | // If the current to-be-cleaned-up savepoint is very big, and the next | |||
skipping to change at line 3810 | skipping to change at line 3825 | |||
try | try | |||
{ | { | |||
tdbb->tdbb_flags |= TDBB_verb_cleanup; | tdbb->tdbb_flags |= TDBB_verb_cleanup; | |||
tdbb->setTransaction(transaction); | tdbb->setTransaction(transaction); | |||
while ( (action = sav_point->sav_verb_actions) ) | while ( (action = sav_point->sav_verb_actions) ) | |||
{ | { | |||
sav_point->sav_verb_actions = action->vct_next; | sav_point->sav_verb_actions = action->vct_next; | |||
jrd_rel* relation = action->vct_relation; | jrd_rel* relation = action->vct_relation; | |||
#ifdef VIO_DEBUG | ||||
VIO_trace(DEBUG_TRACE, | ||||
"VIO_verb_cleanup (transaction %" SQUADFORMAT", s | ||||
avepoint %" SQUADFORMAT", verb_count %u)\n", | ||||
transaction->tra_number, sav_point->sav_number, s | ||||
av_point->sav_verb_count); | ||||
#endif | ||||
if (sav_point->sav_verb_count || transaction->tra_save_po int) | if (sav_point->sav_verb_count || transaction->tra_save_po int) | |||
{ | { | |||
rpb.rpb_relation = relation; | rpb.rpb_relation = relation; | |||
rpb.rpb_number.setValue(BOF_NUMBER); | rpb.rpb_number.setValue(BOF_NUMBER); | |||
rpb.rpb_record = NULL; | rpb.rpb_record = NULL; | |||
rpb.getWindow(tdbb).win_flags = 0; | rpb.getWindow(tdbb).win_flags = 0; | |||
rpb.rpb_transaction_nr = transaction->tra_number; | rpb.rpb_transaction_nr = transaction->tra_number; | |||
if (sav_point->sav_verb_count) | if (sav_point->sav_verb_count) | |||
{ | { | |||
skipping to change at line 4010 | skipping to change at line 4031 | |||
* V I O _ w r i t e l o c k | * V I O _ w r i t e l o c k | |||
* | * | |||
************************************** | ************************************** | |||
* | * | |||
* Functional description | * Functional description | |||
* Modify record to make record owned by this transaction | * Modify record to make record owned by this transaction | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
jrd_rel* const relation = org_rpb->rpb_relation; | ||||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
VIO_trace(DEBUG_WRITES, | VIO_trace(DEBUG_WRITES, | |||
"VIO_writelock (org_rpb %" QUADFORMAT"d, transaction %" SQUADFORM | "VIO_writelock (rel_id %u, org_rpb %" QUADFORMAT"d, transaction % | |||
AT")\n", | " SQUADFORMAT")\n", | |||
org_rpb->rpb_number.getValue(), transaction ? transaction->tra_nu | relation->rel_id, org_rpb->rpb_number.getValue(), transaction ? t | |||
mber : 0); | ransaction->tra_number : 0); | |||
VIO_trace(DEBUG_WRITES_INFO, | VIO_trace(DEBUG_WRITES_INFO, | |||
" old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | " old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | |||
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | |||
org_rpb->rpb_page, org_rpb->rpb_line, org_rpb->rpb_transaction_nr , | org_rpb->rpb_page, org_rpb->rpb_line, org_rpb->rpb_transaction_nr , | |||
org_rpb->rpb_flags, org_rpb->rpb_b_page, org_rpb->rpb_b_line, | org_rpb->rpb_flags, org_rpb->rpb_b_page, org_rpb->rpb_b_line, | |||
org_rpb->rpb_f_page, org_rpb->rpb_f_line); | org_rpb->rpb_f_page, org_rpb->rpb_f_line); | |||
#endif | #endif | |||
if (transaction->tra_flags & TRA_system) | if (transaction->tra_flags & TRA_system) | |||
skipping to change at line 4055 | skipping to change at line 4077 | |||
if (!org_rpb->rpb_record) | if (!org_rpb->rpb_record) | |||
{ | { | |||
Record* const org_record = VIO_record(tdbb, org_rpb, NULL, tdbb-> getDefaultPool()); | Record* const org_record = VIO_record(tdbb, org_rpb, NULL, tdbb-> getDefaultPool()); | |||
org_rpb->rpb_address = org_record->getData(); | org_rpb->rpb_address = org_record->getData(); | |||
const Format* const org_format = org_record->getFormat(); | const Format* const org_format = org_record->getFormat(); | |||
org_rpb->rpb_length = org_format->fmt_length; | org_rpb->rpb_length = org_format->fmt_length; | |||
org_rpb->rpb_format_number = org_format->fmt_version; | org_rpb->rpb_format_number = org_format->fmt_version; | |||
} | } | |||
jrd_rel* const relation = org_rpb->rpb_relation; | ||||
// Set up the descriptor for the new record version. Initially, | // Set up the descriptor for the new record version. Initially, | |||
// it points to the same record data as the original one. | // it points to the same record data as the original one. | |||
record_param new_rpb = *org_rpb; | record_param new_rpb = *org_rpb; | |||
new_rpb.rpb_transaction_nr = transaction->tra_number; | new_rpb.rpb_transaction_nr = transaction->tra_number; | |||
AutoPtr<Record> new_record; | AutoPtr<Record> new_record; | |||
const Format* const new_format = MET_current(tdbb, relation); | const Format* const new_format = MET_current(tdbb, relation); | |||
// If the fetched record is not in the latest format, upgrade it. | // If the fetched record is not in the latest format, upgrade it. | |||
// To do that, allocate new record buffer and make the new record | // To do that, allocate new record buffer and make the new record | |||
skipping to change at line 4096 | skipping to change at line 4116 | |||
switch (prepare_update(tdbb, transaction, org_rpb->rpb_transaction_nr, or g_rpb, &temp, &new_rpb, | switch (prepare_update(tdbb, transaction, org_rpb->rpb_transaction_nr, or g_rpb, &temp, &new_rpb, | |||
stack, true)) | stack, true)) | |||
{ | { | |||
case PREPARE_CONFLICT: | case PREPARE_CONFLICT: | |||
case PREPARE_DELETE: | case PREPARE_DELETE: | |||
org_rpb->rpb_runtime_flags |= RPB_refetch; | org_rpb->rpb_runtime_flags |= RPB_refetch; | |||
return false; | return false; | |||
case PREPARE_LOCKERR: | case PREPARE_LOCKERR: | |||
// We got some kind of locking error (deadlock, timeout o r lock_conflict) | // We got some kind of locking error (deadlock, timeout o r lock_conflict) | |||
// Error details should be stuffed into status vector at this point | // Error details should be stuffed into status vector at this point | |||
ERR_post(Arg::Gds(isc_concurrent_transaction) << Arg::Num | // hvlad: we have no details as TRA_wait has already clea | |||
(org_rpb->rpb_transaction_nr)); | red the status vector | |||
ERR_post(Arg::Gds(isc_deadlock) << | ||||
Arg::Gds(isc_update_conflict) << | ||||
Arg::Gds(isc_concurrent_transaction) << | ||||
Arg::Num(org_rpb->rpb_transaction_nr)); | ||||
} | } | |||
// Old record was restored and re-fetched for write. Now replace it. | // Old record was restored and re-fetched for write. Now replace it. | |||
org_rpb->rpb_transaction_nr = new_rpb.rpb_transaction_nr; | org_rpb->rpb_transaction_nr = new_rpb.rpb_transaction_nr; | |||
org_rpb->rpb_format_number = new_rpb.rpb_format_number; | org_rpb->rpb_format_number = new_rpb.rpb_format_number; | |||
org_rpb->rpb_b_page = temp.rpb_page; | org_rpb->rpb_b_page = temp.rpb_page; | |||
org_rpb->rpb_b_line = temp.rpb_line; | org_rpb->rpb_b_line = temp.rpb_line; | |||
org_rpb->rpb_address = new_rpb.rpb_address; | org_rpb->rpb_address = new_rpb.rpb_address; | |||
org_rpb->rpb_length = new_rpb.rpb_length; | org_rpb->rpb_length = new_rpb.rpb_length; | |||
org_rpb->rpb_flags |= rpb_delta; | org_rpb->rpb_flags &= ~(rpb_delta | rpb_uk_modified); | |||
org_rpb->rpb_flags |= new_rpb.rpb_flags & rpb_delta; | ||||
replace_record(tdbb, org_rpb, &stack, transaction); | replace_record(tdbb, org_rpb, &stack, transaction); | |||
if (!(transaction->tra_flags & TRA_system) && transaction->tra_save_point ) | if (!(transaction->tra_flags & TRA_system) && transaction->tra_save_point ) | |||
verb_post(tdbb, transaction, org_rpb, NULL, false, false); | verb_post(tdbb, transaction, org_rpb, NULL, false, false); | |||
// for an autocommit transaction, mark a commit as necessary | // for an autocommit transaction, mark a commit as necessary | |||
if (transaction->tra_flags & TRA_autocommit) | if (transaction->tra_flags & TRA_autocommit) | |||
transaction->tra_flags |= TRA_perform_autocommit; | transaction->tra_flags |= TRA_perform_autocommit; | |||
skipping to change at line 4366 | skipping to change at line 4390 | |||
* Functional description | * Functional description | |||
* Delete a record an all of its fragments. This assumes the | * Delete a record an all of its fragments. This assumes the | |||
* record has already been fetched for write. If a pool is given, | * record has already been fetched for write. If a pool is given, | |||
* the caller has requested that data be fetched as the record is | * the caller has requested that data be fetched as the record is | |||
* deleted. | * deleted. | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
jrd_rel* relation = rpb->rpb_relation; | ||||
VIO_trace(DEBUG_WRITES, | VIO_trace(DEBUG_WRITES, | |||
"delete_record (record_param %" QUADFORMAT"d, prior_page %" SLONG | "delete_record (rel_id %u, record_param %" QUADFORMAT"d, prior_pa | |||
FORMAT", pool %p)\n", | ge %" SLONGFORMAT", pool %p)\n", | |||
rpb->rpb_number.getValue(), prior_page, (void*) pool); | relation->rel_id, rpb->rpb_number.getValue(), prior_page, (void*) | |||
pool); | ||||
VIO_trace(DEBUG_WRITES_INFO, | VIO_trace(DEBUG_WRITES_INFO, | |||
" delete_record record %" SLONGFORMAT":%d, rpb_trans %" SQUADF ORMAT | " delete_record record %" SLONGFORMAT":%d, rpb_trans %" SQUADF ORMAT | |||
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | |||
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | |||
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | |||
rpb->rpb_f_page, rpb->rpb_f_line); | rpb->rpb_f_page, rpb->rpb_f_line); | |||
#endif | #endif | |||
UCHAR* tail; | UCHAR* tail; | |||
const UCHAR* tail_end; | const UCHAR* tail_end; | |||
skipping to change at line 4442 | skipping to change at line 4467 | |||
************************************** | ************************************** | |||
* | * | |||
* Functional description | * Functional description | |||
* Delete the tail of a record. If no tail, don't do nuttin'. | * Delete the tail of a record. If no tail, don't do nuttin'. | |||
* If the address of a record tail has been passed, fetch data. | * If the address of a record tail has been passed, fetch data. | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
jrd_rel* relation = rpb->rpb_relation; | ||||
VIO_trace(DEBUG_WRITES, | VIO_trace(DEBUG_WRITES, | |||
"delete_tail (record_param %" QUADFORMAT"d, prior_page %" SLONGFO | "delete_tail (rel_id %u, record_param %" QUADFORMAT"d, prior_page | |||
RMAT", tail %p, tail_end %p)\n", | %" SLONGFORMAT", tail %p, tail_end %p)\n", | |||
rpb->rpb_number.getValue(), prior_page, tail, tail_end); | relation->rel_id, rpb->rpb_number.getValue(), prior_page, tail, t | |||
ail_end); | ||||
VIO_trace(DEBUG_WRITES_INFO, | VIO_trace(DEBUG_WRITES_INFO, | |||
" tail of record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | " tail of record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | |||
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | |||
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | |||
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | |||
rpb->rpb_f_page, rpb->rpb_f_line); | rpb->rpb_f_page, rpb->rpb_f_line); | |||
#endif | #endif | |||
RuntimeStatistics::Accumulator fragments(tdbb, rpb->rpb_relation, | RuntimeStatistics::Accumulator fragments(tdbb, rpb->rpb_relation, | |||
skipping to change at line 4528 | skipping to change at line 4554 | |||
* and all of the ancestors. Be particulary careful since this | * and all of the ancestors. Be particulary careful since this | |||
* can do a lot of damage. | * can do a lot of damage. | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
Jrd::Attachment* attachment = transaction->tra_attachment; | Jrd::Attachment* attachment = transaction->tra_attachment; | |||
fb_assert(assert_gc_enabled(transaction, rpb->rpb_relation)); | fb_assert(assert_gc_enabled(transaction, rpb->rpb_relation)); | |||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
jrd_rel* relation = rpb->rpb_relation; | ||||
VIO_trace(DEBUG_WRITES, | VIO_trace(DEBUG_WRITES, | |||
"expunge (record_param %" QUADFORMAT"d, transaction %" SQUADFORMA T | "expunge (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT | |||
", prior_page %" SLONGFORMAT")\n", | ", prior_page %" SLONGFORMAT")\n", | |||
rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0, | relation->rel_id, rpb->rpb_number.getValue(), transaction ? trans action->tra_number : 0, | |||
prior_page); | prior_page); | |||
#endif | #endif | |||
if (attachment->att_flags & ATT_no_cleanup) | if (attachment->att_flags & ATT_no_cleanup) | |||
return; | return; | |||
// Re-fetch the record | // Re-fetch the record | |||
if (!DPM_get(tdbb, rpb, LCK_write)) | if (!DPM_get(tdbb, rpb, LCK_write)) | |||
{ | { | |||
skipping to change at line 4612 | skipping to change at line 4639 | |||
* 1) just been deleted or | * 1) just been deleted or | |||
* 2) just had its back pointers set to zero | * 2) just had its back pointers set to zero | |||
* Therefor we can do a fetch on the back pointers we've got | * Therefor we can do a fetch on the back pointers we've got | |||
* because we have the last existing copy of them. | * because we have the last existing copy of them. | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
jrd_rel* relation = rpb->rpb_relation; | ||||
VIO_trace(DEBUG_WRITES, | VIO_trace(DEBUG_WRITES, | |||
"garbage_collect (record_param %" QUADFORMAT"d, prior_page %" SLO | "garbage_collect (rel_id %u, record_param %" QUADFORMAT"d, prior_ | |||
NGFORMAT", staying)\n", | page %" SLONGFORMAT", staying)\n", | |||
rpb->rpb_number.getValue(), prior_page); | relation->rel_id, rpb->rpb_number.getValue(), prior_page); | |||
VIO_trace(DEBUG_WRITES_INFO, | VIO_trace(DEBUG_WRITES_INFO, | |||
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | |||
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | |||
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | |||
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | |||
rpb->rpb_f_page, rpb->rpb_f_line); | rpb->rpb_f_page, rpb->rpb_f_line); | |||
#endif | #endif | |||
RuntimeStatistics::Accumulator backversions(tdbb, rpb->rpb_relation, | RuntimeStatistics::Accumulator backversions(tdbb, rpb->rpb_relation, | |||
skipping to change at line 5461 | skipping to change at line 5489 | |||
* | * | |||
* Functional description | * Functional description | |||
* Prepare for a modify or erase. Store the old version | * Prepare for a modify or erase. Store the old version | |||
* of a record, fetch the current version, check transaction | * of a record, fetch the current version, check transaction | |||
* states, etc. | * states, etc. | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
Attachment* const attachment = tdbb->getAttachment(); | Attachment* const attachment = tdbb->getAttachment(); | |||
jrd_rel* const relation = rpb->rpb_relation; | ||||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
VIO_trace(DEBUG_TRACE_ALL, | VIO_trace(DEBUG_TRACE_ALL, | |||
"prepare_update (transaction %" SQUADFORMAT | "prepare_update (rel_id %u, transaction %" SQUADFORMAT | |||
", commit_tid read %" SQUADFORMAT", record_param %" QUADFORMAT"d, ", | ", commit_tid read %" SQUADFORMAT", record_param %" QUADFORMAT"d, ", | |||
transaction ? transaction->tra_number : 0, commit_tid_read, | relation->rel_id, transaction ? transaction->tra_number : 0, comm it_tid_read, | |||
rpb ? rpb->rpb_number.getValue() : 0); | rpb ? rpb->rpb_number.getValue() : 0); | |||
VIO_trace(DEBUG_TRACE_ALL, | VIO_trace(DEBUG_TRACE_ALL, | |||
" temp_rpb %" QUADFORMAT"d, new_rpb %" QUADFORMAT"d, stack)\n", | " temp_rpb %" QUADFORMAT"d, new_rpb %" QUADFORMAT"d, stack)\n", | |||
temp ? temp->rpb_number.getValue() : 0, | temp ? temp->rpb_number.getValue() : 0, | |||
new_rpb ? new_rpb->rpb_number.getValue() : 0); | new_rpb ? new_rpb->rpb_number.getValue() : 0); | |||
VIO_trace(DEBUG_TRACE_ALL_INFO, | VIO_trace(DEBUG_TRACE_ALL_INFO, | |||
" old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | " old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | |||
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT | ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT | |||
skipping to change at line 5500 | skipping to change at line 5529 | |||
return an update conflict. If the transaction is dead, back out the | return an update conflict. If the transaction is dead, back out the | |||
old version of the record and try again. If in limbo, punt. | old version of the record and try again. If in limbo, punt. | |||
The above is true only for concurrency & consistency mode transactions. | The above is true only for concurrency & consistency mode transactions. | |||
For read committed transactions, check if the latest commited version | For read committed transactions, check if the latest commited version | |||
is the same as the version that was read for the update. If yes, | is the same as the version that was read for the update. If yes, | |||
the update can take place. If some other transaction has modified | the update can take place. If some other transaction has modified | |||
the record and committed, then an update error will be returned. | the record and committed, then an update error will be returned. | |||
*/ | */ | |||
jrd_rel* const relation = rpb->rpb_relation; | ||||
*temp = *rpb; | *temp = *rpb; | |||
Record* const record = rpb->rpb_record; | Record* const record = rpb->rpb_record; | |||
// Mark the record as chained version, and re-store it | // Mark the record as chained version, and re-store it | |||
temp->rpb_address = record->getData(); | temp->rpb_address = record->getData(); | |||
const Format* const format = record->getFormat(); | const Format* const format = record->getFormat(); | |||
temp->rpb_length = format->fmt_length; | temp->rpb_length = format->fmt_length; | |||
temp->rpb_format_number = format->fmt_version; | temp->rpb_format_number = format->fmt_version; | |||
temp->rpb_flags = rpb_chained; | temp->rpb_flags = rpb_chained; | |||
skipping to change at line 5768 | skipping to change at line 5795 | |||
tdbb->bumpRelStats(RuntimeStatistics::REC ORD_CONFLICTS, relation->rel_id); | tdbb->bumpRelStats(RuntimeStatistics::REC ORD_CONFLICTS, relation->rel_id); | |||
ERR_post(Arg::Gds(isc_deadlock) << | ERR_post(Arg::Gds(isc_deadlock) << | |||
Arg::Gds(isc_update_conf lict) << | Arg::Gds(isc_update_conf lict) << | |||
Arg::Gds(isc_concurrent_ transaction) << Arg::Num(update_conflict_trans)); | Arg::Gds(isc_concurrent_ transaction) << Arg::Num(update_conflict_trans)); | |||
} | } | |||
case tra_active: | case tra_active: | |||
return PREPARE_LOCKERR; | return PREPARE_LOCKERR; | |||
case tra_limbo: | case tra_limbo: | |||
ERR_post(Arg::Gds(isc_deadlock) << Arg::Gds(isc_t rainlim)); | ERR_post(Arg::Gds(isc_trainlim) << Arg::Gds(isc_r ec_in_limbo) << Arg::Num(rpb->rpb_transaction_nr)); | |||
case tra_dead: | case tra_dead: | |||
break; | break; | |||
default: | default: | |||
fb_assert(false); | fb_assert(false); | |||
} // switch (state) | } // switch (state) | |||
break; | break; | |||
skipping to change at line 5877 | skipping to change at line 5904 | |||
* if the purge couldn't happen because somebody else had the record. | * if the purge couldn't happen because somebody else had the record. | |||
* But the function was made void since nobody checks its return value. | * But the function was made void since nobody checks its return value. | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
Database* dbb = tdbb->getDatabase(); | Database* dbb = tdbb->getDatabase(); | |||
CHECK_DBB(dbb); | CHECK_DBB(dbb); | |||
fb_assert(assert_gc_enabled(tdbb->getTransaction(), rpb->rpb_relation)); | fb_assert(assert_gc_enabled(tdbb->getTransaction(), rpb->rpb_relation)); | |||
jrd_rel* const relation = rpb->rpb_relation; | ||||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
VIO_trace(DEBUG_TRACE_ALL, | VIO_trace(DEBUG_TRACE_ALL, | |||
"purge (record_param %" QUADFORMAT"d)\n", rpb->rpb_number.getValu | "purge (rel_id %u, record_param %" QUADFORMAT"d)\n", | |||
e()); | relation->rel_id, rpb->rpb_number.getValue()); | |||
VIO_trace(DEBUG_TRACE_ALL_INFO, | VIO_trace(DEBUG_TRACE_ALL_INFO, | |||
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | |||
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | |||
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | |||
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | |||
rpb->rpb_f_page, rpb->rpb_f_line); | rpb->rpb_f_page, rpb->rpb_f_line); | |||
#endif | #endif | |||
// Release and re-fetch the page for write. Make sure it's still the | // Release and re-fetch the page for write. Make sure it's still the | |||
// same record (give up if not). Then zap the back pointer and release | // same record (give up if not). Then zap the back pointer and release | |||
// the record. | // the record. | |||
record_param temp = *rpb; | record_param temp = *rpb; | |||
jrd_rel* const relation = rpb->rpb_relation; | ||||
AutoGCRecord gc_rec(VIO_gc_record(tdbb, relation)); | AutoGCRecord gc_rec(VIO_gc_record(tdbb, relation)); | |||
Record* record = rpb->rpb_record = gc_rec; | Record* record = rpb->rpb_record = gc_rec; | |||
VIO_data(tdbb, rpb, relation->rel_pool); | VIO_data(tdbb, rpb, relation->rel_pool); | |||
temp.rpb_prior = rpb->rpb_prior; | temp.rpb_prior = rpb->rpb_prior; | |||
rpb->rpb_record = temp.rpb_record; | rpb->rpb_record = temp.rpb_record; | |||
if (!DPM_get(tdbb, rpb, LCK_write)) | if (!DPM_get(tdbb, rpb, LCK_write)) | |||
{ | { | |||
skipping to change at line 5955 | skipping to change at line 5983 | |||
************************************** | ************************************** | |||
* | * | |||
* Functional description | * Functional description | |||
* Replace a record and get rid of the old tail, if any. If requested, | * Replace a record and get rid of the old tail, if any. If requested, | |||
* fetch data for the record on the way out. | * fetch data for the record on the way out. | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
jrd_rel* relation = rpb->rpb_relation; | ||||
VIO_trace(DEBUG_TRACE_ALL, | VIO_trace(DEBUG_TRACE_ALL, | |||
"replace_record (record_param %" QUADFORMAT"d, transaction %" SQU | "replace_record (rel_id %u, record_param %" QUADFORMAT"d, transac | |||
ADFORMAT")\n", | tion %" SQUADFORMAT")\n", | |||
rpb->rpb_number.getValue(), transaction ? transaction->tra_number | relation->rel_id, rpb->rpb_number.getValue(), transaction ? trans | |||
: 0); | action->tra_number : 0); | |||
VIO_trace(DEBUG_TRACE_ALL_INFO, | VIO_trace(DEBUG_TRACE_ALL_INFO, | |||
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | |||
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT | ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT | |||
":%d, prior %p\n", | ":%d, prior %p\n", | |||
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, | |||
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, | |||
rpb->rpb_f_page, rpb->rpb_f_line, (void*) rpb->rpb_prior); | rpb->rpb_f_page, rpb->rpb_f_line, (void*) rpb->rpb_prior); | |||
#endif | #endif | |||
skipping to change at line 6085 | skipping to change at line 6114 | |||
return MOV_get_long(&desc1, 0); | return MOV_get_long(&desc1, 0); | |||
SSHORT value = (SSHORT) DYN_UTIL_gen_unique_id(tdbb, dyn_id, name); | SSHORT value = (SSHORT) DYN_UTIL_gen_unique_id(tdbb, dyn_id, name); | |||
dsc desc2; | dsc desc2; | |||
desc2.makeShort(0, &value); | desc2.makeShort(0, &value); | |||
MOV_move(tdbb, &desc2, &desc1); | MOV_move(tdbb, &desc2, &desc1); | |||
record->clearNull(field_id); | record->clearNull(field_id); | |||
return value; | return value; | |||
} | } | |||
// Assign the 31-bit auto generated ID to a particular field | ||||
static void set_nbackup_id(thread_db* tdbb, Record* record, USHORT field_id, drq | ||||
_type_t dyn_id, | ||||
const char* name) | ||||
{ | ||||
dsc desc1; | ||||
if (EVL_field(0, record, field_id, &desc1)) | ||||
return; | ||||
SLONG value = (SLONG) DYN_UTIL_gen_unique_id(tdbb, dyn_id, name); | ||||
dsc desc2; | ||||
desc2.makeLong(0, &value); | ||||
MOV_move(tdbb, &desc2, &desc1); | ||||
record->clearNull(field_id); | ||||
} | ||||
static void set_owner_name(thread_db* tdbb, Record* record, USHORT field_id) | static void set_owner_name(thread_db* tdbb, Record* record, USHORT field_id) | |||
{ | { | |||
/************************************** | /************************************** | |||
* | * | |||
* s e t _ o w n e r _ n a m e | * s e t _ o w n e r _ n a m e | |||
* | * | |||
************************************** | ************************************** | |||
* | * | |||
* Functional description | * Functional description | |||
* Set the owner name for the metadata object. | * Set the owner name for the metadata object. | |||
skipping to change at line 6182 | skipping to change at line 6227 | |||
* | * | |||
* Functional description | * Functional description | |||
* Modify a record in place. This is used for system transactions | * Modify a record in place. This is used for system transactions | |||
* and for multiple modifications of a user record. | * and for multiple modifications of a user record. | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
Database* dbb = tdbb->getDatabase(); | Database* dbb = tdbb->getDatabase(); | |||
CHECK_DBB(dbb); | CHECK_DBB(dbb); | |||
jrd_rel* const relation = org_rpb->rpb_relation; | ||||
#ifdef VIO_DEBUG | #ifdef VIO_DEBUG | |||
VIO_trace(DEBUG_TRACE_ALL, | VIO_trace(DEBUG_TRACE_ALL, | |||
"update_in_place (transaction %" SQUADFORMAT", org_rpb %" QUADFOR MAT"d, " | "update_in_place (rel_id %u, transaction %" SQUADFORMAT", org_rpb %" QUADFORMAT"d, " | |||
"new_rpb %" QUADFORMAT"d)\n", | "new_rpb %" QUADFORMAT"d)\n", | |||
transaction ? transaction->tra_number : 0, org_rpb->rpb_number.ge tValue(), | relation->rel_id, transaction ? transaction->tra_number : 0, org_ rpb->rpb_number.getValue(), | |||
new_rpb ? new_rpb->rpb_number.getValue() : 0); | new_rpb ? new_rpb->rpb_number.getValue() : 0); | |||
VIO_trace(DEBUG_TRACE_ALL_INFO, | VIO_trace(DEBUG_TRACE_ALL_INFO, | |||
" old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | " old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT | |||
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", | |||
org_rpb->rpb_page, org_rpb->rpb_line, org_rpb->rpb_transaction_nr , | org_rpb->rpb_page, org_rpb->rpb_line, org_rpb->rpb_transaction_nr , | |||
org_rpb->rpb_flags, org_rpb->rpb_b_page, org_rpb->rpb_b_line, | org_rpb->rpb_flags, org_rpb->rpb_b_page, org_rpb->rpb_b_line, | |||
org_rpb->rpb_f_page, org_rpb->rpb_f_line); | org_rpb->rpb_f_page, org_rpb->rpb_f_line); | |||
#endif | #endif | |||
PageStack& stack = new_rpb->rpb_record->getPrecedence(); | PageStack& stack = new_rpb->rpb_record->getPrecedence(); | |||
jrd_rel* const relation = org_rpb->rpb_relation; | ||||
Record* const old_data = org_rpb->rpb_record; | Record* const old_data = org_rpb->rpb_record; | |||
// If the old version has been stored as a delta, things get complicated. Clearly, | // If the old version has been stored as a delta, things get complicated. Clearly, | |||
// if we overwrite the current record, the differences from the current v ersion | // if we overwrite the current record, the differences from the current v ersion | |||
// becomes meaningless. What we need to do is replace the old "delta" re cord | // becomes meaningless. What we need to do is replace the old "delta" re cord | |||
// with an old "complete" record, update in placement, then delete the ol d delta record | // with an old "complete" record, update in placement, then delete the ol d delta record | |||
AutoGCRecord gc_rec; | AutoGCRecord gc_rec; | |||
record_param temp2; | record_param temp2; | |||
skipping to change at line 6326 | skipping to change at line 6371 | |||
* (i.e. update_in_place). | * (i.e. update_in_place). | |||
* new_rpb: Only used to pass to garbage_collect_idx but that functio n doesn't use it! | * new_rpb: Only used to pass to garbage_collect_idx but that functio n doesn't use it! | |||
* same_tx: true if this transaction inserted/updated this record | * same_tx: true if this transaction inserted/updated this record | |||
* and then deleted it. | * and then deleted it. | |||
* false in all other cases. | * false in all other cases. | |||
* | * | |||
**************************************/ | **************************************/ | |||
SET_TDBB(tdbb); | SET_TDBB(tdbb); | |||
Jrd::ContextPoolHolder context(tdbb, transaction->tra_pool); | Jrd::ContextPoolHolder context(tdbb, transaction->tra_pool); | |||
MemoryPool* pool = tdbb->getDefaultPool(); | ||||
// Find action block for relation | // Find action block for relation | |||
VerbAction* action; | VerbAction* action; | |||
for (action = transaction->tra_save_point->sav_verb_actions; action; acti on = action->vct_next) | for (action = transaction->tra_save_point->sav_verb_actions; action; acti on = action->vct_next) | |||
{ | { | |||
if (action->vct_relation == rpb->rpb_relation) | if (action->vct_relation == rpb->rpb_relation) | |||
break; | break; | |||
} | } | |||
if (!action) | if (!action) | |||
{ | { | |||
if ( (action = transaction->tra_save_point->sav_verb_free) ) | if ( (action = transaction->tra_save_point->sav_verb_free) ) | |||
transaction->tra_save_point->sav_verb_free = action->vct_ next; | transaction->tra_save_point->sav_verb_free = action->vct_ next; | |||
else | else | |||
action = FB_NEW_POOL(*tdbb->getDefaultPool()) VerbAction( ); | action = FB_NEW_POOL(*pool) VerbAction(); | |||
action->vct_next = transaction->tra_save_point->sav_verb_actions; | action->vct_next = transaction->tra_save_point->sav_verb_actions; | |||
transaction->tra_save_point->sav_verb_actions = action; | transaction->tra_save_point->sav_verb_actions = action; | |||
action->vct_relation = rpb->rpb_relation; | action->vct_relation = rpb->rpb_relation; | |||
} | } | |||
if (!RecordBitmap::test(action->vct_records, rpb->rpb_number.getValue())) | if (!RecordBitmap::test(action->vct_records, rpb->rpb_number.getValue())) | |||
{ | { | |||
RBM_SET(tdbb->getDefaultPool(), &action->vct_records, rpb->rpb_nu mber.getValue()); | RBM_SET(pool, &action->vct_records, rpb->rpb_number.getValue()); | |||
if (old_data) | if (old_data) | |||
{ | { | |||
// An update-in-place is being posted to this savepoint, and this | // An update-in-place is being posted to this savepoint, and this | |||
// savepoint hasn't seen this record before. | // savepoint hasn't seen this record before. | |||
if (!action->vct_undo) | if (!action->vct_undo) | |||
action->vct_undo = FB_NEW UndoItemTree(tdbb->getD efaultPool()); | action->vct_undo = FB_NEW_POOL(*pool) UndoItemTre e(pool); | |||
action->vct_undo->add(UndoItem(transaction, rpb->rpb_numb er, old_data, same_tx, false)); | action->vct_undo->add(UndoItem(transaction, rpb->rpb_numb er, old_data, same_tx, false)); | |||
} | } | |||
else if (same_tx) | else if (same_tx) | |||
{ | { | |||
// An insert/update followed by a delete is posted to thi s savepoint, | // An insert/update followed by a delete is posted to thi s savepoint, | |||
// and this savepoint hasn't seen this record before. | // and this savepoint hasn't seen this record before. | |||
if (!action->vct_undo) | if (!action->vct_undo) | |||
action->vct_undo = FB_NEW UndoItemTree(tdbb->getD efaultPool()); | action->vct_undo = FB_NEW_POOL(*pool) UndoItemTre e(pool); | |||
action->vct_undo->add(UndoItem(rpb->rpb_number, true, new _ver)); | action->vct_undo->add(UndoItem(rpb->rpb_number, true, new _ver)); | |||
} | } | |||
} | } | |||
else if (same_tx) | else if (same_tx) | |||
{ | { | |||
AutoUndoRecord undo; | AutoUndoRecord undo; | |||
if (action->vct_undo && action->vct_undo->locate(rpb->rpb_number. getValue())) | if (action->vct_undo && action->vct_undo->locate(rpb->rpb_number. getValue())) | |||
{ | { | |||
skipping to change at line 6390 | skipping to change at line 6436 | |||
action->vct_undo->current().markSameTx(); | action->vct_undo->current().markSameTx(); | |||
undo = action->vct_undo->current().setupRecord(transactio n); | undo = action->vct_undo->current().setupRecord(transactio n); | |||
} | } | |||
else | else | |||
{ | { | |||
// An insert/update followed by a delete is posted to thi s savepoint, | // An insert/update followed by a delete is posted to thi s savepoint, | |||
// and this savepoint has seen this record before but it doesn't have undo data. | // and this savepoint has seen this record before but it doesn't have undo data. | |||
if (!action->vct_undo) | if (!action->vct_undo) | |||
action->vct_undo = FB_NEW UndoItemTree(tdbb->getD efaultPool()); | action->vct_undo = FB_NEW_POOL(*pool) UndoItemTre e(pool); | |||
action->vct_undo->add(UndoItem(rpb->rpb_number, true, tru e)); | action->vct_undo->add(UndoItem(rpb->rpb_number, true, tru e)); | |||
} | } | |||
if (old_data) | if (old_data) | |||
{ | { | |||
// The passed old_data will not be used. Thus, garbage c ollect. | // The passed old_data will not be used. Thus, garbage c ollect. | |||
garbage_collect_idx(tdbb, rpb, old_data, undo); | garbage_collect_idx(tdbb, rpb, old_data, undo); | |||
} | } | |||
End of changes. 80 change blocks. | ||||
104 lines changed or deleted | 163 lines changed or added |