1
0
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:
Peter Geoghegan
2019-03-20 09:30:57 -07:00
parent 550b9d26f8
commit e5adcb789d
9 changed files with 532 additions and 390 deletions

View File

@ -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;
}