PostgreSQL Source Code  git master
sync.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * sync.c
4  * File synchronization management code.
5  *
6  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/storage/sync/sync.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <sys/file.h>
20 
21 #include "access/commit_ts.h"
22 #include "access/clog.h"
23 #include "access/multixact.h"
24 #include "access/xlog.h"
25 #include "access/xlogutils.h"
26 #include "commands/tablespace.h"
27 #include "miscadmin.h"
28 #include "pgstat.h"
29 #include "portability/instr_time.h"
30 #include "postmaster/bgwriter.h"
31 #include "storage/bufmgr.h"
32 #include "storage/ipc.h"
33 #include "storage/md.h"
34 #include "utils/hsearch.h"
35 #include "utils/inval.h"
36 #include "utils/memutils.h"
37 
38 static MemoryContext pendingOpsCxt; /* context for the pending ops state */
39 
40 /*
41  * In some contexts (currently, standalone backends and the checkpointer)
42  * we keep track of pending fsync operations: we need to remember all relation
43  * segments that have been written since the last checkpoint, so that we can
44  * fsync them down to disk before completing the next checkpoint. This hash
45  * table remembers the pending operations. We use a hash table mostly as
46  * a convenient way of merging duplicate requests.
47  *
48  * We use a similar mechanism to remember no-longer-needed files that can
49  * be deleted after the next checkpoint, but we use a linked list instead of
50  * a hash table, because we don't expect there to be any duplicate requests.
51  *
52  * These mechanisms are only used for non-temp relations; we never fsync
53  * temp rels, nor do we need to postpone their deletion (see comments in
54  * mdunlink).
55  *
56  * (Regular backends do not track pending operations locally, but forward
57  * them to the checkpointer.)
58  */
59 typedef uint16 CycleCtr; /* can be any convenient integer size */
60 
61 typedef struct
62 {
63  FileTag tag; /* identifies handler and file */
64  CycleCtr cycle_ctr; /* sync_cycle_ctr of oldest request */
65  bool canceled; /* canceled is true if we canceled "recently" */
67 
68 typedef struct
69 {
70  FileTag tag; /* identifies handler and file */
71  CycleCtr cycle_ctr; /* checkpoint_cycle_ctr when request was made */
73 
74 static HTAB *pendingOps = NULL;
76 static MemoryContext pendingOpsCxt; /* context for the above */
77 
80 
81 /* Intervals for calling AbsorbSyncRequests */
82 #define FSYNCS_PER_ABSORB 10
83 #define UNLINKS_PER_ABSORB 10
84 
85 /*
86  * Function pointers for handling sync and unlink requests.
87  */
88 typedef struct SyncOps
89 {
90  int (*sync_syncfiletag) (const FileTag *ftag, char *path);
91  int (*sync_unlinkfiletag) (const FileTag *ftag, char *path);
92  bool (*sync_filetagmatches) (const FileTag *ftag,
93  const FileTag *candidate);
94 } SyncOps;
95 
96 /*
97  * These indexes must correspond to the values of the SyncRequestHandler enum.
98  */
99 static const SyncOps syncsw[] = {
100  /* magnetic disk */
101  [SYNC_HANDLER_MD] = {
103  .sync_unlinkfiletag = mdunlinkfiletag,
104  .sync_filetagmatches = mdfiletagmatches
105  },
106  /* pg_xact */
107  [SYNC_HANDLER_CLOG] = {
108  .sync_syncfiletag = clogsyncfiletag
109  },
110  /* pg_commit_ts */
112  .sync_syncfiletag = committssyncfiletag
113  },
114  /* pg_multixact/offsets */
116  .sync_syncfiletag = multixactoffsetssyncfiletag
117  },
118  /* pg_multixact/members */
120  .sync_syncfiletag = multixactmemberssyncfiletag
121  }
122 };
123 
124 /*
125  * Initialize data structures for the file sync tracking.
126  */
127 void
128 InitSync(void)
129 {
130  /*
131  * Create pending-operations hashtable if we need it. Currently, we need
132  * it if we are standalone (not under a postmaster) or if we are a
133  * checkpointer auxiliary process.
134  */
136  {
137  HASHCTL hash_ctl;
138 
139  /*
140  * XXX: The checkpointer needs to add entries to the pending ops table
141  * when absorbing fsync requests. That is done within a critical
142  * section, which isn't usually allowed, but we make an exception. It
143  * means that there's a theoretical possibility that you run out of
144  * memory while absorbing fsync requests, which leads to a PANIC.
145  * Fortunately the hash table is small so that's unlikely to happen in
146  * practice.
147  */
148  pendingOpsCxt = AllocSetContextCreate(TopMemoryContext,
149  "Pending ops context",
151  MemoryContextAllowInCriticalSection(pendingOpsCxt, true);
152 
153  hash_ctl.keysize = sizeof(FileTag);
154  hash_ctl.entrysize = sizeof(PendingFsyncEntry);
155  hash_ctl.hcxt = pendingOpsCxt;
156  pendingOps = hash_create("Pending Ops Table",
157  100L,
158  &hash_ctl,
160  pendingUnlinks = NIL;
161  }
162 
163 }
164 
165 /*
166  * SyncPreCheckpoint() -- Do pre-checkpoint work
167  *
168  * To distinguish unlink requests that arrived before this checkpoint
169  * started from those that arrived during the checkpoint, we use a cycle
170  * counter similar to the one we use for fsync requests. That cycle
171  * counter is incremented here.
172  *
173  * This must be called *before* the checkpoint REDO point is determined.
174  * That ensures that we won't delete files too soon.
175  *
176  * Note that we can't do anything here that depends on the assumption
177  * that the checkpoint will be completed.
178  */
179 void
181 {
182  /*
183  * Any unlink requests arriving after this point will be assigned the next
184  * cycle counter, and won't be unlinked until next checkpoint.
185  */
187 }
188 
189 /*
190  * SyncPostCheckpoint() -- Do post-checkpoint work
191  *
192  * Remove any lingering files that can now be safely removed.
193  */
194 void
196 {
197  int absorb_counter;
198 
199  absorb_counter = UNLINKS_PER_ABSORB;
200  while (pendingUnlinks != NIL)
201  {
202  PendingUnlinkEntry *entry = (PendingUnlinkEntry *) linitial(pendingUnlinks);
203  char path[MAXPGPATH];
204 
205  /*
206  * New entries are appended to the end, so if the entry is new we've
207  * reached the end of old entries.
208  *
209  * Note: if just the right number of consecutive checkpoints fail, we
210  * could be fooled here by cycle_ctr wraparound. However, the only
211  * consequence is that we'd delay unlinking for one more checkpoint,
212  * which is perfectly tolerable.
213  */
214  if (entry->cycle_ctr == checkpoint_cycle_ctr)
215  break;
216 
217  /* Unlink the file */
218  if (syncsw[entry->tag.handler].sync_unlinkfiletag(&entry->tag,
219  path) < 0)
220  {
221  /*
222  * There's a race condition, when the database is dropped at the
223  * same time that we process the pending unlink requests. If the
224  * DROP DATABASE deletes the file before we do, we will get ENOENT
225  * here. rmtree() also has to ignore ENOENT errors, to deal with
226  * the possibility that we delete the file first.
227  */
228  if (errno != ENOENT)
231  errmsg("could not remove file \"%s\": %m", path)));
232  }
233 
234  /* And remove the list entry */
235  pendingUnlinks = list_delete_first(pendingUnlinks);
236  pfree(entry);
237 
238  /*
239  * As in ProcessSyncRequests, we don't want to stop absorbing fsync
240  * requests for a long time when there are many deletions to be done.
241  * We can safely call AbsorbSyncRequests() at this point in the loop
242  * (note it might try to delete list entries).
243  */
244  if (--absorb_counter <= 0)
245  {
247  absorb_counter = UNLINKS_PER_ABSORB;
248  }
249  }
250 }
251 
252 /*
253 
254  * ProcessSyncRequests() -- Process queued fsync requests.
255  */
256 void
258 {
259  static bool sync_in_progress = false;
260 
261  HASH_SEQ_STATUS hstat;
262  PendingFsyncEntry *entry;
263  int absorb_counter;
264 
265  /* Statistics on sync times */
266  int processed = 0;
267  instr_time sync_start,
268  sync_end,
269  sync_diff;
270  uint64 elapsed;
271  uint64 longest = 0;
272  uint64 total_elapsed = 0;
273 
274  /*
275  * This is only called during checkpoints, and checkpoints should only
276  * occur in processes that have created a pendingOps.
277  */
278  if (!pendingOps)
279  elog(ERROR, "cannot sync without a pendingOps table");
280 
281  /*
282  * If we are in the checkpointer, the sync had better include all fsync
283  * requests that were queued by backends up to this point. The tightest
284  * race condition that could occur is that a buffer that must be written
285  * and fsync'd for the checkpoint could have been dumped by a backend just
286  * before it was visited by BufferSync(). We know the backend will have
287  * queued an fsync request before clearing the buffer's dirtybit, so we
288  * are safe as long as we do an Absorb after completing BufferSync().
289  */
291 
292  /*
293  * To avoid excess fsync'ing (in the worst case, maybe a never-terminating
294  * checkpoint), we want to ignore fsync requests that are entered into the
295  * hashtable after this point --- they should be processed next time,
296  * instead. We use sync_cycle_ctr to tell old entries apart from new
297  * ones: new ones will have cycle_ctr equal to the incremented value of
298  * sync_cycle_ctr.
299  *
300  * In normal circumstances, all entries present in the table at this point
301  * will have cycle_ctr exactly equal to the current (about to be old)
302  * value of sync_cycle_ctr. However, if we fail partway through the
303  * fsync'ing loop, then older values of cycle_ctr might remain when we
304  * come back here to try again. Repeated checkpoint failures would
305  * eventually wrap the counter around to the point where an old entry
306  * might appear new, causing us to skip it, possibly allowing a checkpoint
307  * to succeed that should not have. To forestall wraparound, any time the
308  * previous ProcessSyncRequests() failed to complete, run through the
309  * table and forcibly set cycle_ctr = sync_cycle_ctr.
310  *
311  * Think not to merge this loop with the main loop, as the problem is
312  * exactly that that loop may fail before having visited all the entries.
313  * From a performance point of view it doesn't matter anyway, as this path
314  * will never be taken in a system that's functioning normally.
315  */
316  if (sync_in_progress)
317  {
318  /* prior try failed, so update any stale cycle_ctr values */
319  hash_seq_init(&hstat, pendingOps);
320  while ((entry = (PendingFsyncEntry *) hash_seq_search(&hstat)) != NULL)
321  {
322  entry->cycle_ctr = sync_cycle_ctr;
323  }
324  }
325 
326  /* Advance counter so that new hashtable entries are distinguishable */
327  sync_cycle_ctr++;
328 
329  /* Set flag to detect failure if we don't reach the end of the loop */
330  sync_in_progress = true;
331 
332  /* Now scan the hashtable for fsync requests to process */
333  absorb_counter = FSYNCS_PER_ABSORB;
334  hash_seq_init(&hstat, pendingOps);
335  while ((entry = (PendingFsyncEntry *) hash_seq_search(&hstat)) != NULL)
336  {
337  int failures;
338 
339  /*
340  * If the entry is new then don't process it this time; it is new.
341  * Note "continue" bypasses the hash-remove call at the bottom of the
342  * loop.
343  */
344  if (entry->cycle_ctr == sync_cycle_ctr)
345  continue;
346 
347  /* Else assert we haven't missed it */
348  Assert((CycleCtr) (entry->cycle_ctr + 1) == sync_cycle_ctr);
349 
350  /*
351  * If fsync is off then we don't have to bother opening the file at
352  * all. (We delay checking until this point so that changing fsync on
353  * the fly behaves sensibly.)
354  */
355  if (enableFsync)
356  {
357  /*
358  * If in checkpointer, we want to absorb pending requests every so
359  * often to prevent overflow of the fsync request queue. It is
360  * unspecified whether newly-added entries will be visited by
361  * hash_seq_search, but we don't care since we don't need to
362  * process them anyway.
363  */
364  if (--absorb_counter <= 0)
365  {
367  absorb_counter = FSYNCS_PER_ABSORB;
368  }
369 
370  /*
371  * The fsync table could contain requests to fsync segments that
372  * have been deleted (unlinked) by the time we get to them. Rather
373  * than just hoping an ENOENT (or EACCES on Windows) error can be
374  * ignored, what we do on error is absorb pending requests and
375  * then retry. Since mdunlink() queues a "cancel" message before
376  * actually unlinking, the fsync request is guaranteed to be
377  * marked canceled after the absorb if it really was this case.
378  * DROP DATABASE likewise has to tell us to forget fsync requests
379  * before it starts deletions.
380  */
381  for (failures = 0; !entry->canceled; failures++)
382  {
383  char path[MAXPGPATH];
384 
385  INSTR_TIME_SET_CURRENT(sync_start);
386  if (syncsw[entry->tag.handler].sync_syncfiletag(&entry->tag,
387  path) == 0)
388  {
389  /* Success; update statistics about sync timing */
390  INSTR_TIME_SET_CURRENT(sync_end);
391  sync_diff = sync_end;
392  INSTR_TIME_SUBTRACT(sync_diff, sync_start);
393  elapsed = INSTR_TIME_GET_MICROSEC(sync_diff);
394  if (elapsed > longest)
395  longest = elapsed;
396  total_elapsed += elapsed;
397  processed++;
398 
399  if (log_checkpoints)
400  elog(DEBUG1, "checkpoint sync: number=%d file=%s time=%.3f ms",
401  processed,
402  path,
403  (double) elapsed / 1000);
404 
405  break; /* out of retry loop */
406  }
407 
408  /*
409  * It is possible that the relation has been dropped or
410  * truncated since the fsync request was entered. Therefore,
411  * allow ENOENT, but only if we didn't fail already on this
412  * file.
413  */
414  if (!FILE_POSSIBLY_DELETED(errno) || failures > 0)
417  errmsg("could not fsync file \"%s\": %m",
418  path)));
419  else
420  ereport(DEBUG1,
422  errmsg_internal("could not fsync file \"%s\" but retrying: %m",
423  path)));
424 
425  /*
426  * Absorb incoming requests and check to see if a cancel
427  * arrived for this relation fork.
428  */
430  absorb_counter = FSYNCS_PER_ABSORB; /* might as well... */
431  } /* end retry loop */
432  }
433 
434  /* We are done with this entry, remove it */
435  if (hash_search(pendingOps, &entry->tag, HASH_REMOVE, NULL) == NULL)
436  elog(ERROR, "pendingOps corrupted");
437  } /* end loop over hashtable entries */
438 
439  /* Return sync performance metrics for report at checkpoint end */
440  CheckpointStats.ckpt_sync_rels = processed;
442  CheckpointStats.ckpt_agg_sync_time = total_elapsed;
443 
444  /* Flag successful completion of ProcessSyncRequests */
445  sync_in_progress = false;
446 }
447 
448 /*
449  * RememberSyncRequest() -- callback from checkpointer side of sync request
450  *
451  * We stuff fsync requests into the local hash table for execution
452  * during the checkpointer's next checkpoint. UNLINK requests go into a
453  * separate linked list, however, because they get processed separately.
454  *
455  * See sync.h for more information on the types of sync requests supported.
456  */
457 void
459 {
460  Assert(pendingOps);
461 
462  if (type == SYNC_FORGET_REQUEST)
463  {
464  PendingFsyncEntry *entry;
465 
466  /* Cancel previously entered request */
467  entry = (PendingFsyncEntry *) hash_search(pendingOps,
468  (void *) ftag,
469  HASH_FIND,
470  NULL);
471  if (entry != NULL)
472  entry->canceled = true;
473  }
474  else if (type == SYNC_FILTER_REQUEST)
475  {
476  HASH_SEQ_STATUS hstat;
477  PendingFsyncEntry *entry;
478  ListCell *cell;
479 
480  /* Cancel matching fsync requests */
481  hash_seq_init(&hstat, pendingOps);
482  while ((entry = (PendingFsyncEntry *) hash_seq_search(&hstat)) != NULL)
483  {
484  if (entry->tag.handler == ftag->handler &&
485  syncsw[ftag->handler].sync_filetagmatches(ftag, &entry->tag))
486  entry->canceled = true;
487  }
488 
489  /* Remove matching unlink requests */
490  foreach(cell, pendingUnlinks)
491  {
492  PendingUnlinkEntry *entry = (PendingUnlinkEntry *) lfirst(cell);
493 
494  if (entry->tag.handler == ftag->handler &&
495  syncsw[ftag->handler].sync_filetagmatches(ftag, &entry->tag))
496  {
497  pendingUnlinks = foreach_delete_current(pendingUnlinks, cell);
498  pfree(entry);
499  }
500  }
501  }
502  else if (type == SYNC_UNLINK_REQUEST)
503  {
504  /* Unlink request: put it in the linked list */
505  MemoryContext oldcxt = MemoryContextSwitchTo(pendingOpsCxt);
506  PendingUnlinkEntry *entry;
507 
508  entry = palloc(sizeof(PendingUnlinkEntry));
509  entry->tag = *ftag;
511 
512  pendingUnlinks = lappend(pendingUnlinks, entry);
513 
514  MemoryContextSwitchTo(oldcxt);
515  }
516  else
517  {
518  /* Normal case: enter a request to fsync this segment */
519  MemoryContext oldcxt = MemoryContextSwitchTo(pendingOpsCxt);
520  PendingFsyncEntry *entry;
521  bool found;
522 
523  Assert(type == SYNC_REQUEST);
524 
525  entry = (PendingFsyncEntry *) hash_search(pendingOps,
526  (void *) ftag,
527  HASH_ENTER,
528  &found);
529  /* if new entry, or was previously canceled, initialize it */
530  if (!found || entry->canceled)
531  {
532  entry->cycle_ctr = sync_cycle_ctr;
533  entry->canceled = false;
534  }
535 
536  /*
537  * NB: it's intentional that we don't change cycle_ctr if the entry
538  * already exists. The cycle_ctr must represent the oldest fsync
539  * request that could be in the entry.
540  */
541 
542  MemoryContextSwitchTo(oldcxt);
543  }
544 }
545 
546 /*
547  * Register the sync request locally, or forward it to the checkpointer.
548  *
549  * If retryOnError is true, we'll keep trying if there is no space in the
550  * queue. Return true if we succeeded, or false if there wasn't space.
551  */
552 bool
554  bool retryOnError)
555 {
556  bool ret;
557 
558  if (pendingOps != NULL)
559  {
560  /* standalone backend or startup process: fsync state is local */
561  RememberSyncRequest(ftag, type);
562  return true;
563  }
564 
565  for (;;)
566  {
567  /*
568  * Notify the checkpointer about it. If we fail to queue a message in
569  * retryOnError mode, we have to sleep and try again ... ugly, but
570  * hopefully won't happen often.
571  *
572  * XXX should we CHECK_FOR_INTERRUPTS in this loop? Escaping with an
573  * error in the case of SYNC_UNLINK_REQUEST would leave the
574  * no-longer-used file still present on disk, which would be bad, so
575  * I'm inclined to assume that the checkpointer will always empty the
576  * queue soon.
577  */
578  ret = ForwardSyncRequest(ftag, type);
579 
580  /*
581  * If we are successful in queueing the request, or we failed and were
582  * instructed not to retry on error, break.
583  */
584  if (ret || (!ret && !retryOnError))
585  break;
586 
587  pg_usleep(10000L);
588  }
589 
590  return ret;
591 }
void ProcessSyncRequests(void)
Definition: sync.c:257
#define NIL
Definition: pg_list.h:65
uint64 ckpt_agg_sync_time
Definition: xlog.h:235
void RememberSyncRequest(const FileTag *ftag, SyncRequestType type)
Definition: sync.c:458
Definition: sync.c:88
bool log_checkpoints
Definition: xlog.c:106
int ckpt_sync_rels
Definition: xlog.h:233
#define AllocSetContextCreate
Definition: memutils.h:173
#define DEBUG1
Definition: elog.h:25
CycleCtr cycle_ctr
Definition: sync.c:71
#define HASH_CONTEXT
Definition: hsearch.h:102
void MemoryContextAllowInCriticalSection(MemoryContext context, bool allow)
Definition: mcxt.c:418
#define HASH_ELEM
Definition: hsearch.h:95
MemoryContext hcxt
Definition: hsearch.h:86
FileTag tag
Definition: sync.c:63
int committssyncfiletag(const FileTag *ftag, char *path)
Definition: commit_ts.c:1028
struct timeval instr_time
Definition: instr_time.h:150
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Size entrysize
Definition: hsearch.h:76
struct SyncOps SyncOps
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
static CycleCtr checkpoint_cycle_ctr
Definition: sync.c:79
struct FileTag FileTag
uint16 CycleCtr
Definition: sync.c:59
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
void pg_usleep(long microsec)
Definition: signal.c:53
Definition: dynahash.c:219
unsigned short uint16
Definition: c.h:440
void AbsorbSyncRequests(void)
void pfree(void *pointer)
Definition: mcxt.c:1169
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:46
static List * pendingUnlinks
Definition: sync.c:75
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:170
#define AmCheckpointerProcess()
Definition: miscadmin.h:447
#define MAXPGPATH
bool ForwardSyncRequest(const FileTag *ftag, SyncRequestType type)
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:195
int multixactoffsetssyncfiletag(const FileTag *ftag, char *path)
Definition: multixact.c:3415
bool IsUnderPostmaster
Definition: globals.c:112
int errcode_for_file_access(void)
Definition: elog.c:721
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:349
int clogsyncfiletag(const FileTag *ftag, char *path)
Definition: clog.c:1026
MemoryContext TopMemoryContext
Definition: mcxt.c:48
FileTag tag
Definition: sync.c:70
List * lappend(List *list, void *datum)
Definition: list.c:336
#define WARNING
Definition: elog.h:40
int mdunlinkfiletag(const FileTag *ftag, char *path)
Definition: md.c:1381
CycleCtr cycle_ctr
Definition: sync.c:64
#define HASH_BLOBS
Definition: hsearch.h:97
bool(* sync_filetagmatches)(const FileTag *ftag, const FileTag *candidate)
Definition: sync.c:92
static HTAB * pendingOps
Definition: sync.c:74
int data_sync_elevel(int elevel)
Definition: fd.c:3805
Size keysize
Definition: hsearch.h:75
bool RegisterSyncRequest(const FileTag *ftag, SyncRequestType type, bool retryOnError)
Definition: sync.c:553
#define UNLINKS_PER_ABSORB
Definition: sync.c:83
#define FSYNCS_PER_ABSORB
Definition: sync.c:82
bool mdfiletagmatches(const FileTag *ftag, const FileTag *candidate)
Definition: md.c:1400
#define ereport(elevel,...)
Definition: elog.h:157
int errmsg_internal(const char *fmt,...)
Definition: elog.c:996
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:205
CheckpointStatsData CheckpointStats
Definition: xlog.c:188
SyncRequestType
Definition: sync.h:23
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
int mdsyncfiletag(const FileTag *ftag, char *path)
Definition: md.c:1334
static chr * longest(struct vars *v, struct dfa *d, chr *start, chr *stop, int *hitstopp)
Definition: rege_dfa.c:42
void InitSync(void)
Definition: sync.c:128
bool enableFsync
Definition: globals.c:122
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
bool canceled
Definition: sync.c:65
int16 handler
Definition: sync.h:52
void SyncPostCheckpoint(void)
Definition: sync.c:195
static const SyncOps syncsw[]
Definition: sync.c:99
static CycleCtr sync_cycle_ctr
Definition: sync.c:78
int(* sync_unlinkfiletag)(const FileTag *ftag, char *path)
Definition: sync.c:91
int(* sync_syncfiletag)(const FileTag *ftag, char *path)
Definition: sync.c:90
Definition: pg_list.h:50
Definition: sync.h:50
#define FILE_POSSIBLY_DELETED(err)
Definition: fd.h:77
List * list_delete_first(List *list)
Definition: list.c:875
static MemoryContext pendingOpsCxt
Definition: sync.c:38
void SyncPreCheckpoint(void)
Definition: sync.c:180
int multixactmemberssyncfiletag(const FileTag *ftag, char *path)
Definition: multixact.c:3424
unsigned char bool
Definition: c.h:391
uint64 ckpt_longest_sync
Definition: xlog.h:234