PostgreSQL Source Code git master
Loading...
Searching...
No Matches
syncscan.c File Reference
#include "postgres.h"
#include "access/syncscan.h"
#include "miscadmin.h"
#include "storage/lwlock.h"
#include "storage/shmem.h"
#include "storage/subsystems.h"
#include "utils/rel.h"
Include dependency graph for syncscan.c:

Go to the source code of this file.

Data Structures

struct  ss_scan_location_t
 
struct  ss_lru_item_t
 
struct  ss_scan_locations_t
 

Macros

#define SYNC_SCAN_NELEM   20
 
#define SYNC_SCAN_REPORT_INTERVAL   (128 * 1024 / BLCKSZ)
 
#define SizeOfScanLocations(N)    (offsetof(ss_scan_locations_t, items) + (N) * sizeof(ss_lru_item_t))
 

Typedefs

typedef struct ss_scan_location_t ss_scan_location_t
 
typedef struct ss_lru_item_t ss_lru_item_t
 
typedef struct ss_scan_locations_t ss_scan_locations_t
 

Functions

static void SyncScanShmemRequest (void *arg)
 
static void SyncScanShmemInit (void *arg)
 
static BlockNumber ss_search (RelFileLocator relfilelocator, BlockNumber location, bool set)
 
BlockNumber ss_get_location (Relation rel, BlockNumber relnblocks)
 
void ss_report_location (Relation rel, BlockNumber location)
 

Variables

const ShmemCallbacks SyncScanShmemCallbacks
 
static ss_scan_locations_tscan_locations
 

Macro Definition Documentation

◆ SizeOfScanLocations

#define SizeOfScanLocations (   N)     (offsetof(ss_scan_locations_t, items) + (N) * sizeof(ss_lru_item_t))

Definition at line 112 of file syncscan.c.

117 {
118 .request_fn = SyncScanShmemRequest,
119 .init_fn = SyncScanShmemInit,
120};
121
122/* Pointer to struct in shared memory */
124
125/* prototypes for internal functions */
126static BlockNumber ss_search(RelFileLocator relfilelocator,
127 BlockNumber location, bool set);
128
129
130/*
131 * SyncScanShmemRequest --- register this module's shared memory
132 */
133static void
135{
136 ShmemRequestStruct(.name = "Sync Scan Locations List",
138 .ptr = (void **) &scan_locations,
139 );
140}
141
142/*
143 * SyncScanShmemInit --- initialize this module's shared memory
144 */
145static void
147{
148 int i;
149
152
153 for (i = 0; i < SYNC_SCAN_NELEM; i++)
154 {
156
157 /*
158 * Initialize all slots with invalid values. As scans are started,
159 * these invalid entries will fall off the LRU list and get replaced
160 * with real entries.
161 */
166
167 item->prev = (i > 0) ?
168 (&scan_locations->items[i - 1]) : NULL;
169 item->next = (i < SYNC_SCAN_NELEM - 1) ?
170 (&scan_locations->items[i + 1]) : NULL;
171 }
172}
173
174/*
175 * ss_search --- search the scan_locations structure for an entry with the
176 * given relfilelocator.
177 *
178 * If "set" is true, the location is updated to the given location. If no
179 * entry for the given relfilelocator is found, it will be created at the head
180 * of the list with the given location, even if "set" is false.
181 *
182 * In any case, the location after possible update is returned.
183 *
184 * Caller is responsible for having acquired suitable lock on the shared
185 * data structure.
186 */
187static BlockNumber
188ss_search(RelFileLocator relfilelocator, BlockNumber location, bool set)
189{
190 ss_lru_item_t *item;
191
192 item = scan_locations->head;
193 for (;;)
194 {
195 bool match;
196
198 relfilelocator);
199
200 if (match || item->next == NULL)
201 {
202 /*
203 * If we reached the end of list and no match was found, take over
204 * the last entry
205 */
206 if (!match)
207 {
208 item->location.relfilelocator = relfilelocator;
209 item->location.location = location;
210 }
211 else if (set)
212 item->location.location = location;
213
214 /* Move the entry to the front of the LRU list */
215 if (item != scan_locations->head)
216 {
217 /* unlink */
218 if (item == scan_locations->tail)
219 scan_locations->tail = item->prev;
220 item->prev->next = item->next;
221 if (item->next)
222 item->next->prev = item->prev;
223
224 /* link */
225 item->prev = NULL;
226 item->next = scan_locations->head;
227 scan_locations->head->prev = item;
228 scan_locations->head = item;
229 }
230
231 return item->location.location;
232 }
233
234 item = item->next;
235 }
236
237 /* not reached */
238}
239
240/*
241 * ss_get_location --- get the optimal starting location for scan
242 *
243 * Returns the last-reported location of a sequential scan on the
244 * relation, or 0 if no valid location is found.
245 *
246 * We expect the caller has just done RelationGetNumberOfBlocks(), and
247 * so that number is passed in rather than computing it again. The result
248 * is guaranteed less than relnblocks (assuming that's > 0).
249 */
252{
254
256 startloc = ss_search(rel->rd_locator, 0, false);
258
259 /*
260 * If the location is not a valid block number for this scan, start at 0.
261 *
262 * This can happen if for instance a VACUUM truncated the table since the
263 * location was saved.
264 */
265 if (startloc >= relnblocks)
266 startloc = 0;
267
268#ifdef TRACE_SYNCSCAN
269 if (trace_syncscan)
270 elog(LOG,
271 "SYNC_SCAN: start \"%s\" (size %u) at %u",
273#endif
274
275 return startloc;
276}
277
278/*
279 * ss_report_location --- update the current scan location
280 *
281 * Writes an entry into the shared Sync Scan state of the form
282 * (relfilelocator, blocknumber), overwriting any existing entry for the
283 * same relfilelocator.
284 */
285void
287{
288#ifdef TRACE_SYNCSCAN
289 if (trace_syncscan)
290 {
291 if ((location % 1024) == 0)
292 elog(LOG,
293 "SYNC_SCAN: scanning \"%s\" at %u",
294 RelationGetRelationName(rel), location);
295 }
296#endif
297
298 /*
299 * To reduce lock contention, only report scan progress every N pages. For
300 * the same reason, don't block if the lock isn't immediately available.
301 * Missing a few updates isn't critical, it just means that a new scan
302 * that wants to join the pack will start a little bit behind the head of
303 * the scan. Hopefully the pages are still in OS cache and the scan
304 * catches up quickly.
305 */
306 if ((location % SYNC_SCAN_REPORT_INTERVAL) == 0)
307 {
309 {
310 (void) ss_search(rel->rd_locator, location, true);
312 }
313#ifdef TRACE_SYNCSCAN
314 else if (trace_syncscan)
315 elog(LOG,
316 "SYNC_SCAN: missed update for \"%s\" at %u",
317 RelationGetRelationName(rel), location);
318#endif
319 }
320}
uint32 BlockNumber
Definition block.h:31
#define InvalidBlockNumber
Definition block.h:33
Datum arg
Definition elog.c:1322
#define LOG
Definition elog.h:32
#define elog(elevel,...)
Definition elog.h:228
int i
Definition isn.c:77
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1150
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1767
bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1321
@ LW_EXCLUSIVE
Definition lwlock.h:104
#define InvalidOid
static int fb(int x)
#define RelationGetRelationName(relation)
Definition rel.h:550
#define RelFileLocatorEquals(locator1, locator2)
#define InvalidRelFileNumber
Definition relpath.h:26
#define ShmemRequestStruct(...)
Definition shmem.h:176
RelFileNumber relNumber
RelFileLocator rd_locator
Definition rel.h:57
ss_scan_location_t location
Definition syncscan.c:102
struct ss_lru_item_t * next
Definition syncscan.c:101
struct ss_lru_item_t * prev
Definition syncscan.c:100
RelFileLocator relfilelocator
Definition syncscan.c:94
BlockNumber location
Definition syncscan.c:95
ss_lru_item_t * head
Definition syncscan.c:107
ss_lru_item_t items[FLEXIBLE_ARRAY_MEMBER]
Definition syncscan.c:109
ss_lru_item_t * tail
Definition syncscan.c:108
void ss_report_location(Relation rel, BlockNumber location)
Definition syncscan.c:287
static void SyncScanShmemInit(void *arg)
Definition syncscan.c:147
static ss_scan_locations_t * scan_locations
Definition syncscan.c:124
static void SyncScanShmemRequest(void *arg)
Definition syncscan.c:135
BlockNumber ss_get_location(Relation rel, BlockNumber relnblocks)
Definition syncscan.c:252
static BlockNumber ss_search(RelFileLocator relfilelocator, BlockNumber location, bool set)
Definition syncscan.c:189
#define SYNC_SCAN_NELEM
Definition syncscan.c:72
#define SizeOfScanLocations(N)
Definition syncscan.c:112
#define SYNC_SCAN_REPORT_INTERVAL
Definition syncscan.c:84
const char * name

◆ SYNC_SCAN_NELEM

#define SYNC_SCAN_NELEM   20

Definition at line 72 of file syncscan.c.

◆ SYNC_SCAN_REPORT_INTERVAL

#define SYNC_SCAN_REPORT_INTERVAL   (128 * 1024 / BLCKSZ)

Definition at line 84 of file syncscan.c.

Typedef Documentation

◆ ss_lru_item_t

◆ ss_scan_location_t

◆ ss_scan_locations_t

Function Documentation

◆ ss_get_location()

BlockNumber ss_get_location ( Relation  rel,
BlockNumber  relnblocks 
)

Definition at line 252 of file syncscan.c.

253{
255
257 startloc = ss_search(rel->rd_locator, 0, false);
259
260 /*
261 * If the location is not a valid block number for this scan, start at 0.
262 *
263 * This can happen if for instance a VACUUM truncated the table since the
264 * location was saved.
265 */
266 if (startloc >= relnblocks)
267 startloc = 0;
268
269#ifdef TRACE_SYNCSCAN
270 if (trace_syncscan)
271 elog(LOG,
272 "SYNC_SCAN: start \"%s\" (size %u) at %u",
274#endif
275
276 return startloc;
277}

References elog, fb(), LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), RelationData::rd_locator, RelationGetRelationName, and ss_search().

Referenced by initscan(), and table_block_parallelscan_startblock_init().

◆ ss_report_location()

void ss_report_location ( Relation  rel,
BlockNumber  location 
)

Definition at line 287 of file syncscan.c.

288{
289#ifdef TRACE_SYNCSCAN
290 if (trace_syncscan)
291 {
292 if ((location % 1024) == 0)
293 elog(LOG,
294 "SYNC_SCAN: scanning \"%s\" at %u",
295 RelationGetRelationName(rel), location);
296 }
297#endif
298
299 /*
300 * To reduce lock contention, only report scan progress every N pages. For
301 * the same reason, don't block if the lock isn't immediately available.
302 * Missing a few updates isn't critical, it just means that a new scan
303 * that wants to join the pack will start a little bit behind the head of
304 * the scan. Hopefully the pages are still in OS cache and the scan
305 * catches up quickly.
306 */
307 if ((location % SYNC_SCAN_REPORT_INTERVAL) == 0)
308 {
310 {
311 (void) ss_search(rel->rd_locator, location, true);
313 }
314#ifdef TRACE_SYNCSCAN
315 else if (trace_syncscan)
316 elog(LOG,
317 "SYNC_SCAN: missed update for \"%s\" at %u",
318 RelationGetRelationName(rel), location);
319#endif
320 }
321}

References elog, fb(), LOG, LW_EXCLUSIVE, LWLockConditionalAcquire(), LWLockRelease(), RelationData::rd_locator, RelationGetRelationName, ss_search(), and SYNC_SCAN_REPORT_INTERVAL.

Referenced by heapam_scan_sample_next_block(), heapgettup_advance_block(), and table_block_parallelscan_nextpage().

◆ ss_search()

static BlockNumber ss_search ( RelFileLocator  relfilelocator,
BlockNumber  location,
bool  set 
)
static

Definition at line 189 of file syncscan.c.

190{
191 ss_lru_item_t *item;
192
193 item = scan_locations->head;
194 for (;;)
195 {
196 bool match;
197
199 relfilelocator);
200
201 if (match || item->next == NULL)
202 {
203 /*
204 * If we reached the end of list and no match was found, take over
205 * the last entry
206 */
207 if (!match)
208 {
209 item->location.relfilelocator = relfilelocator;
210 item->location.location = location;
211 }
212 else if (set)
213 item->location.location = location;
214
215 /* Move the entry to the front of the LRU list */
216 if (item != scan_locations->head)
217 {
218 /* unlink */
219 if (item == scan_locations->tail)
220 scan_locations->tail = item->prev;
221 item->prev->next = item->next;
222 if (item->next)
223 item->next->prev = item->prev;
224
225 /* link */
226 item->prev = NULL;
227 item->next = scan_locations->head;
228 scan_locations->head->prev = item;
229 scan_locations->head = item;
230 }
231
232 return item->location.location;
233 }
234
235 item = item->next;
236 }
237
238 /* not reached */
239}

References fb(), ss_scan_locations_t::head, ss_scan_location_t::location, ss_lru_item_t::location, ss_lru_item_t::next, ss_lru_item_t::prev, ss_scan_location_t::relfilelocator, RelFileLocatorEquals, scan_locations, and ss_scan_locations_t::tail.

Referenced by ss_get_location(), and ss_report_location().

◆ SyncScanShmemInit()

static void SyncScanShmemInit ( void arg)
static

Definition at line 147 of file syncscan.c.

148{
149 int i;
150
153
154 for (i = 0; i < SYNC_SCAN_NELEM; i++)
155 {
157
158 /*
159 * Initialize all slots with invalid values. As scans are started,
160 * these invalid entries will fall off the LRU list and get replaced
161 * with real entries.
162 */
167
168 item->prev = (i > 0) ?
169 (&scan_locations->items[i - 1]) : NULL;
170 item->next = (i < SYNC_SCAN_NELEM - 1) ?
171 (&scan_locations->items[i + 1]) : NULL;
172 }
173}

References RelFileLocator::dbOid, fb(), ss_scan_locations_t::head, i, InvalidBlockNumber, InvalidOid, InvalidRelFileNumber, ss_scan_locations_t::items, ss_scan_location_t::location, ss_lru_item_t::location, ss_lru_item_t::next, ss_lru_item_t::prev, ss_scan_location_t::relfilelocator, RelFileLocator::relNumber, scan_locations, RelFileLocator::spcOid, SYNC_SCAN_NELEM, and ss_scan_locations_t::tail.

◆ SyncScanShmemRequest()

static void SyncScanShmemRequest ( void arg)
static

Definition at line 135 of file syncscan.c.

136{
137 ShmemRequestStruct(.name = "Sync Scan Locations List",
139 .ptr = (void **) &scan_locations,
140 );
141}

References name, scan_locations, ShmemRequestStruct, SizeOfScanLocations, and SYNC_SCAN_NELEM.

Variable Documentation

◆ scan_locations

ss_scan_locations_t* scan_locations
static

Definition at line 124 of file syncscan.c.

Referenced by ss_search(), SyncScanShmemInit(), and SyncScanShmemRequest().

◆ SyncScanShmemCallbacks

const ShmemCallbacks SyncScanShmemCallbacks
Initial value:
= {
.request_fn = SyncScanShmemRequest,
.init_fn = SyncScanShmemInit,
}

Definition at line 118 of file syncscan.c.

118 {
119 .request_fn = SyncScanShmemRequest,
120 .init_fn = SyncScanShmemInit,
121};