PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 (const char *fromdir, const char *todir, bool recurse)
 
void copy_file (const char *fromfile, const char *tofile)
 

Function Documentation

◆ copy_file()

void copy_file ( const char *  fromfile,
const char *  tofile 
)

Definition at line 117 of file copydir.c.

118{
119 char *buffer;
120 int srcfd;
121 int dstfd;
122 int nbytes;
123 off_t offset;
124 off_t flush_offset;
125
126 /* Size of copy buffer (read and write requests) */
127#define COPY_BUF_SIZE (8 * BLCKSZ)
128
129 /*
130 * Size of data flush requests. It seems beneficial on most platforms to
131 * do this every 1MB or so. But macOS, at least with early releases of
132 * APFS, is really unfriendly to small mmap/msync requests, so there do it
133 * only every 32MB.
134 */
135#if defined(__darwin__)
136#define FLUSH_DISTANCE (32 * 1024 * 1024)
137#else
138#define FLUSH_DISTANCE (1024 * 1024)
139#endif
140
141 /* Use palloc to ensure we get a maxaligned buffer */
142 buffer = palloc(COPY_BUF_SIZE);
143
144 /*
145 * Open the files
146 */
147 srcfd = OpenTransientFile(fromfile, O_RDONLY | PG_BINARY);
148 if (srcfd < 0)
151 errmsg("could not open file \"%s\": %m", fromfile)));
152
153 dstfd = OpenTransientFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);
154 if (dstfd < 0)
157 errmsg("could not create file \"%s\": %m", tofile)));
158
159 /*
160 * Do the data copying.
161 */
162 flush_offset = 0;
163 for (offset = 0;; offset += nbytes)
164 {
165 /* If we got a cancel signal during the copy of the file, quit */
167
168 /*
169 * We fsync the files later, but during the copy, flush them every so
170 * often to avoid spamming the cache and hopefully get the kernel to
171 * start writing them out before the fsync comes.
172 */
173 if (offset - flush_offset >= FLUSH_DISTANCE)
174 {
175 pg_flush_data(dstfd, flush_offset, offset - flush_offset);
176 flush_offset = offset;
177 }
178
179 pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_READ);
180 nbytes = read(srcfd, buffer, COPY_BUF_SIZE);
182 if (nbytes < 0)
185 errmsg("could not read file \"%s\": %m", fromfile)));
186 if (nbytes == 0)
187 break;
188 errno = 0;
189 pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_WRITE);
190 if ((int) write(dstfd, buffer, nbytes) != nbytes)
191 {
192 /* if write didn't set errno, assume problem is no disk space */
193 if (errno == 0)
194 errno = ENOSPC;
197 errmsg("could not write to file \"%s\": %m", tofile)));
198 }
200 }
201
202 if (offset > flush_offset)
203 pg_flush_data(dstfd, flush_offset, offset - flush_offset);
204
205 if (CloseTransientFile(dstfd) != 0)
208 errmsg("could not close file \"%s\": %m", tofile)));
209
210 if (CloseTransientFile(srcfd) != 0)
213 errmsg("could not close file \"%s\": %m", fromfile)));
214
215 pfree(buffer);
216}
#define PG_BINARY
Definition: c.h:1244
#define FLUSH_DISTANCE
#define COPY_BUF_SIZE
int errcode_for_file_access(void)
Definition: elog.c:876
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
void pg_flush_data(int fd, off_t offset, off_t nbytes)
Definition: fd.c:524
int CloseTransientFile(int fd)
Definition: fd.c:2831
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2655
static int dstfd
Definition: file_ops.c:31
#define write(a, b, c)
Definition: win32.h:14
#define read(a, b, c)
Definition: win32.h:13
void pfree(void *pointer)
Definition: mcxt.c:1524
void * palloc(Size size)
Definition: mcxt.c:1317
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:85
static void pgstat_report_wait_end(void)
Definition: wait_event.h:101

References 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, and write.

Referenced by basic_archive_file(), copydir(), process_directory_recursively(), reconstruct_from_incremental_file(), and ResetUnloggedRelationsInDbspaceDir().

◆ copydir()

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

Definition at line 37 of file copydir.c.

38{
39 DIR *xldir;
40 struct dirent *xlde;
41 char fromfile[MAXPGPATH * 2];
42 char tofile[MAXPGPATH * 2];
43
44 if (MakePGDirectory(todir) != 0)
47 errmsg("could not create directory \"%s\": %m", todir)));
48
49 xldir = AllocateDir(fromdir);
50
51 while ((xlde = ReadDir(xldir, fromdir)) != NULL)
52 {
53 PGFileType xlde_type;
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 xlde_type = get_dirent_type(fromfile, xlde, false, ERROR);
66
67 if (xlde_type == PGFILETYPE_DIR)
68 {
69 /* recurse to handle subdirectories */
70 if (recurse)
71 copydir(fromfile, tofile, true);
72 }
73 else if (xlde_type == PGFILETYPE_REG)
74 copy_file(fromfile, tofile);
75 }
76 FreeDir(xldir);
77
78 /*
79 * Be paranoid here and fsync all files to ensure the copy is really done.
80 * But if fsync is disabled, we're done.
81 */
82 if (!enableFsync)
83 return;
84
85 xldir = AllocateDir(todir);
86
87 while ((xlde = ReadDir(xldir, todir)) != NULL)
88 {
89 if (strcmp(xlde->d_name, ".") == 0 ||
90 strcmp(xlde->d_name, "..") == 0)
91 continue;
92
93 snprintf(tofile, sizeof(tofile), "%s/%s", todir, xlde->d_name);
94
95 /*
96 * We don't need to sync subdirectories here since the recursive
97 * copydir will do it before it returns
98 */
99 if (get_dirent_type(tofile, xlde, false, ERROR) == PGFILETYPE_REG)
100 fsync_fname(tofile, false);
101 }
102 FreeDir(xldir);
103
104 /*
105 * It's important to fsync the destination directory itself as individual
106 * file fsyncs don't guarantee that the directory entry for the file is
107 * synced. Recent versions of ext4 have made the window much wider but
108 * it's been true for ext3 and other filesystems in the past.
109 */
110 fsync_fname(todir, true);
111}
void copy_file(const char *fromfile, const char *tofile)
Definition: copydir.c:117
void copydir(const char *fromdir, const char *todir, bool recurse)
Definition: copydir.c:37
int MakePGDirectory(const char *directoryName)
Definition: fd.c:3936
int FreeDir(DIR *dir)
Definition: fd.c:2983
void fsync_fname(const char *fname, bool isdir)
Definition: fd.c:755
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2865
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2931
PGFileType get_dirent_type(const char *path, const struct dirent *de, bool look_through_symlinks, int elevel)
Definition: file_utils.c:526
PGFileType
Definition: file_utils.h:19
@ PGFILETYPE_DIR
Definition: file_utils.h:23
@ PGFILETYPE_REG
Definition: file_utils.h:22
bool enableFsync
Definition: globals.c:128
#define MAXPGPATH
#define snprintf
Definition: port.h:239
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15

References AllocateDir(), CHECK_FOR_INTERRUPTS, copy_file(), copydir(), dirent::d_name, enableFsync, ereport, errcode_for_file_access(), errmsg(), ERROR, FreeDir(), fsync_fname(), get_dirent_type(), MakePGDirectory(), MAXPGPATH, PGFILETYPE_DIR, PGFILETYPE_REG, ReadDir(), and snprintf.

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