PostgreSQL Source Code  git master
copydir.c File Reference
#include "postgres.h"
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include "storage/copydir.h"
#include "storage/fd.h"
#include "miscadmin.h"
#include "pgstat.h"
Include dependency graph for copydir.c:

Go to the source code of this file.

Macros

#define COPY_BUF_SIZE   (8 * BLCKSZ)
 
#define FLUSH_DISTANCE   (1024 * 1024)
 

Functions

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

Macro Definition Documentation

◆ COPY_BUF_SIZE

#define COPY_BUF_SIZE   (8 * BLCKSZ)

Referenced by copy_file().

◆ FLUSH_DISTANCE

#define FLUSH_DISTANCE   (1024 * 1024)

Referenced by copy_file().

Function Documentation

◆ copy_file()

void copy_file ( char *  fromfile,
char *  tofile 
)

Definition at line 135 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().

136 {
137  char *buffer;
138  int srcfd;
139  int dstfd;
140  int nbytes;
141  off_t offset;
142  off_t flush_offset;
143 
144  /* Size of copy buffer (read and write requests) */
145 #define COPY_BUF_SIZE (8 * BLCKSZ)
146 
147  /*
148  * Size of data flush requests. It seems beneficial on most platforms to
149  * do this every 1MB or so. But macOS, at least with early releases of
150  * APFS, is really unfriendly to small mmap/msync requests, so there do it
151  * only every 32MB.
152  */
153 #if defined(__darwin__)
154 #define FLUSH_DISTANCE (32 * 1024 * 1024)
155 #else
156 #define FLUSH_DISTANCE (1024 * 1024)
157 #endif
158 
159  /* Use palloc to ensure we get a maxaligned buffer */
160  buffer = palloc(COPY_BUF_SIZE);
161 
162  /*
163  * Open the files
164  */
165  srcfd = OpenTransientFile(fromfile, O_RDONLY | PG_BINARY);
166  if (srcfd < 0)
167  ereport(ERROR,
169  errmsg("could not open file \"%s\": %m", fromfile)));
170 
171  dstfd = OpenTransientFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);
172  if (dstfd < 0)
173  ereport(ERROR,
175  errmsg("could not create file \"%s\": %m", tofile)));
176 
177  /*
178  * Do the data copying.
179  */
180  flush_offset = 0;
181  for (offset = 0;; offset += nbytes)
182  {
183  /* If we got a cancel signal during the copy of the file, quit */
185 
186  /*
187  * We fsync the files later, but during the copy, flush them every so
188  * often to avoid spamming the cache and hopefully get the kernel to
189  * start writing them out before the fsync comes.
190  */
191  if (offset - flush_offset >= FLUSH_DISTANCE)
192  {
193  pg_flush_data(dstfd, flush_offset, offset - flush_offset);
194  flush_offset = offset;
195  }
196 
198  nbytes = read(srcfd, buffer, COPY_BUF_SIZE);
200  if (nbytes < 0)
201  ereport(ERROR,
203  errmsg("could not read file \"%s\": %m", fromfile)));
204  if (nbytes == 0)
205  break;
206  errno = 0;
208  if ((int) write(dstfd, buffer, nbytes) != nbytes)
209  {
211  /* if write didn't set errno, assume problem is no disk space */
212  if (errno == 0)
213  errno = ENOSPC;
214  ereport(ERROR,
216  errmsg("could not write to file \"%s\": %m", tofile)));
217  }
219  }
220 
221  if (offset > flush_offset)
222  pg_flush_data(dstfd, flush_offset, offset - flush_offset);
223 
224  if (CloseTransientFile(dstfd))
225  ereport(ERROR,
227  errmsg("could not close file \"%s\": %m", tofile)));
228 
229  CloseTransientFile(srcfd);
230 
231  pfree(buffer);
232 }
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:2173
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:2343
void pg_flush_data(int fd, off_t offset, off_t nbytes)
Definition: fd.c:412
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  if (xldir == NULL)
51  ereport(ERROR,
53  errmsg("could not open directory \"%s\": %m", fromdir)));
54 
55  while ((xlde = ReadDir(xldir, fromdir)) != NULL)
56  {
57  struct stat fst;
58 
59  /* If we got a cancel signal during the copy of the directory, quit */
61 
62  if (strcmp(xlde->d_name, ".") == 0 ||
63  strcmp(xlde->d_name, "..") == 0)
64  continue;
65 
66  snprintf(fromfile, sizeof(fromfile), "%s/%s", fromdir, xlde->d_name);
67  snprintf(tofile, sizeof(tofile), "%s/%s", todir, xlde->d_name);
68 
69  if (lstat(fromfile, &fst) < 0)
70  ereport(ERROR,
72  errmsg("could not stat file \"%s\": %m", fromfile)));
73 
74  if (S_ISDIR(fst.st_mode))
75  {
76  /* recurse to handle subdirectories */
77  if (recurse)
78  copydir(fromfile, tofile, true);
79  }
80  else if (S_ISREG(fst.st_mode))
81  copy_file(fromfile, tofile);
82  }
83  FreeDir(xldir);
84 
85  /*
86  * Be paranoid here and fsync all files to ensure the copy is really done.
87  * But if fsync is disabled, we're done.
88  */
89  if (!enableFsync)
90  return;
91 
92  xldir = AllocateDir(todir);
93  if (xldir == NULL)
94  ereport(ERROR,
96  errmsg("could not open directory \"%s\": %m", todir)));
97 
98  while ((xlde = ReadDir(xldir, todir)) != NULL)
99  {
100  struct stat fst;
101 
102  if (strcmp(xlde->d_name, ".") == 0 ||
103  strcmp(xlde->d_name, "..") == 0)
104  continue;
105 
106  snprintf(tofile, sizeof(tofile), "%s/%s", todir, xlde->d_name);
107 
108  /*
109  * We don't need to sync subdirectories here since the recursive
110  * copydir will do it before it returns
111  */
112  if (lstat(tofile, &fst) < 0)
113  ereport(ERROR,
115  errmsg("could not stat file \"%s\": %m", tofile)));
116 
117  if (S_ISREG(fst.st_mode))
118  fsync_fname(tofile, false);
119  }
120  FreeDir(xldir);
121 
122  /*
123  * It's important to fsync the destination directory itself as individual
124  * file fsyncs don't guarantee that the directory entry for the file is
125  * synced. Recent versions of ext4 have made the window much wider but
126  * it's been true for ext3 and other filesystems in the past.
127  */
128  fsync_fname(todir, true);
129 }
void fsync_fname(const char *fname, bool isdir)
Definition: fd.c:572
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:135
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2373
#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:2439
#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:2482