diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index a3fbff38803..b1f76709b30 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -62,6 +62,8 @@ #include "../common/StatusArg.h" #include "../auth/SecureRemotePassword/Message.h" #include "../jrd/Mapping.h" +#include "../jrd/btr_proto.h" +#include "../jrd/lck_proto.h" namespace Jrd { @@ -110,6 +112,7 @@ static void updateRdbFields(const TypeClause* type, SSHORT& fieldPrecisionNull, SSHORT& fieldPrecision, SSHORT& collationIdNull, SSHORT& collationId, SSHORT& segmentLengthNull, SSHORT& segmentLength); +static int blocking_ast_index(void* ast_object); static const char* const CHECK_CONSTRAINT_EXCEPTION = "check_constraint"; @@ -9794,6 +9797,35 @@ bool DropIndexNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) return true; } +static int blocking_ast_index(void* ast_object) +{ +/************************************** + * + * b l o c k i n g _ a s t _ i n d e x + * + ************************************** + * + * Functional description + * Someone is trying to get lock on index. + * If index is not on deletion, relese the lock. + * + **************************************/ + IndexLock* const index = static_cast(ast_object); + try + { + if (!index->idl_deletion && index->idl_lock) + { + Database* const dbb = index->idl_lock->lck_dbb; + AsyncContextHolder tdbb(dbb, FB_FUNCTION, index->idl_lock); + LCK_release(tdbb, index->idl_lock); + } + } + catch (const Exception&) + {} // no-op + + return 0; +} + void DropIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { // run all statements under savepoint control @@ -9802,6 +9834,28 @@ void DropIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, j AutoCacheRequest request(tdbb, drq_e_indices, DYN_REQUESTS); bool found = false; + Jrd::IndexStatus idx_state; + SLONG idx_id; + SLONG rel_id; + + // Need to create lock on index. This lock guarantees + // that index which are deleted and should not be used in future queries + idx_id = MET_lookup_index_name(tdbb, name, &rel_id, &idx_state); + + if (idx_id != -1) + { + jrd_rel* relation = MET_lookup_relation_id(tdbb, rel_id, true); + IndexLock* index = CMP_get_index_lock(tdbb, relation, idx_id); + if (index) + { + // mark the index to deletion stage and get exclusive lock on it + index->idl_lock->lck_ast = blocking_ast_index; + index->idl_lock->lck_object = index; + index->idl_deletion = true; + LCK_lock(tdbb, index->idl_lock, LCK_EX, LCK_WAIT); + } + } + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) IDX IN RDB$INDICES WITH IDX.RDB$INDEX_NAME EQ name.c_str() diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index ddc45c7ebf6..005f0874926 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -59,6 +59,7 @@ #include "../jrd/mov_proto.h" #include "../jrd/pag_proto.h" #include "../jrd/tra_proto.h" +#include "../jrd/cmp_proto.h" using namespace Jrd; using namespace Ods; @@ -478,7 +479,6 @@ bool BTR_delete_index(thread_db* tdbb, WIN* window, USHORT id) return tree_exists; } - bool BTR_description(thread_db* tdbb, jrd_rel* relation, index_root_page* root, index_desc* idx, USHORT id) { @@ -503,6 +503,19 @@ bool BTR_description(thread_db* tdbb, jrd_rel* relation, index_root_page* root, if (irt_desc->getRoot() == 0) return false; + IndexLock* index = CMP_get_index_lock(tdbb, relation, id); + if (index) + { + // try to get lock on the index, if it's unsuccessful, then + // the index already locked on deletion stage + if(!LCK_lock(tdbb, index->idl_lock, LCK_SR, LCK_NO_WAIT)) + { + // clean status vector after trying lock + fb_utils::init_status(tdbb->tdbb_status_vector); + return false; + } + } + idx->idx_id = id; idx->idx_root = irt_desc->getRoot(); idx->idx_count = irt_desc->irt_keys; diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 90b3d16123c..d3adf186646 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -1294,6 +1294,26 @@ void DFW_delete_deferred( jrd_tra* transaction, SavNumber sav_number) for (DfwHash::iterator i(h->hash); i.hasData();) { DeferredWork* work(i); + // If the index deleting was rolled back, + // We need to deque the index lock from lock manager + if (work->dfw_type == dfw_delete_index || + work->dfw_type == dfw_delete_expression_index) + { + DeferredWork* w = work; + const DeferredWork* arg = w->findArg(dfw_arg_index_name); + fb_assert(arg); + fb_assert(arg->dfw_id > 0); + const USHORT id = arg->dfw_id - 1; + + Jrd::thread_db* tdbb = JRD_get_thread_data(); + jrd_rel* relation = MET_lookup_relation_id(tdbb, w->dfw_id, false); + + IndexLock* index = CMP_get_index_lock(tdbb, relation, id); + + // mark index as non deleted and make it shared + index->idl_deletion = false; + LCK_lock(tdbb, index->idl_lock, LCK_SR, LCK_WAIT); + } ++i; delete work; } diff --git a/src/jrd/lck.cpp b/src/jrd/lck.cpp index 8f862a7e6a5..e25b46d18f4 100644 --- a/src/jrd/lck.cpp +++ b/src/jrd/lck.cpp @@ -73,6 +73,8 @@ static bool internal_enqueue(thread_db*, CheckStatusWrapper*, Lock*, USHORT, SSH static SLONG get_owner_handle(thread_db* tdbb, enum lck_t lock_type); static lck_owner_t get_owner_type(enum lck_t lock_type); +static Firebird::GlobalPtr > index_locks; + #ifdef DEBUG_LCK namespace { diff --git a/src/jrd/lck_proto.h b/src/jrd/lck_proto.h index 024d7ffb97f..001b40472f8 100644 --- a/src/jrd/lck_proto.h +++ b/src/jrd/lck_proto.h @@ -46,7 +46,6 @@ void LCK_release(Jrd::thread_db*, Jrd::Lock*); void LCK_re_post(Jrd::thread_db*, Jrd::Lock*); void LCK_write_data(Jrd::thread_db*, Jrd::Lock*, SINT64); - class AutoLock { public: diff --git a/src/jrd/req.h b/src/jrd/req.h index 47bedf10655..611a34985f7 100644 --- a/src/jrd/req.h +++ b/src/jrd/req.h @@ -324,6 +324,7 @@ class IndexLock : public pool_alloc jrd_rel* idl_relation; // Parent relation USHORT idl_id; // Index id USHORT idl_count; // Use count + bool idl_deletion; // Deletion stage }; } //namespace Jrd