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-2023, 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/fd.h"
33 #include "storage/ipc.h"
34 #include "storage/latch.h"
35 #include "storage/md.h"
36 #include "utils/hsearch.h"
37 #include "utils/inval.h"
38 #include "utils/memutils.h"
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 */
72  bool canceled; /* true if request has been canceled */
74 
75 static HTAB *pendingOps = NULL;
77 static MemoryContext pendingOpsCxt; /* context for the above */
78 
81 
82 /* Intervals for calling AbsorbSyncRequests */
83 #define FSYNCS_PER_ABSORB 10
84 #define UNLINKS_PER_ABSORB 10
85 
86 /*
87  * Function pointers for handling sync and unlink requests.
88  */
89 typedef struct SyncOps
90 {
91  int (*sync_syncfiletag) (const FileTag *ftag, char *path);
92  int (*sync_unlinkfiletag) (const FileTag *ftag, char *path);
93  bool (*sync_filetagmatches) (const FileTag *ftag,
94  const FileTag *candidate);
96 
97 /*
98  * These indexes must correspond to the values of the SyncRequestHandler enum.
99  */
100 static const SyncOps syncsw[] = {
101  /* magnetic disk */
102  [SYNC_HANDLER_MD] = {
104  .sync_unlinkfiletag = mdunlinkfiletag,
105  .sync_filetagmatches = mdfiletagmatches
106  },
107  /* pg_xact */
108  [SYNC_HANDLER_CLOG] = {
109  .sync_syncfiletag = clogsyncfiletag
110  },
111  /* pg_commit_ts */
113  .sync_syncfiletag = committssyncfiletag
114  },
115  /* pg_multixact/offsets */
117  .sync_syncfiletag = multixactoffsetssyncfiletag
118  },
119  /* pg_multixact/members */
121  .sync_syncfiletag = multixactmemberssyncfiletag
122  }
123 };
124 
125 /*
126  * Initialize data structures for the file sync tracking.
127  */
128 void
129 InitSync(void)
130 {
131  /*
132  * Create pending-operations hashtable if we need it. Currently, we need
133  * it if we are standalone (not under a postmaster) or if we are a
134  * checkpointer auxiliary process.
135  */
137  {
138  HASHCTL hash_ctl;
139 
140  /*
141  * XXX: The checkpointer needs to add entries to the pending ops table
142  * when absorbing fsync requests. That is done within a critical
143  * section, which isn't usually allowed, but we make an exception. It
144  * means that there's a theoretical possibility that you run out of
145  * memory while absorbing fsync requests, which leads to a PANIC.
146  * Fortunately the hash table is small so that's unlikely to happen in
147  * practice.
148  */
150  "Pending ops context",
153 
154  hash_ctl.keysize = sizeof(FileTag);
155  hash_ctl.entrysize = sizeof(PendingFsyncEntry);
156  hash_ctl.hcxt = pendingOpsCxt;
157  pendingOps = hash_create("Pending Ops Table",
158  100L,
159  &hash_ctl,
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. Since this calls
175  * AbsorbSyncRequests(), which performs memory allocations, it cannot be
176  * called within a critical section.
177  *
178  * Note that we can't do anything here that depends on the assumption
179  * that the checkpoint will be completed.
180  */
181 void
183 {
184  /*
185  * Operations such as DROP TABLESPACE assume that the next checkpoint will
186  * process all recently forwarded unlink requests, but if they aren't
187  * absorbed prior to advancing the cycle counter, they won't be processed
188  * until a future checkpoint. The following absorb ensures that any
189  * unlink requests forwarded before the checkpoint began will be processed
190  * in the current checkpoint.
191  */
193 
194  /*
195  * Any unlink requests arriving after this point will be assigned the next
196  * cycle counter, and won't be unlinked until next checkpoint.
197  */
199 }
200 
201 /*
202  * SyncPostCheckpoint() -- Do post-checkpoint work
203  *
204  * Remove any lingering files that can now be safely removed.
205  */
206 void
208 {
209  int absorb_counter;
210  ListCell *lc;
211 
212  absorb_counter = UNLINKS_PER_ABSORB;
213  foreach(lc, pendingUnlinks)
214  {
216  char path[MAXPGPATH];
217 
218  /* Skip over any canceled entries */
219  if (entry->canceled)
220  continue;
221 
222  /*
223  * New entries are appended to the end, so if the entry is new we've
224  * reached the end of old entries.
225  *
226  * Note: if just the right number of consecutive checkpoints fail, we
227  * could be fooled here by cycle_ctr wraparound. However, the only
228  * consequence is that we'd delay unlinking for one more checkpoint,
229  * which is perfectly tolerable.
230  */
231  if (entry->cycle_ctr == checkpoint_cycle_ctr)
232  break;
233 
234  /* Unlink the file */
235  if (syncsw[entry->tag.handler].sync_unlinkfiletag(&entry->tag,
236  path) < 0)
237  {
238  /*
239  * There's a race condition, when the database is dropped at the
240  * same time that we process the pending unlink requests. If the
241  * DROP DATABASE deletes the file before we do, we will get ENOENT
242  * here. rmtree() also has to ignore ENOENT errors, to deal with
243  * the possibility that we delete the file first.
244  */
245  if (errno != ENOENT)
248  errmsg("could not remove file \"%s\": %m", path)));
249  }
250 
251  /* Mark the list entry as canceled, just in case */
252  entry->canceled = true;
253 
254  /*
255  * As in ProcessSyncRequests, we don't want to stop absorbing fsync
256  * requests for a long time when there are many deletions to be done.
257  * We can safely call AbsorbSyncRequests() at this point in the loop.
258  */
259  if (--absorb_counter <= 0)
260  {
262  absorb_counter = UNLINKS_PER_ABSORB;
263  }
264  }
265 
266  /*
267  * If we reached the end of the list, we can just remove the whole list
268  * (remembering to pfree all the PendingUnlinkEntry objects). Otherwise,
269  * we must keep the entries at or after "lc".
270  */
271  if (lc == NULL)
272  {
275  }
276  else
277  {
278  int ntodelete = list_cell_number(pendingUnlinks, lc);
279 
280  for (int i = 0; i < ntodelete; i++)
282 
284  }
285 }
286 
287 /*
288  * ProcessSyncRequests() -- Process queued fsync requests.
289  */
290 void
292 {
293  static bool sync_in_progress = false;
294 
295  HASH_SEQ_STATUS hstat;
296  PendingFsyncEntry *entry;
297  int absorb_counter;
298 
299  /* Statistics on sync times */
300  int processed = 0;
301  instr_time sync_start,
302  sync_end,
303  sync_diff;
304  uint64 elapsed;
305  uint64 longest = 0;
306  uint64 total_elapsed = 0;
307 
308  /*
309  * This is only called during checkpoints, and checkpoints should only
310  * occur in processes that have created a pendingOps.
311  */
312  if (!pendingOps)
313  elog(ERROR, "cannot sync without a pendingOps table");
314 
315  /*
316  * If we are in the checkpointer, the sync had better include all fsync
317  * requests that were queued by backends up to this point. The tightest
318  * race condition that could occur is that a buffer that must be written
319  * and fsync'd for the checkpoint could have been dumped by a backend just
320  * before it was visited by BufferSync(). We know the backend will have
321  * queued an fsync request before clearing the buffer's dirtybit, so we
322  * are safe as long as we do an Absorb after completing BufferSync().
323  */
325 
326  /*
327  * To avoid excess fsync'ing (in the worst case, maybe a never-terminating
328  * checkpoint), we want to ignore fsync requests that are entered into the
329  * hashtable after this point --- they should be processed next time,
330  * instead. We use sync_cycle_ctr to tell old entries apart from new
331  * ones: new ones will have cycle_ctr equal to the incremented value of
332  * sync_cycle_ctr.
333  *
334  * In normal circumstances, all entries present in the table at this point
335  * will have cycle_ctr exactly equal to the current (about to be old)
336  * value of sync_cycle_ctr. However, if we fail partway through the
337  * fsync'ing loop, then older values of cycle_ctr might remain when we
338  * come back here to try again. Repeated checkpoint failures would
339  * eventually wrap the counter around to the point where an old entry
340  * might appear new, causing us to skip it, possibly allowing a checkpoint
341  * to succeed that should not have. To forestall wraparound, any time the
342  * previous ProcessSyncRequests() failed to complete, run through the
343  * table and forcibly set cycle_ctr = sync_cycle_ctr.
344  *
345  * Think not to merge this loop with the main loop, as the problem is
346  * exactly that that loop may fail before having visited all the entries.
347  * From a performance point of view it doesn't matter anyway, as this path
348  * will never be taken in a system that's functioning normally.
349  */
350  if (sync_in_progress)
351  {
352  /* prior try failed, so update any stale cycle_ctr values */
353  hash_seq_init(&hstat, pendingOps);
354  while ((entry = (PendingFsyncEntry *) hash_seq_search(&hstat)) != NULL)
355  {
356  entry->cycle_ctr = sync_cycle_ctr;
357  }
358  }
359 
360  /* Advance counter so that new hashtable entries are distinguishable */
361  sync_cycle_ctr++;
362 
363  /* Set flag to detect failure if we don't reach the end of the loop */
364  sync_in_progress = true;
365 
366  /* Now scan the hashtable for fsync requests to process */
367  absorb_counter = FSYNCS_PER_ABSORB;
368  hash_seq_init(&hstat, pendingOps);
369  while ((entry = (PendingFsyncEntry *) hash_seq_search(&hstat)) != NULL)
370  {
371  int failures;
372 
373  /*
374  * If the entry is new then don't process it this time; it is new.
375  * Note "continue" bypasses the hash-remove call at the bottom of the
376  * loop.
377  */
378  if (entry->cycle_ctr == sync_cycle_ctr)
379  continue;
380 
381  /* Else assert we haven't missed it */
382  Assert((CycleCtr) (entry->cycle_ctr + 1) == sync_cycle_ctr);
383 
384  /*
385  * If fsync is off then we don't have to bother opening the file at
386  * all. (We delay checking until this point so that changing fsync on
387  * the fly behaves sensibly.)
388  */
389  if (enableFsync)
390  {
391  /*
392  * If in checkpointer, we want to absorb pending requests every so
393  * often to prevent overflow of the fsync request queue. It is
394  * unspecified whether newly-added entries will be visited by
395  * hash_seq_search, but we don't care since we don't need to
396  * process them anyway.
397  */
398  if (--absorb_counter <= 0)
399  {
401  absorb_counter = FSYNCS_PER_ABSORB;
402  }
403 
404  /*
405  * The fsync table could contain requests to fsync segments that
406  * have been deleted (unlinked) by the time we get to them. Rather
407  * than just hoping an ENOENT (or EACCES on Windows) error can be
408  * ignored, what we do on error is absorb pending requests and
409  * then retry. Since mdunlink() queues a "cancel" message before
410  * actually unlinking, the fsync request is guaranteed to be
411  * marked canceled after the absorb if it really was this case.
412  * DROP DATABASE likewise has to tell us to forget fsync requests
413  * before it starts deletions.
414  */
415  for (failures = 0; !entry->canceled; failures++)
416  {
417  char path[MAXPGPATH];
418 
419  INSTR_TIME_SET_CURRENT(sync_start);
420  if (syncsw[entry->tag.handler].sync_syncfiletag(&entry->tag,
421  path) == 0)
422  {
423  /* Success; update statistics about sync timing */
424  INSTR_TIME_SET_CURRENT(sync_end);
425  sync_diff = sync_end;
426  INSTR_TIME_SUBTRACT(sync_diff, sync_start);
427  elapsed = INSTR_TIME_GET_MICROSEC(sync_diff);
428  if (elapsed > longest)
429  longest = elapsed;
430  total_elapsed += elapsed;
431  processed++;
432 
433  if (log_checkpoints)
434  elog(DEBUG1, "checkpoint sync: number=%d file=%s time=%.3f ms",
435  processed,
436  path,
437  (double) elapsed / 1000);
438 
439  break; /* out of retry loop */
440  }
441 
442  /*
443  * It is possible that the relation has been dropped or
444  * truncated since the fsync request was entered. Therefore,
445  * allow ENOENT, but only if we didn't fail already on this
446  * file.
447  */
448  if (!FILE_POSSIBLY_DELETED(errno) || failures > 0)
451  errmsg("could not fsync file \"%s\": %m",
452  path)));
453  else
454  ereport(DEBUG1,
456  errmsg_internal("could not fsync file \"%s\" but retrying: %m",
457  path)));
458 
459  /*
460  * Absorb incoming requests and check to see if a cancel
461  * arrived for this relation fork.
462  */
464  absorb_counter = FSYNCS_PER_ABSORB; /* might as well... */
465  } /* end retry loop */
466  }
467 
468  /* We are done with this entry, remove it */
469  if (hash_search(pendingOps, &entry->tag, HASH_REMOVE, NULL) == NULL)
470  elog(ERROR, "pendingOps corrupted");
471  } /* end loop over hashtable entries */
472 
473  /* Return sync performance metrics for report at checkpoint end */
474  CheckpointStats.ckpt_sync_rels = processed;
476  CheckpointStats.ckpt_agg_sync_time = total_elapsed;
477 
478  /* Flag successful completion of ProcessSyncRequests */
479  sync_in_progress = false;
480 }
481 
482 /*
483  * RememberSyncRequest() -- callback from checkpointer side of sync request
484  *
485  * We stuff fsync requests into the local hash table for execution
486  * during the checkpointer's next checkpoint. UNLINK requests go into a
487  * separate linked list, however, because they get processed separately.
488  *
489  * See sync.h for more information on the types of sync requests supported.
490  */
491 void
493 {
495 
496  if (type == SYNC_FORGET_REQUEST)
497  {
498  PendingFsyncEntry *entry;
499 
500  /* Cancel previously entered request */
502  ftag,
503  HASH_FIND,
504  NULL);
505  if (entry != NULL)
506  entry->canceled = true;
507  }
508  else if (type == SYNC_FILTER_REQUEST)
509  {
510  HASH_SEQ_STATUS hstat;
511  PendingFsyncEntry *pfe;
512  ListCell *cell;
513 
514  /* Cancel matching fsync requests */
515  hash_seq_init(&hstat, pendingOps);
516  while ((pfe = (PendingFsyncEntry *) hash_seq_search(&hstat)) != NULL)
517  {
518  if (pfe->tag.handler == ftag->handler &&
519  syncsw[ftag->handler].sync_filetagmatches(ftag, &pfe->tag))
520  pfe->canceled = true;
521  }
522 
523  /* Cancel matching unlink requests */
524  foreach(cell, pendingUnlinks)
525  {
527 
528  if (pue->tag.handler == ftag->handler &&
529  syncsw[ftag->handler].sync_filetagmatches(ftag, &pue->tag))
530  pue->canceled = true;
531  }
532  }
533  else if (type == SYNC_UNLINK_REQUEST)
534  {
535  /* Unlink request: put it in the linked list */
537  PendingUnlinkEntry *entry;
538 
539  entry = palloc(sizeof(PendingUnlinkEntry));
540  entry->tag = *ftag;
542  entry->canceled = false;
543 
545 
546  MemoryContextSwitchTo(oldcxt);
547  }
548  else
549  {
550  /* Normal case: enter a request to fsync this segment */
552  PendingFsyncEntry *entry;
553  bool found;
554 
556 
558  ftag,
559  HASH_ENTER,
560  &found);
561  /* if new entry, or was previously canceled, initialize it */
562  if (!found || entry->canceled)
563  {
564  entry->cycle_ctr = sync_cycle_ctr;
565  entry->canceled = false;
566  }
567 
568  /*
569  * NB: it's intentional that we don't change cycle_ctr if the entry
570  * already exists. The cycle_ctr must represent the oldest fsync
571  * request that could be in the entry.
572  */
573 
574  MemoryContextSwitchTo(oldcxt);
575  }
576 }
577 
578 /*
579  * Register the sync request locally, or forward it to the checkpointer.
580  *
581  * If retryOnError is true, we'll keep trying if there is no space in the
582  * queue. Return true if we succeeded, or false if there wasn't space.
583  */
584 bool
586  bool retryOnError)
587 {
588  bool ret;
589 
590  if (pendingOps != NULL)
591  {
592  /* standalone backend or startup process: fsync state is local */
593  RememberSyncRequest(ftag, type);
594  return true;
595  }
596 
597  for (;;)
598  {
599  /*
600  * Notify the checkpointer about it. If we fail to queue a message in
601  * retryOnError mode, we have to sleep and try again ... ugly, but
602  * hopefully won't happen often.
603  *
604  * XXX should we CHECK_FOR_INTERRUPTS in this loop? Escaping with an
605  * error in the case of SYNC_UNLINK_REQUEST would leave the
606  * no-longer-used file still present on disk, which would be bad, so
607  * I'm inclined to assume that the checkpointer will always empty the
608  * queue soon.
609  */
610  ret = ForwardSyncRequest(ftag, type);
611 
612  /*
613  * If we are successful in queueing the request, or we failed and were
614  * instructed not to retry on error, break.
615  */
616  if (ret || (!ret && !retryOnError))
617  break;
618 
620  WAIT_EVENT_REGISTER_SYNC_REQUEST);
621  }
622 
623  return ret;
624 }
unsigned short uint16
Definition: c.h:494
unsigned char bool
Definition: c.h:445
bool ForwardSyncRequest(const FileTag *ftag, SyncRequestType type)
void AbsorbSyncRequests(void)
int clogsyncfiletag(const FileTag *ftag, char *path)
Definition: clog.c:1035
int committssyncfiletag(const FileTag *ftag, char *path)
Definition: commit_ts.c:1021
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:953
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:350
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1431
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1421
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1156
int errcode_for_file_access(void)
Definition: elog.c:881
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define WARNING
Definition: elog.h:36
#define DEBUG1
Definition: elog.h:30
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
int data_sync_elevel(int elevel)
Definition: fd.c:3906
#define FILE_POSSIBLY_DELETED(err)
Definition: fd.h:76
bool enableFsync
Definition: globals.c:125
bool IsUnderPostmaster
Definition: globals.c:115
@ HASH_FIND
Definition: hsearch.h:113
@ HASH_REMOVE
Definition: hsearch.h:115
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:122
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:181
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:194
int i
Definition: isn.c:73
int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info)
Definition: latch.c:518
#define WL_TIMEOUT
Definition: latch.h:130
#define WL_EXIT_ON_PM_DEATH
Definition: latch.h:132
Assert(fmt[strlen(fmt) - 1] !='\n')
List * list_delete_first_n(List *list, int n)
Definition: list.c:982
List * lappend(List *list, void *datum)
Definition: list.c:338
void list_free_deep(List *list)
Definition: list.c:1559
void pfree(void *pointer)
Definition: mcxt.c:1456
MemoryContext TopMemoryContext
Definition: mcxt.c:141
void MemoryContextAllowInCriticalSection(MemoryContext context, bool allow)
Definition: mcxt.c:603
void * palloc(Size size)
Definition: mcxt.c:1226
bool mdfiletagmatches(const FileTag *ftag, const FileTag *candidate)
Definition: md.c:1614
int mdunlinkfiletag(const FileTag *ftag, char *path)
Definition: md.c:1595
int mdsyncfiletag(const FileTag *ftag, char *path)
Definition: md.c:1542
#define AllocSetContextCreate
Definition: memutils.h:126
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:150
#define AmCheckpointerProcess()
Definition: miscadmin.h:458
int multixactoffsetssyncfiletag(const FileTag *ftag, char *path)
Definition: multixact.c:3411
int multixactmemberssyncfiletag(const FileTag *ftag, char *path)
Definition: multixact.c:3420
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
#define MAXPGPATH
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
static int list_cell_number(const List *l, const ListCell *c)
Definition: pg_list.h:333
static chr * longest(struct vars *v, struct dfa *d, chr *start, chr *stop, int *hitstopp)
Definition: rege_dfa.c:42
uint64 ckpt_agg_sync_time
Definition: xlog.h:173
uint64 ckpt_longest_sync
Definition: xlog.h:172
int ckpt_sync_rels
Definition: xlog.h:171
Definition: sync.h:51
int16 handler
Definition: sync.h:52
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
MemoryContext hcxt
Definition: hsearch.h:86
Definition: dynahash.c:220
Definition: pg_list.h:54
FileTag tag
Definition: sync.c:63
CycleCtr cycle_ctr
Definition: sync.c:64
bool canceled
Definition: sync.c:65
FileTag tag
Definition: sync.c:70
CycleCtr cycle_ctr
Definition: sync.c:71
bool canceled
Definition: sync.c:72
Definition: sync.c:90
int(* sync_syncfiletag)(const FileTag *ftag, char *path)
Definition: sync.c:91
bool(* sync_filetagmatches)(const FileTag *ftag, const FileTag *candidate)
Definition: sync.c:93
int(* sync_unlinkfiletag)(const FileTag *ftag, char *path)
Definition: sync.c:92
void ProcessSyncRequests(void)
Definition: sync.c:291
static CycleCtr checkpoint_cycle_ctr
Definition: sync.c:80
void SyncPreCheckpoint(void)
Definition: sync.c:182
static List * pendingUnlinks
Definition: sync.c:76
static HTAB * pendingOps
Definition: sync.c:75
struct SyncOps SyncOps
#define UNLINKS_PER_ABSORB
Definition: sync.c:84
void InitSync(void)
Definition: sync.c:129
static const SyncOps syncsw[]
Definition: sync.c:100
static MemoryContext pendingOpsCxt
Definition: sync.c:77
void RememberSyncRequest(const FileTag *ftag, SyncRequestType type)
Definition: sync.c:492
static CycleCtr sync_cycle_ctr
Definition: sync.c:79
#define FSYNCS_PER_ABSORB
Definition: sync.c:83
void SyncPostCheckpoint(void)
Definition: sync.c:207
bool RegisterSyncRequest(const FileTag *ftag, SyncRequestType type, bool retryOnError)
Definition: sync.c:585
uint16 CycleCtr
Definition: sync.c:59
struct FileTag FileTag
@ SYNC_HANDLER_MD
Definition: sync.h:37
@ SYNC_HANDLER_COMMIT_TS
Definition: sync.h:39
@ SYNC_HANDLER_MULTIXACT_MEMBER
Definition: sync.h:41
@ SYNC_HANDLER_CLOG
Definition: sync.h:38
@ SYNC_HANDLER_MULTIXACT_OFFSET
Definition: sync.h:40
SyncRequestType
Definition: sync.h:24
@ SYNC_FILTER_REQUEST
Definition: sync.h:28
@ SYNC_FORGET_REQUEST
Definition: sync.h:27
@ SYNC_UNLINK_REQUEST
Definition: sync.h:26
@ SYNC_REQUEST
Definition: sync.h:25
const char * type
bool log_checkpoints
Definition: xlog.c:132
CheckpointStatsData CheckpointStats
Definition: xlog.c:212