PostgreSQL Source Code  git master
copydir.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void copydir (char *fromdir, char *todir, bool recurse)
 
void copy_file (char *fromfile, char *tofile)
 

Function Documentation

◆ copy_file()

void copy_file ( char *  fromfile,
char *  tofile 
)

Definition at line 127 of file copydir.c.

References buffer, CHECK_FOR_INTERRUPTS, CloseTransientFile(), COPY_BUF_SIZE, dstfd, ereport, errcode_for_file_access(), errmsg(), ERROR, FLUSH_DISTANCE, OpenTransientFile(), palloc(), pfree(), PG_BINARY, pg_flush_data(), pgstat_report_wait_end(), pgstat_report_wait_start(), read, WAIT_EVENT_COPY_FILE_READ, WAIT_EVENT_COPY_FILE_WRITE, and write.

Referenced by copydir(), and ResetUnloggedRelationsInDbspaceDir().

128 {
129  char *buffer;
130  int srcfd;
131  int dstfd;
132  int nbytes;
133  off_t offset;
134  off_t flush_offset;
135 
136  /* Size of copy buffer (read and write requests) */
137 #define COPY_BUF_SIZE (8 * BLCKSZ)
138 
139  /*
140  * Size of data flush requests. It seems beneficial on most platforms to
141  * do this every 1MB or so. But macOS, at least with early releases of
142  * APFS, is really unfriendly to small mmap/msync requests, so there do it
143  * only every 32MB.
144  */
145 #if defined(__darwin__)
146 #define FLUSH_DISTANCE (32 * 1024 * 1024)
147 #else
148 #define FLUSH_DISTANCE (1024 * 1024)
149 #endif
150 
151  /* Use palloc to ensure we get a maxaligned buffer */
152  buffer = palloc(COPY_BUF_SIZE);
153 
154  /*
155  * Open the files
156  */
157  srcfd = OpenTransientFile(fromfile, O_RDONLY | PG_BINARY);
158  if (srcfd < 0)
159  ereport(ERROR,
161  errmsg("could not open file \"%s\": %m", fromfile)));
162 
163  dstfd = OpenTransientFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);
164  if (dstfd < 0)
165  ereport(ERROR,
167  errmsg("could not create file \"%s\": %m", tofile)));
168 
169  /*
170  * Do the data copying.
171  */
172  flush_offset = 0;
173  for (offset = 0;; offset += nbytes)
174  {
175  /* If we got a cancel signal during the copy of the file, quit */
177 
178  /*
179  * We fsync the files later, but during the copy, flush them every so
180  * often to avoid spamming the cache and hopefully get the kernel to
181  * start writing them out before the fsync comes.
182  */
183  if (offset - flush_offset >= FLUSH_DISTANCE)
184  {
185  pg_flush_data(dstfd, flush_offset, offset - flush_offset);
186  flush_offset = offset;
187  }
188 
190  nbytes = read(srcfd, buffer, COPY_BUF_SIZE);
192  if (nbytes < 0)
193  ereport(ERROR,
195  errmsg("could not read file \"%s\": %m", fromfile)));
196  if (nbytes == 0)
197  break;
198  errno = 0;
200  if ((int) write(dstfd, buffer, nbytes) != nbytes)
201  {
203  /* if write didn't set errno, assume problem is no disk space */
204  if (errno == 0)
205  errno = ENOSPC;
206  ereport(ERROR,
208  errmsg("could not write to file \"%s\": %m", tofile)));
209  }
211  }
212 
213  if (offset > flush_offset)
214  pg_flush_data(dstfd, flush_offset, offset - flush_offset);
215 
216  if (CloseTransientFile(dstfd))
217  ereport(ERROR,
219  errmsg("could not close file \"%s\": %m", tofile)));
220 
221  CloseTransientFile(srcfd);
222 
223  pfree(buffer);
224 }
static int dstfd
Definition: file_ops.c:29
#define write(a, b, c)
Definition: win32.h:14
#define PG_BINARY
Definition: c.h:1025
#define COPY_BUF_SIZE
void pfree(void *pointer)
Definition: mcxt.c:949
#define ERROR
Definition: elog.h:43
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2392
int errcode_for_file_access(void)
Definition: elog.c:598
static void pgstat_report_wait_end(void)
Definition: pgstat.h:1244
#define ereport(elevel, rest)
Definition: elog.h:122
int CloseTransientFile(int fd)
Definition: fd.c:2562
void pg_flush_data(int fd, off_t offset, off_t nbytes)
Definition: fd.c:421
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: pgstat.h:1220
#define FLUSH_DISTANCE
void * palloc(Size size)
Definition: mcxt.c:848
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
#define read(a, b, c)
Definition: win32.h:13

◆ copydir()

void copydir ( char *  fromdir,
char *  todir,
bool  recurse 
)

Definition at line 37 of file copydir.c.

References AllocateDir(), CHECK_FOR_INTERRUPTS, copy_file(), copydir(), dirent::d_name, enableFsync, ereport, errcode_for_file_access(), errmsg(), ERROR, FreeDir(), fsync_fname(), lstat, MAXPGPATH, mkdir, ReadDir(), S_IRWXU, S_ISDIR, S_ISREG, snprintf(), and stat.

Referenced by copydir(), createdb(), dbase_redo(), and movedb().

38 {
39  DIR *xldir;
40  struct dirent *xlde;
41  char fromfile[MAXPGPATH * 2];
42  char tofile[MAXPGPATH * 2];
43 
44  if (mkdir(todir, S_IRWXU) != 0)
45  ereport(ERROR,
47  errmsg("could not create directory \"%s\": %m", todir)));
48 
49  xldir = AllocateDir(fromdir);
50 
51  while ((xlde = ReadDir(xldir, fromdir)) != NULL)
52  {
53  struct stat fst;
54 
55  /* If we got a cancel signal during the copy of the directory, quit */
57 
58  if (strcmp(xlde->d_name, ".") == 0 ||
59  strcmp(xlde->d_name, "..") == 0)
60  continue;
61 
62  snprintf(fromfile, sizeof(fromfile), "%s/%s", fromdir, xlde->d_name);
63  snprintf(tofile, sizeof(tofile), "%s/%s", todir, xlde->d_name);
64 
65  if (lstat(fromfile, &fst) < 0)
66  ereport(ERROR,
68  errmsg("could not stat file \"%s\": %m", fromfile)));
69 
70  if (S_ISDIR(fst.st_mode))
71  {
72  /* recurse to handle subdirectories */
73  if (recurse)
74  copydir(fromfile, tofile, true);
75  }
76  else if (S_ISREG(fst.st_mode))
77  copy_file(fromfile, tofile);
78  }
79  FreeDir(xldir);
80 
81  /*
82  * Be paranoid here and fsync all files to ensure the copy is really done.
83  * But if fsync is disabled, we're done.
84  */
85  if (!enableFsync)
86  return;
87 
88  xldir = AllocateDir(todir);
89 
90  while ((xlde = ReadDir(xldir, todir)) != NULL)
91  {
92  struct stat fst;
93 
94  if (strcmp(xlde->d_name, ".") == 0 ||
95  strcmp(xlde->d_name, "..") == 0)
96  continue;
97 
98  snprintf(tofile, sizeof(tofile), "%s/%s", todir, xlde->d_name);
99 
100  /*
101  * We don't need to sync subdirectories here since the recursive
102  * copydir will do it before it returns
103  */
104  if (lstat(tofile, &fst) < 0)
105  ereport(ERROR,
107  errmsg("could not stat file \"%s\": %m", tofile)));
108 
109  if (S_ISREG(fst.st_mode))
110  fsync_fname(tofile, false);
111  }
112  FreeDir(xldir);
113 
114  /*
115  * It's important to fsync the destination directory itself as individual
116  * file fsyncs don't guarantee that the directory entry for the file is
117  * synced. Recent versions of ext4 have made the window much wider but
118  * it's been true for ext3 and other filesystems in the past.
119  */
120  fsync_fname(todir, true);
121 }
void fsync_fname(const char *fname, bool isdir)
Definition: fd.c:581
void copydir(char *fromdir, char *todir, bool recurse)
Definition: copydir.c:37
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
Definition: dirent.h:9
Definition: dirent.c:25
#define ERROR
Definition: elog.h:43
#define MAXPGPATH
int errcode_for_file_access(void)
Definition: elog.c:598
void copy_file(char *fromfile, char *tofile)
Definition: copydir.c:127
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2596
#define ereport(elevel, rest)
Definition: elog.h:122
#define S_ISREG(m)
Definition: win32_port.h:310
#define stat(a, b)
Definition: win32_port.h:266
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2662
#define S_ISDIR(m)
Definition: win32_port.h:307
#define lstat(path, sb)
Definition: win32_port.h:255
bool enableFsync
Definition: globals.c:111
#define S_IRWXU
Definition: win32_port.h:280
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
char d_name[MAX_PATH]
Definition: dirent.h:14
#define mkdir(a, b)
Definition: win32_port.h:58
int FreeDir(DIR *dir)
Definition: fd.c:2714