218{
219 int src_fd;
220 int dst_fd;
223 ssize_t totalBytesRead = 0;
224 ssize_t src_filesize;
225 int rewriteVmBytesPerPage;
228
229 /* Compute number of old-format bytes per new page */
231
232 if ((src_fd = open(fromfile, O_RDONLY |
PG_BINARY, 0)) < 0)
233 pg_fatal(
"error while copying relation \"%s.%s\": could not open file \"%s\": %m",
234 schemaName, relName, fromfile);
235
236 if (
fstat(src_fd, &statbuf) != 0)
237 pg_fatal(
"error while copying relation \"%s.%s\": could not stat file \"%s\": %m",
238 schemaName, relName, fromfile);
239
240 if ((dst_fd = open(tofile, O_RDWR | O_CREAT | O_EXCL |
PG_BINARY,
242 pg_fatal(
"error while copying relation \"%s.%s\": could not create file \"%s\": %m",
243 schemaName, relName, tofile);
244
245 /* Save old file size */
246 src_filesize = statbuf.st_size;
247
248 /*
249 * Turn each visibility map page into 2 pages one by one. Each new page
250 * has the same page header as the old one. If the last section of the
251 * last page is empty, we skip it, mostly to avoid turning one-page
252 * visibility maps for small relations into two pages needlessly.
253 */
254 while (totalBytesRead < src_filesize)
255 {
256 ssize_t bytesRead;
257 char *old_cur;
258 char *old_break;
259 char *old_blkend;
261 bool old_lastblk;
262
263 if ((bytesRead =
read(src_fd, buffer.
data, BLCKSZ)) != BLCKSZ)
264 {
265 if (bytesRead < 0)
266 pg_fatal(
"error while copying relation \"%s.%s\": could not read file \"%s\": %m",
267 schemaName, relName, fromfile);
268 else
269 pg_fatal(
"error while copying relation \"%s.%s\": partial page found in file \"%s\"",
270 schemaName, relName, fromfile);
271 }
272
273 totalBytesRead += BLCKSZ;
274 old_lastblk = (totalBytesRead == src_filesize);
275
276 /* Save the page header data */
278
279 /*
280 * These old_* variables point to old visibility map page. old_cur
281 * points to current position on old page. old_blkend points to end of
282 * old block. old_break is the end+1 position on the old page for the
283 * data that will be transferred to the current new page.
284 */
286 old_blkend = buffer.
data + bytesRead;
287 old_break = old_cur + rewriteVmBytesPerPage;
288
289 while (old_break <= old_blkend)
290 {
291 char *new_cur;
292 bool empty = true;
293 bool old_lastpart;
294
295 /* First, copy old page header to new page */
297
298 /* Rewriting the last part of the last old page? */
299 old_lastpart = old_lastblk && (old_break == old_blkend);
300
302
303 /* Process old page bytes one by one, and turn it into new page. */
304 while (old_cur < old_break)
305 {
309
310 /* Generate new format bits while keeping old information */
312 {
314 {
315 empty = false;
316 new_vmbits |=
318 }
319 }
320
321 /* Copy new visibility map bytes to new-format page */
322 new_cur[0] = (char) (new_vmbits & 0xFF);
323 new_cur[1] = (char) (new_vmbits >> 8);
324
325 old_cur++;
327 }
328
329 /* If the last part of the last page is empty, skip writing it */
330 if (old_lastpart && empty)
331 break;
332
333 /* Set new checksum for visibility map page, if enabled */
337
338 errno = 0;
339 if (
write(dst_fd, new_vmbuf.
data, BLCKSZ) != BLCKSZ)
340 {
341 /* if write didn't set errno, assume problem is no disk space */
342 if (errno == 0)
343 errno = ENOSPC;
344 pg_fatal(
"error while copying relation \"%s.%s\": could not write file \"%s\": %m",
345 schemaName, relName, tofile);
346 }
347
348 /* Advance for next new page */
349 old_break += rewriteVmBytesPerPage;
350 new_blkno++;
351 }
352 }
353
354 /* Clean up */
357}
PageHeaderData * PageHeader
#define SizeOfPageHeaderData
uint16 pg_checksum_page(char *page, BlockNumber blkno)
uint32 data_checksum_version
#define BITS_PER_HEAPBLOCK
#define VISIBILITYMAP_ALL_VISIBLE