summaryrefslogtreecommitdiff
path: root/src/backend/access/nbtree/nbtscan.c
blob: 3de9f39d3252ac0eba3763a91da842ddbbe094a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*-------------------------------------------------------------------------
 *
 * btscan.c--
 *    manage scans on btrees.
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *    $Header: /cvsroot/pgsql/src/backend/access/nbtree/Attic/nbtscan.c,v 1.6 1996/11/15 18:37:00 momjian Exp $
 *
 *
 * NOTES
 *   Because we can be doing an index scan on a relation while we update
 *   it, we need to avoid missing data that moves around in the index.
 *   The routines and global variables in this file guarantee that all
 *   scans in the local address space stay correctly positioned.  This
 *   is all we need to worry about, since write locking guarantees that
 *   no one else will be on the same page at the same time as we are.
 *
 *   The scheme is to manage a list of active scans in the current backend.
 *   Whenever we add or remove records from an index, or whenever we
 *   split a leaf page, we check the list of active scans to see if any
 *   has been affected.  A scan is affected only if it is on the same
 *   relation, and the same page, as the update.
 *
 *-------------------------------------------------------------------------
 */

#include <postgres.h>

#include <storage/bufpage.h>
#include <access/nbtree.h>

typedef struct BTScanListData {
    IndexScanDesc		btsl_scan;
    struct BTScanListData	*btsl_next;
} BTScanListData;

typedef BTScanListData	*BTScanList;

static BTScanList	BTScans = (BTScanList) NULL;
     
/*
 *  _bt_regscan() -- register a new scan.
 */
void
_bt_regscan(IndexScanDesc scan)
{
    BTScanList new_el;
    
    new_el = (BTScanList) palloc(sizeof(BTScanListData));
    new_el->btsl_scan = scan;
    new_el->btsl_next = BTScans;
    BTScans = new_el;
}

/*
 *  _bt_dropscan() -- drop a scan from the scan list
 */
void
_bt_dropscan(IndexScanDesc scan)
{
    BTScanList chk, last;
    
    last = (BTScanList) NULL;
    for (chk = BTScans;
	 chk != (BTScanList) NULL && chk->btsl_scan != scan;
	 chk = chk->btsl_next) {
	last = chk;
    }
    
    if (chk == (BTScanList) NULL)
	elog(WARN, "btree scan list trashed; can't find 0x%lx", scan);
    
    if (last == (BTScanList) NULL)
	BTScans = chk->btsl_next;
    else
	last->btsl_next = chk->btsl_next;
    
    pfree (chk);
}

void
_bt_adjscans(Relation rel, ItemPointer tid)
{
    BTScanList l;
    Oid relid;
    
    relid = rel->rd_id;
    for (l = BTScans; l != (BTScanList) NULL; l = l->btsl_next) {
	if (relid == l->btsl_scan->relation->rd_id)
	    _bt_scandel(l->btsl_scan, ItemPointerGetBlockNumber(tid),
			ItemPointerGetOffsetNumber(tid));
    }
}

void
_bt_scandel(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno)
{
    ItemPointer current;
    Buffer buf;
    BTScanOpaque so;
    
    if (!_bt_scantouched(scan, blkno, offno))
	return;
    
    so = (BTScanOpaque) scan->opaque;
    buf = so->btso_curbuf;
    
    current = &(scan->currentItemData);
    if (ItemPointerIsValid(current)
	&& ItemPointerGetBlockNumber(current) == blkno
	&& ItemPointerGetOffsetNumber(current) >= offno) {
	_bt_step(scan, &buf, BackwardScanDirection);
	so->btso_curbuf = buf;
    }
    
    current = &(scan->currentMarkData);
    if (ItemPointerIsValid(current)
	&& ItemPointerGetBlockNumber(current) == blkno
	&& ItemPointerGetOffsetNumber(current) >= offno) {
	ItemPointerData tmp;
	tmp = *current;
	*current = scan->currentItemData;
	scan->currentItemData = tmp;
	_bt_step(scan, &buf, BackwardScanDirection);
	so->btso_mrkbuf = buf;
	tmp = *current;
	*current = scan->currentItemData;
	scan->currentItemData = tmp;
    }
}

bool
_bt_scantouched(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno)
{
    ItemPointer current;
    
    current = &(scan->currentItemData);
    if (ItemPointerIsValid(current)
	&& ItemPointerGetBlockNumber(current) == blkno
	&& ItemPointerGetOffsetNumber(current) >= offno)
	return (true);
    
    current = &(scan->currentMarkData);
    if (ItemPointerIsValid(current)
	&& ItemPointerGetBlockNumber(current) == blkno
	&& ItemPointerGetOffsetNumber(current) >= offno)
	return (true);
    
    return (false);
}