mirror of
https://github.com/postgres/postgres.git
synced 2025-07-31 22:04:40 +03:00
Refactor nbtree insertion scankeys.
Use dedicated struct to represent nbtree insertion scan keys. Having a dedicated struct makes the difference between search type scankeys and insertion scankeys a lot clearer, and simplifies the signature of several related functions. This is based on a suggestion by Andrey Lepikhov. Streamline how unique index insertions cache binary search progress. Cache the state of in-progress binary searches within _bt_check_unique() for later instead of having callers avoid repeating the binary search in an ad-hoc manner. This makes it easy to add a new optimization: _bt_check_unique() now falls out of its loop immediately in the common case where it's already clear that there couldn't possibly be a duplicate. The new _bt_check_unique() scheme makes it a lot easier to manage cached binary search effort afterwards, from within _bt_findinsertloc(). This is needed for the upcoming patch to make nbtree tuples unique by treating heap TID as a final tiebreaker column. Unique key binary searches need to restore lower and upper bounds. They cannot simply continue to use the >= lower bound as the offset to insert at, because the heap TID tiebreaker column must be used in comparisons for the restored binary search (unlike the original _bt_check_unique() binary search, where scankey's heap TID column must be omitted). Author: Peter Geoghegan, Heikki Linnakangas Reviewed-By: Heikki Linnakangas, Andrey Lepikhov Discussion: https://postgr.es/m/CAH2-WzmE6AhUdk9NdWBf4K3HjWXZBX3+umC7mH7+WDrKcRtsOw@mail.gmail.com
This commit is contained in:
@ -127,9 +127,9 @@ static void bt_check_every_level(Relation rel, Relation heaprel,
|
||||
static BtreeLevel bt_check_level_from_leftmost(BtreeCheckState *state,
|
||||
BtreeLevel level);
|
||||
static void bt_target_page_check(BtreeCheckState *state);
|
||||
static ScanKey bt_right_page_check_scankey(BtreeCheckState *state);
|
||||
static void bt_downlink_check(BtreeCheckState *state, BlockNumber childblock,
|
||||
ScanKey targetkey);
|
||||
static BTScanInsert bt_right_page_check_scankey(BtreeCheckState *state);
|
||||
static void bt_downlink_check(BtreeCheckState *state, BTScanInsert targetkey,
|
||||
BlockNumber childblock);
|
||||
static void bt_downlink_missing_check(BtreeCheckState *state);
|
||||
static void bt_tuple_present_callback(Relation index, HeapTuple htup,
|
||||
Datum *values, bool *isnull,
|
||||
@ -139,14 +139,14 @@ static IndexTuple bt_normalize_tuple(BtreeCheckState *state,
|
||||
static inline bool offset_is_negative_infinity(BTPageOpaque opaque,
|
||||
OffsetNumber offset);
|
||||
static inline bool invariant_leq_offset(BtreeCheckState *state,
|
||||
ScanKey key,
|
||||
BTScanInsert key,
|
||||
OffsetNumber upperbound);
|
||||
static inline bool invariant_geq_offset(BtreeCheckState *state,
|
||||
ScanKey key,
|
||||
BTScanInsert key,
|
||||
OffsetNumber lowerbound);
|
||||
static inline bool invariant_leq_nontarget_offset(BtreeCheckState *state,
|
||||
Page other,
|
||||
ScanKey key,
|
||||
BTScanInsert key,
|
||||
Page nontarget,
|
||||
OffsetNumber upperbound);
|
||||
static Page palloc_btree_page(BtreeCheckState *state, BlockNumber blocknum);
|
||||
|
||||
@ -838,8 +838,8 @@ bt_target_page_check(BtreeCheckState *state)
|
||||
{
|
||||
ItemId itemid;
|
||||
IndexTuple itup;
|
||||
ScanKey skey;
|
||||
size_t tupsize;
|
||||
BTScanInsert skey;
|
||||
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
|
||||
@ -1030,7 +1030,7 @@ bt_target_page_check(BtreeCheckState *state)
|
||||
*/
|
||||
else if (offset == max)
|
||||
{
|
||||
ScanKey rightkey;
|
||||
BTScanInsert rightkey;
|
||||
|
||||
/* Get item in next/right page */
|
||||
rightkey = bt_right_page_check_scankey(state);
|
||||
@ -1082,7 +1082,7 @@ bt_target_page_check(BtreeCheckState *state)
|
||||
{
|
||||
BlockNumber childblock = BTreeInnerTupleGetDownLink(itup);
|
||||
|
||||
bt_downlink_check(state, childblock, skey);
|
||||
bt_downlink_check(state, skey, childblock);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1111,11 +1111,12 @@ bt_target_page_check(BtreeCheckState *state)
|
||||
* Note that !readonly callers must reverify that target page has not
|
||||
* been concurrently deleted.
|
||||
*/
|
||||
static ScanKey
|
||||
static BTScanInsert
|
||||
bt_right_page_check_scankey(BtreeCheckState *state)
|
||||
{
|
||||
BTPageOpaque opaque;
|
||||
ItemId rightitem;
|
||||
IndexTuple firstitup;
|
||||
BlockNumber targetnext;
|
||||
Page rightpage;
|
||||
OffsetNumber nline;
|
||||
@ -1303,8 +1304,8 @@ bt_right_page_check_scankey(BtreeCheckState *state)
|
||||
* Return first real item scankey. Note that this relies on right page
|
||||
* memory remaining allocated.
|
||||
*/
|
||||
return _bt_mkscankey(state->rel,
|
||||
(IndexTuple) PageGetItem(rightpage, rightitem));
|
||||
firstitup = (IndexTuple) PageGetItem(rightpage, rightitem);
|
||||
return _bt_mkscankey(state->rel, firstitup);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1317,8 +1318,8 @@ bt_right_page_check_scankey(BtreeCheckState *state)
|
||||
* verification this way around is much more practical.
|
||||
*/
|
||||
static void
|
||||
bt_downlink_check(BtreeCheckState *state, BlockNumber childblock,
|
||||
ScanKey targetkey)
|
||||
bt_downlink_check(BtreeCheckState *state, BTScanInsert targetkey,
|
||||
BlockNumber childblock)
|
||||
{
|
||||
OffsetNumber offset;
|
||||
OffsetNumber maxoffset;
|
||||
@ -1423,8 +1424,7 @@ bt_downlink_check(BtreeCheckState *state, BlockNumber childblock,
|
||||
if (offset_is_negative_infinity(copaque, offset))
|
||||
continue;
|
||||
|
||||
if (!invariant_leq_nontarget_offset(state, child,
|
||||
targetkey, offset))
|
||||
if (!invariant_leq_nontarget_offset(state, targetkey, child, offset))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INDEX_CORRUPTED),
|
||||
errmsg("down-link lower bound invariant violated for index \"%s\"",
|
||||
@ -1864,13 +1864,12 @@ offset_is_negative_infinity(BTPageOpaque opaque, OffsetNumber offset)
|
||||
* to corruption.
|
||||
*/
|
||||
static inline bool
|
||||
invariant_leq_offset(BtreeCheckState *state, ScanKey key,
|
||||
invariant_leq_offset(BtreeCheckState *state, BTScanInsert key,
|
||||
OffsetNumber upperbound)
|
||||
{
|
||||
int16 nkeyatts = IndexRelationGetNumberOfKeyAttributes(state->rel);
|
||||
int32 cmp;
|
||||
|
||||
cmp = _bt_compare(state->rel, nkeyatts, key, state->target, upperbound);
|
||||
cmp = _bt_compare(state->rel, key, state->target, upperbound);
|
||||
|
||||
return cmp <= 0;
|
||||
}
|
||||
@ -1883,13 +1882,12 @@ invariant_leq_offset(BtreeCheckState *state, ScanKey key,
|
||||
* to corruption.
|
||||
*/
|
||||
static inline bool
|
||||
invariant_geq_offset(BtreeCheckState *state, ScanKey key,
|
||||
invariant_geq_offset(BtreeCheckState *state, BTScanInsert key,
|
||||
OffsetNumber lowerbound)
|
||||
{
|
||||
int16 nkeyatts = IndexRelationGetNumberOfKeyAttributes(state->rel);
|
||||
int32 cmp;
|
||||
|
||||
cmp = _bt_compare(state->rel, nkeyatts, key, state->target, lowerbound);
|
||||
cmp = _bt_compare(state->rel, key, state->target, lowerbound);
|
||||
|
||||
return cmp >= 0;
|
||||
}
|
||||
@ -1905,14 +1903,12 @@ invariant_geq_offset(BtreeCheckState *state, ScanKey key,
|
||||
* to corruption.
|
||||
*/
|
||||
static inline bool
|
||||
invariant_leq_nontarget_offset(BtreeCheckState *state,
|
||||
Page nontarget, ScanKey key,
|
||||
OffsetNumber upperbound)
|
||||
invariant_leq_nontarget_offset(BtreeCheckState *state, BTScanInsert key,
|
||||
Page nontarget, OffsetNumber upperbound)
|
||||
{
|
||||
int16 nkeyatts = IndexRelationGetNumberOfKeyAttributes(state->rel);
|
||||
int32 cmp;
|
||||
|
||||
cmp = _bt_compare(state->rel, nkeyatts, key, nontarget, upperbound);
|
||||
cmp = _bt_compare(state->rel, key, nontarget, upperbound);
|
||||
|
||||
return cmp <= 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user