mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-15 08:20:16 +08:00
This feature is controlled by a new old_snapshot_threshold GUC. A value of -1 disables the feature, and that is the default. The value of 0 is just intended for testing. Above that it is the number of minutes a snapshot can reach before pruning and vacuum are allowed to remove dead tuples which the snapshot would otherwise protect. The xmin associated with a transaction ID does still protect dead tuples. A connection which is using an "old" snapshot does not get an error unless it accesses a page modified recently enough that it might not be able to produce accurate results. This is similar to the Oracle feature, and we use the same SQLSTATE and error message for compatibility.
180 lines
3.5 KiB
C
180 lines
3.5 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* blscan.c
|
|
* Bloom index scan functions.
|
|
*
|
|
* Copyright (c) 2016, PostgreSQL Global Development Group
|
|
*
|
|
* IDENTIFICATION
|
|
* contrib/bloom/blscan.c
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include "access/relscan.h"
|
|
#include "pgstat.h"
|
|
#include "miscadmin.h"
|
|
#include "storage/bufmgr.h"
|
|
#include "storage/lmgr.h"
|
|
#include "utils/memutils.h"
|
|
#include "utils/rel.h"
|
|
|
|
#include "bloom.h"
|
|
|
|
/*
|
|
* Begin scan of bloom index.
|
|
*/
|
|
IndexScanDesc
|
|
blbeginscan(Relation r, int nkeys, int norderbys)
|
|
{
|
|
IndexScanDesc scan;
|
|
|
|
scan = RelationGetIndexScan(r, nkeys, norderbys);
|
|
|
|
return scan;
|
|
}
|
|
|
|
/*
|
|
* Rescan a bloom index.
|
|
*/
|
|
void
|
|
blrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
|
|
ScanKey orderbys, int norderbys)
|
|
{
|
|
BloomScanOpaque so;
|
|
|
|
so = (BloomScanOpaque) scan->opaque;
|
|
|
|
if (so == NULL)
|
|
{
|
|
/* if called from blbeginscan */
|
|
so = (BloomScanOpaque) palloc(sizeof(BloomScanOpaqueData));
|
|
initBloomState(&so->state, scan->indexRelation);
|
|
scan->opaque = so;
|
|
|
|
}
|
|
else
|
|
{
|
|
if (so->sign)
|
|
pfree(so->sign);
|
|
}
|
|
so->sign = NULL;
|
|
|
|
if (scankey && scan->numberOfKeys > 0)
|
|
{
|
|
memmove(scan->keyData, scankey,
|
|
scan->numberOfKeys * sizeof(ScanKeyData));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* End scan of bloom index.
|
|
*/
|
|
void
|
|
blendscan(IndexScanDesc scan)
|
|
{
|
|
BloomScanOpaque so = (BloomScanOpaque) scan->opaque;
|
|
|
|
if (so->sign)
|
|
pfree(so->sign);
|
|
so->sign = NULL;
|
|
}
|
|
|
|
/*
|
|
* Insert all matching tuples into to a bitmap.
|
|
*/
|
|
int64
|
|
blgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
|
|
{
|
|
int64 ntids = 0;
|
|
BlockNumber blkno = BLOOM_HEAD_BLKNO,
|
|
npages;
|
|
int i;
|
|
BufferAccessStrategy bas;
|
|
BloomScanOpaque so = (BloomScanOpaque) scan->opaque;
|
|
|
|
if (so->sign == NULL)
|
|
{
|
|
/* New search: have to calculate search signature */
|
|
ScanKey skey = scan->keyData;
|
|
|
|
so->sign = palloc0(sizeof(SignType) * so->state.opts.bloomLength);
|
|
|
|
for (i = 0; i < scan->numberOfKeys; i++)
|
|
{
|
|
/*
|
|
* Assume bloom-indexable operators to be strict, so nothing could
|
|
* be found for NULL key.
|
|
*/
|
|
if (skey->sk_flags & SK_ISNULL)
|
|
{
|
|
pfree(so->sign);
|
|
so->sign = NULL;
|
|
return 0;
|
|
}
|
|
|
|
/* Add next value to the signature */
|
|
signValue(&so->state, so->sign, skey->sk_argument,
|
|
skey->sk_attno - 1);
|
|
|
|
skey++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We're going to read the whole index. This is why we use appropriate
|
|
* buffer access strategy.
|
|
*/
|
|
bas = GetAccessStrategy(BAS_BULKREAD);
|
|
npages = RelationGetNumberOfBlocks(scan->indexRelation);
|
|
|
|
for (blkno = BLOOM_HEAD_BLKNO; blkno < npages; blkno++)
|
|
{
|
|
Buffer buffer;
|
|
Page page;
|
|
|
|
buffer = ReadBufferExtended(scan->indexRelation, MAIN_FORKNUM,
|
|
blkno, RBM_NORMAL, bas);
|
|
|
|
LockBuffer(buffer, BUFFER_LOCK_SHARE);
|
|
page = BufferGetPage(buffer, scan->xs_snapshot, scan->indexRelation,
|
|
BGP_TEST_FOR_OLD_SNAPSHOT);
|
|
|
|
if (!BloomPageIsDeleted(page))
|
|
{
|
|
OffsetNumber offset,
|
|
maxOffset = BloomPageGetMaxOffset(page);
|
|
|
|
for (offset = 1; offset <= maxOffset; offset++)
|
|
{
|
|
BloomTuple *itup = BloomPageGetTuple(&so->state, page, offset);
|
|
bool res = true;
|
|
|
|
/* Check index signature with scan signature */
|
|
for (i = 0; i < so->state.opts.bloomLength; i++)
|
|
{
|
|
if ((itup->sign[i] & so->sign[i]) != so->sign[i])
|
|
{
|
|
res = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Add matching tuples to bitmap */
|
|
if (res)
|
|
{
|
|
tbm_add_tuples(tbm, &itup->heapPtr, 1, true);
|
|
ntids++;
|
|
}
|
|
}
|
|
}
|
|
|
|
UnlockReleaseBuffer(buffer);
|
|
CHECK_FOR_INTERRUPTS();
|
|
}
|
|
FreeAccessStrategy(bas);
|
|
|
|
return ntids;
|
|
}
|