static void execute_pagemap(datapagemap_t *pagemap, const char *path) { datapagemap_iterator_t *iter; BlockNumber blkno; iter = datapagemap_iterate(pagemap); while (datapagemap_next(iter, &blkno)) { off_t offset = blkno * BLCKSZ; copy_file_range(path, offset, offset + BLCKSZ); } }
static void execute_pagemap(datapagemap_t *pagemap, const char *path) { datapagemap_iterator_t *iter; BlockNumber blkno; iter = datapagemap_iterate(pagemap); while (datapagemap_next(iter, &blkno)) { off_t offset = blkno * BLCKSZ; copy_file_range(path, offset, offset + BLCKSZ, false); /* Ok, this block has now been copied from new data dir to old */ } }
/* * Calculate the totals needed for progress reports. */ void calculate_totals(void) { file_entry_t *entry; int i; filemap_t *map = filemap; map->total_size = 0; map->fetch_size = 0; for (i = 0; i < map->narray; i++) { entry = map->array[i]; if (entry->type != FILE_TYPE_REGULAR) continue; map->total_size += entry->newsize; if (entry->action == FILE_ACTION_COPY) { map->fetch_size += entry->newsize; continue; } if (entry->action == FILE_ACTION_COPY_TAIL) map->fetch_size += (entry->newsize - entry->oldsize); if (entry->pagemap.bitmapsize > 0) { datapagemap_iterator_t *iter; BlockNumber blk; iter = datapagemap_iterate(&entry->pagemap); while (datapagemap_next(iter, &blk)) map->fetch_size += BLCKSZ; pg_free(iter); } } }
/* * Backup data file in the from_root directory to the to_root directory with * same relative path. * If lsn is not NULL, pages only which are modified after the lsn will be * copied. */ bool backup_data_file(const char *from_root, const char *to_root, pgFile *file, const XLogRecPtr *lsn) { char to_path[MAXPGPATH]; FILE *in; FILE *out; BackupPageHeader header; DataPage page; /* used as read buffer */ BlockNumber blknum = 0; size_t read_len = 0; pg_crc32 crc; off_t offset; INIT_CRC32C(crc); /* reset size summary */ file->read_size = 0; file->write_size = 0; /* open backup mode file for read */ in = fopen(file->path, "r"); if (in == NULL) { FIN_CRC32C(crc); file->crc = crc; /* maybe vanished, it's not error */ if (errno == ENOENT) return false; elog(ERROR, "cannot open backup mode file \"%s\": %s", file->path, strerror(errno)); } /* open backup file for write */ if (check) snprintf(to_path, lengthof(to_path), "%s/tmp", backup_path); else join_path_components(to_path, to_root, file->path + strlen(from_root) + 1); out = fopen(to_path, "w"); if (out == NULL) { int errno_tmp = errno; fclose(in); elog(ERROR, "cannot open backup file \"%s\": %s", to_path, strerror(errno_tmp)); } /* confirm server version */ check_server_version(); /* * Read each page and write the page excluding hole. If it has been * determined that the page can be copied safely, but no page map * has been built, it means that we are in presence of a relation * file that needs to be completely scanned. If a page map is present * only scan the blocks needed. In each case, pages are copied without * their hole to ensure some basic level of compression. */ if (file->pagemap.bitmapsize == 0) { for (blknum = 0; (read_len = fread(&page, 1, sizeof(page), in)) == sizeof(page); ++blknum) { XLogRecPtr page_lsn; int upper_offset; int upper_length; header.block = blknum; /* * If an invalid data page was found, fallback to simple copy to ensure * all pages in the file don't have BackupPageHeader. */ if (!parse_page(&page, &page_lsn, &header.hole_offset, &header.hole_length)) { elog(LOG, "%s fall back to simple copy", file->path); fclose(in); fclose(out); file->is_datafile = false; return copy_file(from_root, to_root, file); } file->read_size += read_len; /* if the page has not been modified since last backup, skip it */ if (lsn && !XLogRecPtrIsInvalid(page_lsn) && page_lsn < *lsn) continue; upper_offset = header.hole_offset + header.hole_length; upper_length = BLCKSZ - upper_offset; /* write data page excluding hole */ if (fwrite(&header, 1, sizeof(header), out) != sizeof(header) || fwrite(page.data, 1, header.hole_offset, out) != header.hole_offset || fwrite(page.data + upper_offset, 1, upper_length, out) != upper_length) { int errno_tmp = errno; /* oops */ fclose(in); fclose(out); elog(ERROR, "cannot write at block %u of \"%s\": %s", blknum, to_path, strerror(errno_tmp)); } /* update CRC */ COMP_CRC32C(crc, &header, sizeof(header)); COMP_CRC32C(crc, page.data, header.hole_offset); COMP_CRC32C(crc, page.data + upper_offset, upper_length); file->write_size += sizeof(header) + read_len - header.hole_length; } } else { datapagemap_iterator_t *iter; iter = datapagemap_iterate(&file->pagemap); while (datapagemap_next(iter, &blknum)) { XLogRecPtr page_lsn; int upper_offset; int upper_length; int ret; offset = blknum * BLCKSZ; if (offset > 0) { ret = fseek(in, offset, SEEK_SET); if (ret != 0) elog(ERROR, "Can't seek in file offset: %llu ret:%i\n", (long long unsigned int) offset, ret); } read_len = fread(&page, 1, sizeof(page), in); header.block = blknum; /* * If an invalid data page was found, fallback to simple copy to ensure * all pages in the file don't have BackupPageHeader. */ if (!parse_page(&page, &page_lsn, &header.hole_offset, &header.hole_length)) { elog(LOG, "%s fall back to simple copy", file->path); fclose(in); fclose(out); file->is_datafile = false; return copy_file(from_root, to_root, file); } file->read_size += read_len; /* if the page has not been modified since last backup, skip it */ if (lsn && !XLogRecPtrIsInvalid(page_lsn) && page_lsn < *lsn) continue; upper_offset = header.hole_offset + header.hole_length; upper_length = BLCKSZ - upper_offset; /* write data page excluding hole */ if (fwrite(&header, 1, sizeof(header), out) != sizeof(header) || fwrite(page.data, 1, header.hole_offset, out) != header.hole_offset || fwrite(page.data + upper_offset, 1, upper_length, out) != upper_length) { int errno_tmp = errno; /* oops */ fclose(in); fclose(out); elog(ERROR, "cannot write at block %u of \"%s\": %s", blknum, to_path, strerror(errno_tmp)); } /* update CRC */ COMP_CRC32C(crc, &header, sizeof(header)); COMP_CRC32C(crc, page.data, header.hole_offset); COMP_CRC32C(crc, page.data + upper_offset, upper_length); file->write_size += sizeof(header) + read_len - header.hole_length; } pg_free(iter); } /* * update file permission * FIXME: Should set permission on open? */ if (!check && chmod(to_path, FILE_PERMISSION) == -1) { int errno_tmp = errno; fclose(in); fclose(out); elog(ERROR, "cannot change mode of \"%s\": %s", file->path, strerror(errno_tmp)); } fclose(in); fclose(out); /* finish CRC calculation and store into pgFile */ FIN_CRC32C(crc); file->crc = crc; /* Treat empty file as not-datafile */ if (file->read_size == 0) file->is_datafile = false; /* We do not backup if all pages skipped. */ if (file->write_size == 0 && file->read_size > 0) { if (remove(to_path) == -1) elog(ERROR, "cannot remove file \"%s\": %s", to_path, strerror(errno)); return false; } /* remove $BACKUP_PATH/tmp created during check */ if (check) remove(to_path); return true; }