PostgreSQL Source Code  git master
file.c File Reference
#include "postgres_fe.h"
#include <sys/stat.h>
#include <fcntl.h>
#include "access/visibilitymapdefs.h"
#include "common/file_perm.h"
#include "pg_upgrade.h"
#include "storage/bufpage.h"
#include "storage/checksum.h"
#include "storage/checksum_impl.h"
Include dependency graph for file.c:

Go to the source code of this file.

Macros

#define COPY_BUF_SIZE   (50 * BLCKSZ)
 

Functions

void cloneFile (const char *src, const char *dst, const char *schemaName, const char *relName)
 
void copyFile (const char *src, const char *dst, const char *schemaName, const char *relName)
 
void linkFile (const char *src, const char *dst, const char *schemaName, const char *relName)
 
void rewriteVisibilityMap (const char *fromfile, const char *tofile, const char *schemaName, const char *relName)
 
void check_file_clone (void)
 
void check_hard_link (void)
 

Macro Definition Documentation

◆ COPY_BUF_SIZE

#define COPY_BUF_SIZE   (50 * BLCKSZ)

Function Documentation

◆ check_file_clone()

void check_file_clone ( void  )

Definition at line 320 of file file.c.

321 {
322  char existing_file[MAXPGPATH];
323  char new_link_file[MAXPGPATH];
324 
325  snprintf(existing_file, sizeof(existing_file), "%s/PG_VERSION", old_cluster.pgdata);
326  snprintf(new_link_file, sizeof(new_link_file), "%s/PG_VERSION.clonetest", new_cluster.pgdata);
327  unlink(new_link_file); /* might fail */
328 
329 #if defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE)
330  if (copyfile(existing_file, new_link_file, NULL, COPYFILE_CLONE_FORCE) < 0)
331  pg_fatal("could not clone file between old and new data directories: %s",
332  strerror(errno));
333 #elif defined(__linux__) && defined(FICLONE)
334  {
335  int src_fd;
336  int dest_fd;
337 
338  if ((src_fd = open(existing_file, O_RDONLY | PG_BINARY, 0)) < 0)
339  pg_fatal("could not open file \"%s\": %s",
340  existing_file, strerror(errno));
341 
342  if ((dest_fd = open(new_link_file, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
343  pg_file_create_mode)) < 0)
344  pg_fatal("could not create file \"%s\": %s",
345  new_link_file, strerror(errno));
346 
347  if (ioctl(dest_fd, FICLONE, src_fd) < 0)
348  pg_fatal("could not clone file between old and new data directories: %s",
349  strerror(errno));
350 
351  close(src_fd);
352  close(dest_fd);
353  }
354 #else
355  pg_fatal("file cloning not supported on this platform");
356 #endif
357 
358  unlink(new_link_file);
359 }
#define PG_BINARY
Definition: c.h:1283
int pg_file_create_mode
Definition: file_perm.c:19
#define close(a)
Definition: win32.h:12
#define pg_fatal(...)
#define MAXPGPATH
ClusterInfo new_cluster
Definition: pg_upgrade.c:65
ClusterInfo old_cluster
Definition: pg_upgrade.c:64
#define strerror
Definition: port.h:251
#define snprintf
Definition: port.h:238
char * pgdata
Definition: pg_upgrade.h:283

References close, MAXPGPATH, new_cluster, old_cluster, PG_BINARY, pg_fatal, pg_file_create_mode, ClusterInfo::pgdata, snprintf, and strerror.

Referenced by check_new_cluster().

◆ check_hard_link()

void check_hard_link ( void  )

Definition at line 362 of file file.c.

363 {
364  char existing_file[MAXPGPATH];
365  char new_link_file[MAXPGPATH];
366 
367  snprintf(existing_file, sizeof(existing_file), "%s/PG_VERSION", old_cluster.pgdata);
368  snprintf(new_link_file, sizeof(new_link_file), "%s/PG_VERSION.linktest", new_cluster.pgdata);
369  unlink(new_link_file); /* might fail */
370 
371  if (link(existing_file, new_link_file) < 0)
372  pg_fatal("could not create hard link between old and new data directories: %s\n"
373  "In link mode the old and new data directories must be on the same file system.",
374  strerror(errno));
375 
376  unlink(new_link_file);
377 }

References link(), MAXPGPATH, new_cluster, old_cluster, pg_fatal, ClusterInfo::pgdata, snprintf, and strerror.

Referenced by check_new_cluster().

◆ cloneFile()

void cloneFile ( const char *  src,
const char *  dst,
const char *  schemaName,
const char *  relName 
)

Definition at line 38 of file file.c.

40 {
41 #if defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE)
42  if (copyfile(src, dst, NULL, COPYFILE_CLONE_FORCE) < 0)
43  pg_fatal("error while cloning relation \"%s.%s\" (\"%s\" to \"%s\"): %s",
44  schemaName, relName, src, dst, strerror(errno));
45 #elif defined(__linux__) && defined(FICLONE)
46  int src_fd;
47  int dest_fd;
48 
49  if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
50  pg_fatal("error while cloning relation \"%s.%s\": could not open file \"%s\": %s",
51  schemaName, relName, src, strerror(errno));
52 
53  if ((dest_fd = open(dst, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
54  pg_file_create_mode)) < 0)
55  pg_fatal("error while cloning relation \"%s.%s\": could not create file \"%s\": %s",
56  schemaName, relName, dst, strerror(errno));
57 
58  if (ioctl(dest_fd, FICLONE, src_fd) < 0)
59  {
60  int save_errno = errno;
61 
62  unlink(dst);
63 
64  pg_fatal("error while cloning relation \"%s.%s\" (\"%s\" to \"%s\"): %s",
65  schemaName, relName, src, dst, strerror(save_errno));
66  }
67 
68  close(src_fd);
69  close(dest_fd);
70 #endif
71 }

References close, PG_BINARY, pg_fatal, pg_file_create_mode, and strerror.

Referenced by transfer_relfile().

◆ copyFile()

void copyFile ( const char *  src,
const char *  dst,
const char *  schemaName,
const char *  relName 
)

Definition at line 81 of file file.c.

83 {
84 #ifndef WIN32
85  int src_fd;
86  int dest_fd;
87  char *buffer;
88 
89  if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
90  pg_fatal("error while copying relation \"%s.%s\": could not open file \"%s\": %s",
91  schemaName, relName, src, strerror(errno));
92 
93  if ((dest_fd = open(dst, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
94  pg_file_create_mode)) < 0)
95  pg_fatal("error while copying relation \"%s.%s\": could not create file \"%s\": %s",
96  schemaName, relName, dst, strerror(errno));
97 
98  /* copy in fairly large chunks for best efficiency */
99 #define COPY_BUF_SIZE (50 * BLCKSZ)
100 
101  buffer = (char *) pg_malloc(COPY_BUF_SIZE);
102 
103  /* perform data copying i.e read src source, write to destination */
104  while (true)
105  {
106  ssize_t nbytes = read(src_fd, buffer, COPY_BUF_SIZE);
107 
108  if (nbytes < 0)
109  pg_fatal("error while copying relation \"%s.%s\": could not read file \"%s\": %s",
110  schemaName, relName, src, strerror(errno));
111 
112  if (nbytes == 0)
113  break;
114 
115  errno = 0;
116  if (write(dest_fd, buffer, nbytes) != nbytes)
117  {
118  /* if write didn't set errno, assume problem is no disk space */
119  if (errno == 0)
120  errno = ENOSPC;
121  pg_fatal("error while copying relation \"%s.%s\": could not write file \"%s\": %s",
122  schemaName, relName, dst, strerror(errno));
123  }
124  }
125 
126  pg_free(buffer);
127  close(src_fd);
128  close(dest_fd);
129 
130 #else /* WIN32 */
131 
132  if (CopyFile(src, dst, true) == 0)
133  {
134  _dosmaperr(GetLastError());
135  pg_fatal("error while copying relation \"%s.%s\" (\"%s\" to \"%s\"): %s",
136  schemaName, relName, src, dst, strerror(errno));
137  }
138 
139 #endif /* WIN32 */
140 }
void pg_free(void *ptr)
Definition: fe_memutils.c:105
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
#define COPY_BUF_SIZE
#define write(a, b, c)
Definition: win32.h:14
#define read(a, b, c)
Definition: win32.h:13
void _dosmaperr(unsigned long)
Definition: win32error.c:177

References _dosmaperr(), close, COPY_BUF_SIZE, PG_BINARY, pg_fatal, pg_file_create_mode, pg_free(), pg_malloc(), read, strerror, and write.

Referenced by transfer_relfile().

◆ linkFile()

void linkFile ( const char *  src,
const char *  dst,
const char *  schemaName,
const char *  relName 
)

Definition at line 150 of file file.c.

152 {
153  if (link(src, dst) < 0)
154  pg_fatal("error while creating link for relation \"%s.%s\" (\"%s\" to \"%s\"): %s",
155  schemaName, relName, src, dst, strerror(errno));
156 }

References link(), pg_fatal, and strerror.

Referenced by transfer_relfile().

◆ rewriteVisibilityMap()

void rewriteVisibilityMap ( const char *  fromfile,
const char *  tofile,
const char *  schemaName,
const char *  relName 
)

Definition at line 176 of file file.c.

178 {
179  int src_fd;
180  int dst_fd;
181  PGIOAlignedBlock buffer;
182  PGIOAlignedBlock new_vmbuf;
183  ssize_t totalBytesRead = 0;
184  ssize_t src_filesize;
185  int rewriteVmBytesPerPage;
186  BlockNumber new_blkno = 0;
187  struct stat statbuf;
188 
189  /* Compute number of old-format bytes per new page */
190  rewriteVmBytesPerPage = (BLCKSZ - SizeOfPageHeaderData) / 2;
191 
192  if ((src_fd = open(fromfile, O_RDONLY | PG_BINARY, 0)) < 0)
193  pg_fatal("error while copying relation \"%s.%s\": could not open file \"%s\": %s",
194  schemaName, relName, fromfile, strerror(errno));
195 
196  if (fstat(src_fd, &statbuf) != 0)
197  pg_fatal("error while copying relation \"%s.%s\": could not stat file \"%s\": %s",
198  schemaName, relName, fromfile, strerror(errno));
199 
200  if ((dst_fd = open(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
201  pg_file_create_mode)) < 0)
202  pg_fatal("error while copying relation \"%s.%s\": could not create file \"%s\": %s",
203  schemaName, relName, tofile, strerror(errno));
204 
205  /* Save old file size */
206  src_filesize = statbuf.st_size;
207 
208  /*
209  * Turn each visibility map page into 2 pages one by one. Each new page
210  * has the same page header as the old one. If the last section of the
211  * last page is empty, we skip it, mostly to avoid turning one-page
212  * visibility maps for small relations into two pages needlessly.
213  */
214  while (totalBytesRead < src_filesize)
215  {
216  ssize_t bytesRead;
217  char *old_cur;
218  char *old_break;
219  char *old_blkend;
220  PageHeaderData pageheader;
221  bool old_lastblk;
222 
223  if ((bytesRead = read(src_fd, buffer.data, BLCKSZ)) != BLCKSZ)
224  {
225  if (bytesRead < 0)
226  pg_fatal("error while copying relation \"%s.%s\": could not read file \"%s\": %s",
227  schemaName, relName, fromfile, strerror(errno));
228  else
229  pg_fatal("error while copying relation \"%s.%s\": partial page found in file \"%s\"",
230  schemaName, relName, fromfile);
231  }
232 
233  totalBytesRead += BLCKSZ;
234  old_lastblk = (totalBytesRead == src_filesize);
235 
236  /* Save the page header data */
237  memcpy(&pageheader, buffer.data, SizeOfPageHeaderData);
238 
239  /*
240  * These old_* variables point to old visibility map page. old_cur
241  * points to current position on old page. old_blkend points to end of
242  * old block. old_break is the end+1 position on the old page for the
243  * data that will be transferred to the current new page.
244  */
245  old_cur = buffer.data + SizeOfPageHeaderData;
246  old_blkend = buffer.data + bytesRead;
247  old_break = old_cur + rewriteVmBytesPerPage;
248 
249  while (old_break <= old_blkend)
250  {
251  char *new_cur;
252  bool empty = true;
253  bool old_lastpart;
254 
255  /* First, copy old page header to new page */
256  memcpy(new_vmbuf.data, &pageheader, SizeOfPageHeaderData);
257 
258  /* Rewriting the last part of the last old page? */
259  old_lastpart = old_lastblk && (old_break == old_blkend);
260 
261  new_cur = new_vmbuf.data + SizeOfPageHeaderData;
262 
263  /* Process old page bytes one by one, and turn it into new page. */
264  while (old_cur < old_break)
265  {
266  uint8 byte = *(uint8 *) old_cur;
267  uint16 new_vmbits = 0;
268  int i;
269 
270  /* Generate new format bits while keeping old information */
271  for (i = 0; i < BITS_PER_BYTE; i++)
272  {
273  if (byte & (1 << i))
274  {
275  empty = false;
276  new_vmbits |=
278  }
279  }
280 
281  /* Copy new visibility map bytes to new-format page */
282  new_cur[0] = (char) (new_vmbits & 0xFF);
283  new_cur[1] = (char) (new_vmbits >> 8);
284 
285  old_cur++;
286  new_cur += BITS_PER_HEAPBLOCK;
287  }
288 
289  /* If the last part of the last page is empty, skip writing it */
290  if (old_lastpart && empty)
291  break;
292 
293  /* Set new checksum for visibility map page, if enabled */
295  ((PageHeader) new_vmbuf.data)->pd_checksum =
296  pg_checksum_page(new_vmbuf.data, new_blkno);
297 
298  errno = 0;
299  if (write(dst_fd, new_vmbuf.data, BLCKSZ) != BLCKSZ)
300  {
301  /* if write didn't set errno, assume problem is no disk space */
302  if (errno == 0)
303  errno = ENOSPC;
304  pg_fatal("error while copying relation \"%s.%s\": could not write file \"%s\": %s",
305  schemaName, relName, tofile, strerror(errno));
306  }
307 
308  /* Advance for next new page */
309  old_break += rewriteVmBytesPerPage;
310  new_blkno++;
311  }
312  }
313 
314  /* Clean up */
315  close(dst_fd);
316  close(src_fd);
317 }
uint32 BlockNumber
Definition: block.h:31
PageHeaderData * PageHeader
Definition: bufpage.h:170
#define SizeOfPageHeaderData
Definition: bufpage.h:213
unsigned short uint16
Definition: c.h:494
unsigned char uint8
Definition: c.h:493
uint16 pg_checksum_page(char *page, BlockNumber blkno)
int i
Definition: isn.c:73
#define BITS_PER_BYTE
ControlData controldata
Definition: pg_upgrade.h:280
uint32 data_checksum_version
Definition: pg_upgrade.h:246
char data[BLCKSZ]
Definition: c.h:1150
#define BITS_PER_HEAPBLOCK
#define VISIBILITYMAP_ALL_VISIBLE
#define fstat
Definition: win32_port.h:283

References BITS_PER_BYTE, BITS_PER_HEAPBLOCK, close, ClusterInfo::controldata, PGIOAlignedBlock::data, ControlData::data_checksum_version, fstat, i, new_cluster, PG_BINARY, pg_checksum_page(), pg_fatal, pg_file_create_mode, read, SizeOfPageHeaderData, stat::st_size, strerror, VISIBILITYMAP_ALL_VISIBLE, and write.

Referenced by transfer_relfile().