8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-02-02 10:00:38 +01:00

alter index active/inactive, WIP

This commit is contained in:
AlexPeshkoff 2024-12-30 15:11:52 +03:00
parent ce593a8962
commit 7defa17f80
7 changed files with 103 additions and 37 deletions

View File

@ -11743,6 +11743,7 @@ void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
AutoCacheRequest request(tdbb, drq_m_index, DYN_REQUESTS);
bool found = false;
bool active = create;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
IDX IN RDB$INDICES
@ -11750,26 +11751,31 @@ void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
{
found = true;
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_INDEX,
indexName, NULL);
active = IDX.RDB$INDEX_INACTIVE.NULL ? true : !IDX.RDB$INDEX_INACTIVE;
relName = IDX.RDB$RELATION_NAME;
relation = MetadataCache::lookupRelation(tdbb, relName, CacheFlag::AUTOCREATE);
fb_assert(relation);
if (relation && !idxId.isUnknown())
relation->oldIndexVersion(tdbb, idxId.value);
expressionIndex = !IDX.RDB$EXPRESSION_BLR.NULL;
if (!IDX.RDB$INDEX_ID.NULL)
if (active != create)
{
fb_assert(IDX.RDB$INDEX_ID);
idxId = IDX.RDB$INDEX_ID - 1;
}
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_INDEX,
indexName, NULL);
MODIFY IDX
IDX.RDB$INDEX_INACTIVE.NULL = FALSE;
IDX.RDB$INDEX_INACTIVE = create ? FALSE : TRUE;
END_MODIFY
relName = IDX.RDB$RELATION_NAME;
relation = MetadataCache::lookupRelation(tdbb, relName, CacheFlag::AUTOCREATE);
fb_assert(relation);
if (relation && !idxId.isUnknown())
relation->oldIndexVersion(tdbb, idxId.value);
expressionIndex = !IDX.RDB$EXPRESSION_BLR.NULL;
if (!IDX.RDB$INDEX_ID.NULL)
{
fb_assert(IDX.RDB$INDEX_ID);
idxId = IDX.RDB$INDEX_ID - 1;
}
MODIFY IDX
IDX.RDB$INDEX_INACTIVE.NULL = FALSE;
IDX.RDB$INDEX_INACTIVE = create ? FALSE : TRUE;
END_MODIFY
}
}
END_FOR
@ -11779,6 +11785,9 @@ void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
status_exception::raise(Arg::PrivateDyn(48));
}
if (active == create)
return;
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_INDEX,
indexName, NULL);
@ -12034,6 +12043,30 @@ MetaId DropIndexNode::exec(thread_db* tdbb, Cached::Relation* rel, jrd_tra* tran
}
void DropIndexNode::clearId(thread_db* tdbb, MetaId relId, MetaId indexId)
{
SET_TDBB(tdbb);
Attachment* attachment = tdbb->getAttachment();
Database* dbb = tdbb->getDatabase();
jrd_tra* transaction = attachment->getSysTransaction(); // ID cleanup not related to current transaction
AutoCacheRequest handle(tdbb, irq_index_id_erase, IRQ_REQUESTS);
FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction)
IND IN RDB$INDICES
CROSS REL IN RDB$RELATIONS
OVER RDB$RELATION_NAME
WITH IND.RDB$INDEX_ID EQ indexId + 1
AND REL.RDB$RELATION_ID EQ relId
{
MODIFY IND
IND.RDB$INDEX_ID = 0;
IND.RDB$INDEX_ID.NULL = TRUE;
END_MODIFY
}
END_FOR
}
//----------------------

View File

@ -1962,6 +1962,8 @@ public:
static bool deleteSegmentRecords(thread_db* tdbb, jrd_tra* transaction,
const MetaName& name);
static void clearId(thread_db* tdbb, MetaId relId, MetaId indexId);
public:
virtual Firebird::string internalPrint(NodePrinter& printer) const;
virtual void checkPermission(thread_db* tdbb, jrd_tra* transaction);

View File

@ -554,6 +554,11 @@ public:
return perm;
}
bool getActive()
{
return !idv_inactive;
}
private:
Cached::Index* perm;
MetaName idv_name;
@ -561,6 +566,7 @@ private:
SSHORT idv_segmentCount = 0;
SSHORT idv_type = 0;
MetaName idv_foreignKey; // FOREIGN RELATION NAME
bool idv_inactive = false;
public:
ValueExprNode* idv_expression = nullptr; // node tree for index expression

View File

@ -63,6 +63,7 @@
#include "../jrd/pag_proto.h"
#include "../jrd/tra_proto.h"
#include "../jrd/tpc_proto.h"
#include "../dsql/DdlNodes.h"
using namespace Jrd;
using namespace Ods;
@ -187,19 +188,20 @@ namespace
temporary_key jumpKey;
};
int indexCacheState(thread_db* tdbb, TraNumber trans, Cached::Relation* rel, MetaId idxId, bool creating)
int indexCacheState(thread_db* tdbb, TraNumber descTrans, Cached::Relation* rel, MetaId idxId, bool creating)
{
int rc = TPC_cache_state(tdbb, trans);
int rc = TPC_cache_state(tdbb, descTrans);
if (rc == tra_committed) // too old dead transaction may be reported as committed
{
// check presence of record for this index in RDB$INDICES
// use metadata cache for better performance
bool indexRecordPresent = rel->lookup_index(tdbb, idxId, CacheFlag::AUTOCREATE);
auto* index = rel->lookup_index(tdbb, idxId, CacheFlag::AUTOCREATE);
bool indexPresent = index && index->getActive();
// if index really created => record should be present
// if index really dropped => record should be missing
// otherwise transaction is dead, not committed
if (indexRecordPresent != creating)
if (indexPresent != creating)
return tra_dead;
}
return rc;
@ -525,9 +527,13 @@ bool BTR_delete_index(thread_db* tdbb, WIN* window, MetaId id)
irt_desc->setEmpty();
const PageNumber prior(window->win_page);
const MetaId relation_id = root->irt_relation;
CCH_RELEASE(tdbb, window);
delete_tree(tdbb, relation_id, id, next, prior);
// clear RDB$INDEX_ID
DropIndexNode::clearId(tdbb, relation_id, id);
return tree_exists;
}
@ -580,6 +586,8 @@ void BTR_mark_index_for_delete(thread_db* tdbb, WIN* window, MetaId id)
const PageNumber next(window->win_page.getPageSpaceID(), irt_desc->getRoot());
jrd_tra* tra = tdbb->getTransaction();
TraNumber descTrans = irt_desc->getTransaction();
fb_assert(tra);
if (tra)
{
@ -592,9 +600,23 @@ void BTR_mark_index_for_delete(thread_db* tdbb, WIN* window, MetaId id)
case irt_drop:
badState(irt_desc, "irt_in_progress/irt_commit/irt_drop", msg);
case irt_rollback: // created right now, may be dropped ?????????? when? one more state?
checkTransactionNumber(irt_desc, tra, msg);
irt_desc->setDrop(tra->tra_number);
case irt_rollback: // created not long ago
if (descTrans != tra->tra_number)
{
// another transaction - may be no records were modified in the index?
switch (TPC_cache_state(tdbb, descTrans))
{
case tra_committed: // did not switch to normal state - anyway treat as normal one
case tra_dead: // drop index right now - nobody is using it
irt_desc->setCommit(tra->tra_number);
break;
default: // if we see such index that transaction should not be active - raise error
badState(irt_desc, "irt_rollback", msg);
}
}
else
irt_desc->setCommit(tra->tra_number);
break;
case irt_normal:
@ -2087,7 +2109,7 @@ bool BTR_next_index(thread_db* tdbb, Cached::Relation* relation, jrd_tra* transa
TraNumber oldestActive = tdbb->getDatabase()->dbb_oldest_active;
const index_root_page::irt_repeat* irt_desc = root->irt_rpt + id;
const TraNumber trans = irt_desc->getTransaction();
const TraNumber descTrans = irt_desc->getTransaction();
switch (irt_desc->getState())
{
@ -2096,7 +2118,7 @@ bool BTR_next_index(thread_db* tdbb, Cached::Relation* relation, jrd_tra* transa
case irt_in_progress:
// index creation - should wait to know what to do
if (trans && transaction)
if (descTrans && transaction)
{
IndexCreateLock crtLock(tdbb, relation->getId());
@ -2111,7 +2133,7 @@ bool BTR_next_index(thread_db* tdbb, Cached::Relation* relation, jrd_tra* transa
case irt_rollback: // to be removed when irt_transaction dead
case irt_commit: // change state on irt_transaction completion
switch (TPC_cache_state(tdbb, trans))
switch (TPC_cache_state(tdbb, descTrans))
{
case tra_committed: // switch to normal / drop state
case tra_dead: // drop index on rollback / switch to normal state
@ -2121,8 +2143,8 @@ bool BTR_next_index(thread_db* tdbb, Cached::Relation* relation, jrd_tra* transa
break;
case irt_drop:
// drop index when OAT > trans
needWrite = oldestActive > trans;
// drop index when OAT > descTrans
needWrite = oldestActive > descTrans;
break;
}
@ -2135,7 +2157,7 @@ bool BTR_next_index(thread_db* tdbb, Cached::Relation* relation, jrd_tra* transa
root = (index_root_page*) CCH_FETCH(tdbb, window, LCK_write, pag_root);
index_root_page::irt_repeat* irt_write = root->irt_rpt + id;
const TraNumber trans = irt_write->getTransaction();
const TraNumber descTrans = irt_write->getTransaction();
bool delIndex = false;
switch (irt_write->getState())
@ -2148,7 +2170,7 @@ bool BTR_next_index(thread_db* tdbb, Cached::Relation* relation, jrd_tra* transa
fatal_exception::raise("Index state still irt_in_progress after wait for creation lock");
case irt_rollback: // to be removed when irt_transaction dead
switch (indexCacheState(tdbb, trans, relation, id, true))
switch (indexCacheState(tdbb, descTrans, relation, id, true))
{
case tra_committed: // switch to normal state
CCH_MARK(tdbb, window);
@ -2162,7 +2184,7 @@ bool BTR_next_index(thread_db* tdbb, Cached::Relation* relation, jrd_tra* transa
break;
case irt_commit: // change state on irt_transaction completion
switch (indexCacheState(tdbb, trans, relation, id, false))
switch (indexCacheState(tdbb, descTrans, relation, id, false))
{
case tra_committed: // switch to drop state
CCH_MARK(tdbb, window);
@ -2177,8 +2199,8 @@ bool BTR_next_index(thread_db* tdbb, Cached::Relation* relation, jrd_tra* transa
break;
case irt_drop:
// drop index when OAT > trans
if (oldestActive > trans)
// drop index when OAT > descTrans
if (oldestActive > descTrans)
delIndex = true;
break;
}

View File

@ -185,6 +185,7 @@ enum irq_type_t
irq_out_proc_param_dep, // check output procedure parameter dependency
irq_l_pub_tab_state, // lookup publication state for a table
irq_index_scan, // scan index for caching
irq_index_id_erase, // cleanup index ID
irq_get_index_by_name, // find appropriate index
irq_MAX

View File

@ -5304,6 +5304,7 @@ bool IndexVersion::scan(thread_db* tdbb, ObjectBase::Flag flags)
idv_segmentCount = IND.RDB$SEGMENT_COUNT;
idv_type = IND.RDB$INDEX_TYPE;
idv_foreignKey = IND.RDB$FOREIGN_KEY;
idv_inactive = IND.RDB$INDEX_INACTIVE.NULL ? false : IND.RDB$INDEX_INACTIVE;
if (!IND.RDB$EXPRESSION_BLR.NULL)
expression = IND.RDB$EXPRESSION_BLR;

View File

@ -430,7 +430,7 @@ const UCHAR irt_state_b = 128;
const UCHAR irt_in_progress = 0; // index creation
const UCHAR irt_rollback = irt_state_a; // to be removed when irt_transaction dead
const UCHAR irt_commit = irt_state_b; // to be prepared for remove when irt_transaction committed
const UCHAR irt_drop = irt_state_a | irt_state_b; // to be removed when irt_transaction < OAT
const UCHAR irt_drop = irt_state_a | irt_state_b; // to be removed when OAT > irt_transaction
const UCHAR irt_normal = 1; // any constant not overlapping irt_state_mask is fine here
// index state mask in flags
@ -505,7 +505,8 @@ inline void index_root_page::irt_repeat::setNormal(ULONG root_page)
inline void index_root_page::irt_repeat::setCommit(TraNumber traNumber)
{
fb_assert(getState() == irt_normal);
// going to drop index tra that created it committed but no records added
fb_assert((getState() == irt_normal) || (getState() == irt_rollback));
fb_assert(traNumber < MAX_ULONG); // temp limit, need ODS change !!!!!!!!!!!!!!!!!!!!!!!!
fb_assert(irt_root);
irt_transaction = traNumber;