From f8752bb6776cb75815f4ec2efda4fa861364cd63 Mon Sep 17 00:00:00 2001 From: hvlad Date: Sun, 22 Jul 2018 19:43:51 +0300 Subject: [PATCH] Hopefully final corrections: missed (info, EDS) items, spaces, etc --- doc/README.read_consistency.md | 2 +- src/jrd/Database.h | 2 +- src/jrd/extds/ExtDS.cpp | 9 +++++++- src/jrd/extds/ExtDS.h | 3 ++- src/jrd/inf.cpp | 4 +++- src/jrd/inf_pub.h | 1 + src/jrd/tpc.cpp | 4 ++-- src/jrd/tra.cpp | 41 ++++++++++++++++++++++++++-------- src/jrd/tra.h | 4 ++-- src/jrd/tra_proto.h | 2 +- src/jrd/vio.cpp | 6 ++--- 11 files changed, 56 insertions(+), 22 deletions(-) diff --git a/doc/README.read_consistency.md b/doc/README.read_consistency.md index f79eeb1941..3fcb21d8fb 100644 --- a/doc/README.read_consistency.md +++ b/doc/README.read_consistency.md @@ -128,7 +128,7 @@ So, there are three kinds of read-committed transactions now: When statement executed within read committed read consistency transaction its database view is not changed (similar to snapshot transaction). Therefore it is useless to wait for commit of concurrent transaction in the hope to re-read new committed record version. On read, behavior is -similar to read committed *no record version* transaction - do not wait for active transaction and +similar to read committed *record version* transaction - do not wait for active transaction and walk backversions chain looking for record version visible to the current snapshot. When update conflict happens engine behavior is changed. If concurrent transaction is active, diff --git a/src/jrd/Database.h b/src/jrd/Database.h index 73dde2908d..488ba62604 100644 --- a/src/jrd/Database.h +++ b/src/jrd/Database.h @@ -499,7 +499,7 @@ public: StmtNumber generateStatementId(); // void assignLatestTransactionId(TraNumber number); void assignLatestAttachmentId(AttNumber number); - + USHORT getMaxIndexKeyLength() const { diff --git a/src/jrd/extds/ExtDS.cpp b/src/jrd/extds/ExtDS.cpp index 9de688b300..7a907c784b 100644 --- a/src/jrd/extds/ExtDS.cpp +++ b/src/jrd/extds/ExtDS.cpp @@ -1471,6 +1471,11 @@ void Transaction::generateTPB(thread_db* /*tdbb*/, ClumpletWriter& tpb, tpb.insertTag(isc_tpb_rec_version); break; + case traReadCommitedReadConsistency: + tpb.insertTag(isc_tpb_read_committed); + tpb.insertTag(isc_tpb_read_consistency); + break; + case traConcurrency: tpb.insertTag(isc_tpb_concurrency); break; @@ -1574,7 +1579,9 @@ Transaction* Transaction::getTransaction(thread_db* tdbb, Connection* conn, TraS TraModes traMode = traConcurrency; if (tran->tra_flags & TRA_read_committed) { - if (tran->tra_flags & TRA_rec_version) + if (tran->tra_flags & TRA_read_consistency) + traMode = traReadCommitedReadConsistency; + else if (tran->tra_flags & TRA_rec_version) traMode = traReadCommitedRecVersions; else traMode = traReadCommited; diff --git a/src/jrd/extds/ExtDS.h b/src/jrd/extds/ExtDS.h index b2de6bbd29..654e22df95 100644 --- a/src/jrd/extds/ExtDS.h +++ b/src/jrd/extds/ExtDS.h @@ -47,7 +47,8 @@ class Transaction; class Statement; class Blob; -enum TraModes {traReadCommited, traReadCommitedRecVersions, traConcurrency, traConsistency}; +enum TraModes {traReadCommited, traReadCommitedRecVersions, traReadCommitedReadConsistency, + traConcurrency, traConsistency}; enum TraScope {traNotSet = 0, traAutonomous, traCommon, traTwoPhase}; // Known built-in provider's names diff --git a/src/jrd/inf.cpp b/src/jrd/inf.cpp index fa1bbca8d8..a17bcfd274 100644 --- a/src/jrd/inf.cpp +++ b/src/jrd/inf.cpp @@ -1114,7 +1114,9 @@ void INF_transaction_info(const jrd_tra* transaction, if (transaction->tra_flags & TRA_read_committed) { *p++ = isc_info_tra_read_committed; - if (transaction->tra_flags & TRA_rec_version) + if (transaction->tra_flags & TRA_read_consistency) + *p++ = isc_info_tra_read_consistency; + else if (transaction->tra_flags & TRA_rec_version) *p++ = isc_info_tra_rec_version; else *p++ = isc_info_tra_no_rec_version; diff --git a/src/jrd/inf_pub.h b/src/jrd/inf_pub.h index 432302eac0..efedf8e636 100644 --- a/src/jrd/inf_pub.h +++ b/src/jrd/inf_pub.h @@ -401,6 +401,7 @@ enum info_db_provider // isc_info_tra_read_committed options #define isc_info_tra_no_rec_version 0 #define isc_info_tra_rec_version 1 +#define isc_info_tra_read_consistency 2 // isc_info_tra_access responses #define isc_info_tra_readonly 0 diff --git a/src/jrd/tpc.cpp b/src/jrd/tpc.cpp index 08f94344ff..a562555344 100644 --- a/src/jrd/tpc.cpp +++ b/src/jrd/tpc.cpp @@ -295,7 +295,7 @@ void TipCache::loadInventoryPages(thread_db* tdbb) // At the same time, simple write to a volatile variable is not good // as it is not deterministic. Some compilers generate barriers and some do not. ((std::atomic*)(statusBlock->data + transOffset))->store(cn, std::memory_order_relaxed); - + if (++t > hdr_next_transaction) break; @@ -431,7 +431,7 @@ TraNumber TipCache::findStates(TraNumber minNumber, TraNumber maxNumber, ULONG m // Barrier is not needed here. Slightly out-dated information shall be ok here. // Such transaction shall already be considered active by our caller. // TODO: check if this assumption is indeed correct. - + CommitNumber cn = ((std::atomic*)(statusBlock->data + transOffset))->load(std::memory_order_relaxed); switch (cn) { diff --git a/src/jrd/tra.cpp b/src/jrd/tra.cpp index 5e9888314f..b4876b5f39 100644 --- a/src/jrd/tra.cpp +++ b/src/jrd/tra.cpp @@ -151,7 +151,7 @@ void TRA_setup_request_snapshot(Jrd::thread_db* tdbb, Jrd::jrd_req* request) // We assume that request is already attached to a transaction fb_assert(transaction); - // If we are not READ COMMITTED or stable cursors are not needed then nothing to do here + // If we are not READ COMMITTED or read consistency is not needed then nothing to do here if (!(transaction->tra_flags & TRA_read_committed) || !(transaction->tra_flags & TRA_read_consistency)) return; @@ -1521,7 +1521,7 @@ void TRA_set_state(thread_db* tdbb, jrd_tra* transaction, TraNumber number, int } -int TRA_snapshot_state(thread_db* tdbb, jrd_tra* trans, TraNumber number, CommitNumber *snapshot) +int TRA_snapshot_state(thread_db* tdbb, const jrd_tra* trans, TraNumber number, CommitNumber *snapshot) { /************************************** * @@ -1552,7 +1552,7 @@ int TRA_snapshot_state(thread_db* tdbb, jrd_tra* trans, TraNumber number, Commit // If the transaction is older than the oldest // interesting transaction, it must be committed. - if (number < trans->tra_oldest) + if (number < trans->tra_oldest) { if (snapshot) *snapshot = att->att_active_snapshots.getSnapshotForVersion(CN_PREHISTORIC); @@ -1561,7 +1561,7 @@ int TRA_snapshot_state(thread_db* tdbb, jrd_tra* trans, TraNumber number, Commit // If the transaction is the system transaction, it is considered committed. - if (number == TRA_system_transaction) + if (number == TRA_system_transaction) { if (snapshot) *snapshot = att->att_active_snapshots.getSnapshotForVersion(CN_PREHISTORIC); @@ -2711,7 +2711,7 @@ static void transaction_options(thread_db* tdbb, RelationLockTypeMap lockmap; TriState wait, lock_timeout; - TriState isolation, read_only, rec_version; + TriState isolation, read_only, rec_version, read_consistency; bool anylock_write = false; ++tpb; @@ -2793,6 +2793,14 @@ static void transaction_options(thread_db* tdbb, Arg::Gds(isc_tpb_multiple_spec) << Arg::Str("isc_tpb_rec_version")); } + if (read_consistency.isAssigned()) + { + ERR_post(Arg::Gds(isc_bad_tpb_content) << + // 'Option @1 is not valid if @2 was used previously in TPB' + Arg::Gds(isc_tpb_conflicting_options) << + Arg::Str("isc_tpb_rec_version") << Arg::Str("isc_tpb_read_consistency")); + } + transaction->tra_flags &= ~TRA_read_consistency; transaction->tra_flags |= TRA_rec_version; break; @@ -2810,8 +2818,15 @@ static void transaction_options(thread_db* tdbb, Arg::Gds(isc_tpb_multiple_spec) << Arg::Str("isc_tpb_no_rec_version")); } + if (read_consistency.isAssigned()) + { + ERR_post(Arg::Gds(isc_bad_tpb_content) << + // 'Option @1 is not valid if @2 was used previously in TPB' + Arg::Gds(isc_tpb_conflicting_options) << + Arg::Str("isc_tpb_no_rec_version") << Arg::Str("isc_tpb_read_consistency")); + } + transaction->tra_flags &= ~(TRA_rec_version | TRA_read_consistency); - ; break; case isc_tpb_read_consistency: @@ -2821,14 +2836,22 @@ static void transaction_options(thread_db* tdbb, Arg::Gds(isc_tpb_option_without_rc) << Arg::Str("isc_tpb_read_consistency")); } - if (!rec_version.assignOnce(false)) + if (!read_consistency.assignOnce(true)) { ERR_post(Arg::Gds(isc_bad_tpb_content) << Arg::Gds(isc_tpb_multiple_spec) << Arg::Str("isc_tpb_read_consistency")); } - transaction->tra_flags &= ~TRA_rec_version; - transaction->tra_flags |= TRA_read_consistency; + if (rec_version.isAssigned()) + { + ERR_post(Arg::Gds(isc_bad_tpb_content) << + // 'Option @1 is not valid if @2 was used previously in TPB' + Arg::Gds(isc_tpb_conflicting_options) << + Arg::Str("isc_tpb_read_consistency") << (rec_version.asBool() ? + Arg::Str("isc_tpb_rec_version") : Arg::Str("isc_tpb_no_rec_version")) ); + } + + transaction->tra_flags |= TRA_read_consistency | TRA_rec_version; break; case isc_tpb_nowait: diff --git a/src/jrd/tra.h b/src/jrd/tra.h index dbd7546702..ab664e99fa 100644 --- a/src/jrd/tra.h +++ b/src/jrd/tra.h @@ -411,11 +411,11 @@ const ULONG TRA_restart_requests = 0x4000L; // restart all requests in attachmen const ULONG TRA_no_auto_undo = 0x8000L; // don't start a savepoint in TRA_start const ULONG TRA_precommitted = 0x10000L; // transaction committed at startup const ULONG TRA_own_interface = 0x20000L; // tra_interface was created for internal needs -const ULONG TRA_read_consistency = 0x40000L; // ensure read consistency for cursors in this transaction +const ULONG TRA_read_consistency = 0x40000L; // ensure read consistency in this transaction // flags derived from TPB, see also transaction_options() at tra.cpp const ULONG TRA_OPTIONS_MASK = (TRA_degree3 | TRA_readonly | TRA_ignore_limbo | TRA_read_committed | - TRA_autocommit | TRA_rec_version | TRA_no_auto_undo | TRA_restart_requests); + TRA_autocommit | TRA_rec_version | TRA_read_consistency | TRA_no_auto_undo | TRA_restart_requests); const int TRA_MASK = 3; //const int TRA_BITS_PER_TRANS = 2; diff --git a/src/jrd/tra_proto.h b/src/jrd/tra_proto.h index e563af380e..f4ccb64f8c 100644 --- a/src/jrd/tra_proto.h +++ b/src/jrd/tra_proto.h @@ -54,7 +54,7 @@ Jrd::jrd_tra* TRA_reconnect(Jrd::thread_db* tdbb, const UCHAR*, USHORT); void TRA_release_transaction(Jrd::thread_db* tdbb, Jrd::jrd_tra*, Jrd::TraceTransactionEnd*); void TRA_rollback(Jrd::thread_db* tdbb, Jrd::jrd_tra*, const bool, const bool); void TRA_set_state(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction, TraNumber number, int state); -int TRA_snapshot_state(Jrd::thread_db* tdbb, Jrd::jrd_tra* trans, TraNumber number, CommitNumber* snapshot = NULL); +int TRA_snapshot_state(Jrd::thread_db* tdbb, const Jrd::jrd_tra* trans, TraNumber number, CommitNumber* snapshot = NULL); Jrd::jrd_tra* TRA_start(Jrd::thread_db* tdbb, ULONG flags, SSHORT lock_timeout, Jrd::jrd_tra* outer = NULL); Jrd::jrd_tra* TRA_start(Jrd::thread_db* tdbb, int, const UCHAR*, Jrd::jrd_tra* outer = NULL); int TRA_state(const UCHAR*, TraNumber oldest, TraNumber number); diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index ec609da7b0..1af9299d8d 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -5218,7 +5218,7 @@ static void list_staying(thread_db* tdbb, record_param* rpb, RecordStack& stayin RuntimeStatistics::Accumulator backversions(tdbb, rpb->rpb_relation, RuntimeStatistics::RECORD_BACKVERSION_READS); - + // Limit number of "restarts" if primary version constantly changed. Currently, // LS_ACTIVE_RPB is passed by VIO_intermediate_gc only and it is ok to return // empty staying in this case. @@ -5677,7 +5677,7 @@ static int prepare_update( thread_db* tdbb, temp->rpb_b_page = rpb->rpb_b_page; temp->rpb_b_line = rpb->rpb_b_line; temp->rpb_flags &= ~rpb_delta; - temp->rpb_flags |= rpb->rpb_flags & rpb_delta; // NS 2014-09-10: XXX - what is this code doing? + temp->rpb_flags |= rpb->rpb_flags & rpb_delta; temp->rpb_transaction_nr = rpb->rpb_transaction_nr; DPM_store(tdbb, temp, stack, DPM_secondary); @@ -5730,7 +5730,7 @@ static int prepare_update( thread_db* tdbb, switch (state) { case tra_committed: - // We need to loop waiting in read committed transactions only + // We need to loop waiting in read committed with no read consistency transactions only if (!(transaction->tra_flags & TRA_read_committed) || (transaction->tra_flags & TRA_read_consistency)) {