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:
parent
ce593a8962
commit
7defa17f80
@ -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
|
||||
}
|
||||
|
||||
|
||||
//----------------------
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user