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 "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 BlockNumber ss_search (RelFileLocator relfilelocator, BlockNumber location, bool set)
 
Size SyncScanShmemSize (void)
 
void SyncScanShmemInit (void)
 
BlockNumber ss_get_location (Relation rel, BlockNumber relnblocks)
 
void ss_report_location (Relation rel, BlockNumber location)
 

Variables

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 111 of file syncscan.c.

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

◆ SYNC_SCAN_NELEM

#define SYNC_SCAN_NELEM   20

Definition at line 71 of file syncscan.c.

◆ SYNC_SCAN_REPORT_INTERVAL

#define SYNC_SCAN_REPORT_INTERVAL   (128 * 1024 / BLCKSZ)

Definition at line 83 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 254 of file syncscan.c.

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

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 289 of file syncscan.c.

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

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 191 of file syncscan.c.

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

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()

void SyncScanShmemInit ( void  )

Definition at line 135 of file syncscan.c.

136{
137 int i;
138 bool found;
139
141 ShmemInitStruct("Sync Scan Locations List",
143 &found);
144
146 {
147 /* Initialize shared memory area */
148 Assert(!found);
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
160 * replaced 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 else
174 Assert(found);
175}

References Assert, RelFileLocator::dbOid, fb(), ss_scan_locations_t::head, i, InvalidBlockNumber, InvalidOid, InvalidRelFileNumber, IsUnderPostmaster, 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, ShmemInitStruct(), SizeOfScanLocations, RelFileLocator::spcOid, SYNC_SCAN_NELEM, and ss_scan_locations_t::tail.

Referenced by CreateOrAttachShmemStructs().

◆ SyncScanShmemSize()

Size SyncScanShmemSize ( void  )

Definition at line 126 of file syncscan.c.

127{
129}

References SizeOfScanLocations, and SYNC_SCAN_NELEM.

Referenced by CalculateShmemSize().

Variable Documentation

◆ scan_locations

ss_scan_locations_t* scan_locations
static

Definition at line 115 of file syncscan.c.

Referenced by ss_search(), and SyncScanShmemInit().