强制备份问题

发布于 2024-10-07 16:58:08 字数 40 浏览 2 评论 0原文

为了安全起见,备份perforce服务器目录下的所有文件是否足够?

for safety purpose, is it enough to backup all the files under perforce server directory?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

柠檬色的秋千 2024-10-14 16:58:08

简短回答:否
长答案:您需要了解的有关 Perforce 数据备份和恢复的所有信息,请参阅 手动。简而言之,对于不耐烦的人:

  1. p4 verify //...
    (验证服务器的完整性)
  2. p4 管理检查点
    (做一个检查点;确保这一步成功)
  3. 备份检查点文件和旧的日志文件
    (如果您使用日志文件运行 Perforce,您应该这样做)
  4. 备份您的版本化文件
    (这是实际数据,不要与 Perforce 服务器目录中的 db.* 文件混淆。)

但请务必阅读手册,尤其是有关各种恢复方案的内容。记住:
备份通常工作正常,只是恢复失败。

Short answer: No
Long answer: All you need to know about backup and recovery of Perforce data is detailed in the Manual. In a nutshell for the impatient:

  1. p4 verify //...
    (Verify the integrity of your server)
  2. p4 admin checkpoint
    (Make a checkpoint; make sure that this step is successful)
  3. back up the checkpoint file and the old journal file
    (if you run Perforce with Journal files, which you should)
  4. back up your versioned files
    (that's the actual data, not to be confused with the db.* files in the Perforce server directory.)

But please do read the manual, especially about the various restore scenarios. Remember:
Backups usually work fine, it's the restore that fails.

溇涏 2024-10-14 16:58:08

除了 p4 手动答案中 jhwist 的正确答案(永久链接)我想添加这是我在使用 Perforce 几年的过程中学到的一些东西。

...

根据存储库的大小,对 p4 数据库执行验证可能需要几个小时,在此期间将被锁定,并且没有人能够执行任何查询。锁定 P4 数据库可能会对用户产生多种流程影响,例如:如果有人在这段时间内使用或尝试使用 P4,P4SCC 插件(即用于 Visual Studio 集成)将会旋转,用户最终会必须强制退出才能重新获得控制权。

解决方案

  1. 在不同端口上生成第二个 P4D 实例 (p4d_2)
  2. 挂起/终止主实例 (p4d_1)。
  3. 使用 p4d_2 执行 p4 verify //... 和检查点。
  4. 备份存储阵列上的物理版本文件。
  5. 杀死 p4d_2。
  6. 重新启动 p4d_1。

另外:由于这很可能是在晚上或周末运行的自动化过程,因此您必须需要彻底阅读检查点日志文件以确保其成功 否则,当您需要执行恢复时,您将陷入困境(请阅读下一点)。备份不应该是一个一劳永逸的过程。

有关 Perforce 备份的更多信息,请参阅 Perforce 白皮书:Perforce 的高可用性和灾难恢复解决方案。

哈特哈,

In addition to jhwist's correct from the p4 manual answer (permalink) I would like to add a few things that I've learnt during using Perforce for several years.

...

Depending on the size of your repository performing a verify on the p4 database can take several hours, which during it will be locked and no one will be able to perform any queries. Locking the P4 database can have several on flow effects to your users, for example: if someone is using or attempts to use P4 during this time a P4SCC plug-in (ie. for visual studio integration) it will spin and the user will eventually have to force quit to regain control.

Solution

  1. Spawn a second instance of P4D on a different port (p4d_2)
  2. Suspend/terminate the main instance (p4d_1).
  3. Perform the p4 verify //... and checkpoint using p4d_2.
  4. Backup the physical version files on the storage array.
  5. Kill p4d_2.
  6. Restart p4d_1.

Also: As this will be more than likely be an automated process run at night or over the weekend can cannot stress enough that you need to thoroughly read the checkpoint log file to ensure that it was successful otherwise you will be in a difficult spot when you need to perform a restore (read the next point). Backup should not be a set and forget procedure.

Further information about Perforce backup can be found in Perforce whitepaper: High Availability And Disaster Recovery Solutions For Perforce.

HTH,

北斗星光 2024-10-14 16:58:08

FWIW 我在自己的开发工作站上使用了额外的备份策略。我有一个 perl 脚本,每天晚上运行,并查找我从给定的工作空间列表中从 Perforce 签出的所有文件。然后,该文件列表将作为我正常工作站备份过程的一部分进行备份。查找已检出文件的 Perl 脚本对我来说看起来相当棘手。它不是我写的,对 Perl 也不是特别熟悉。

如果有人感兴趣,我可以在这里发布脚本以及我如何调用它。

请注意,该脚本是在 Perforce 推出“搁置”功能之前开发的。我现在可能会更好地拥有一个每天晚上“搁置”我的工作的脚本(除了我当前的备份策略之外或代替它)。

这是脚本:

# This script copies any files that are opened for any action (other than
# delete) in the specified client workspace to another specified directory.
# The directory structure of the workspace is duplicated in the target
# directory.  Furthermore, a file is not copied if it already exists in the
# target directory unless the file in the workspace is newer than the one
# in the target directory.

# Note: This script looks at *all* pending changelists in the specified
# workspace.
# Note: This script uses the client specification Root to get the local
# pathname of the files.  So if you are using a substituted drive for the
# client root, it must be properly substituted before running this script.

# Argument 1: Client workspace name
# Argument 2: Target directory (full path)

use File::Path;
# use File::Copy;
use File::Basename;
use Win32;

if ($#ARGV != 1) {
    die("usage: $0 client_name target_directory\n");
}

my $client = shift(@ARGV);
my $target_dir = shift(@ARGV);
my @opened_files = ();
my $client_root = "";
my $files_copied = 0;

# I need to know the root directory of the client, so that I can derive the
# local pathname of the file.  Strange that "p4 -ztag opened" doesn't give
# me the local pathname; I would have expected it to.

open(CLIENT_SPEC, "p4 -c $client client -o|")
        || die("Cannot retrieve client specification: $!");
while (<CLIENT_SPEC>) {
    my ($tag, $value) = split(/\s/, $_, 2);
    if ($tag eq "Root:") {
        $value = chop_line($value);
        $client_root = $value;
    }
}
close(CLIENT_SPEC);
if ($client_root eq "") {
    die("Unable to determine root of client $client\n");
} elsif (substr($client_root, -1) ne "\\") {
    $client_root = $client_root . "\\";
} 

# Use the -ztag option so that we can get the client file path as well as
# the depot path.

open(OPENED_FILES, "p4 -c $client -ztag opened|")
        || die("Cannot get list of opened files: $!");
while (<OPENED_FILES>) {
    # What we do is to get the client path and append it onto the
    # @opened_files array.  Then when we get the action, if it is a delete,
    # we pop the last entry back off the array.  This assumes that the tags
    # come out with clientFile before action.

    $_ = chop_line($_);
    my ($prefix, $tag, $value) = split(/\s/, $_, 3);
    if ($tag eq "clientFile") {
        push(@opened_files, $value);
    }
    if ( ($tag eq "action") && ($value eq "delete") ) {
        pop(@opened_files);
    }
}
close(OPENED_FILES);

# Okay, now we have the list of opened files.  Process each file to
# copy it to the destination.

foreach $client_path (@opened_files) {

    # Trim off the client name and replace it with the client root
    # directory.  Also replace forward slashes with backslashes.

    $client_path = substr($client_path, length($client) + 3);
    $client_path =~ s/\//\\/g;
    my $local_path = $client_root . $client_path;

    # Okay, now $client_path is the partial pathname starting at the
    # client's root.  That's the path we also want to use starting at the
    # target path for the destination.

    my $dest_path = $target_dir . "\\" . $client_path;
    my $copy_it = 0;

    if (-e $dest_path) {
        # Target exists.  Is the local path newer?
        my @target_stat = stat($dest_path);
        my @local_stat = stat($local_path);
        
        if ($local_stat[9] > $target_stat[9]) {
            $copy_it = 1;
        }
    } else {
        # Target does not exist, definitely copy it.  But we may have to
        # create some directories.  Use File::Path to do that.

        my ($basename, $dest_dir) = fileparse($dest_path);
        if (! (-e $dest_dir)) {
            mkpath($dest_dir) || die("Cannot create directory $dest_dir\n");
        }
        $copy_it = 1;
    }

    if ($copy_it) {
        Win32::CopyFile($local_path, $dest_path, 1)
                || warn("Could not copy file $local_path: $!\n");
        $files_copied++;
    }
}
print("$files_copied files copied.\n");

exit(0);

################ Subroutines #########################################

# chop_line removes any trailing carriage-returns or newlines from its
# argument and returns the possibly-modified string.

sub chop_line {
    my $string = shift;

    $string =~ s/[\r\n]*\z//;
    return $string;
}

运行:

REM Make sure that we are pointing to the current Perforce server
P4 set -s P4PORT=MyPerforceServer:ThePortThatPerforceIsOn
p4 set p4client=MyPerforceWorkspace

REM Copy checked out files to a local directory that will be backed up
.\p4backup.pl MyPerforceWorkspace c:\PerforceBackups\MyPerforceWorkspace_backup

FWIW I have used an additional backup strategy on my own development workstation. I have a perl script that runs every night and finds all files that I have checked out of Perforce from a given list of workspaces. That list of files is then backed up as part of my normal workstation backup procedure. The Perl script to find the files that are checked out looks pretty tricky to me. I did not write it and am not particularly familiar with Perl.

If anyone is interested, I can post the script here along with how I call it.

Note that this script was developed before Perforce came out with its "shelving" capability. I might be better off now to have a script that "shelves" my work every night (either in addition to my current backup strategy or in place of it).

Here is the script:

# This script copies any files that are opened for any action (other than
# delete) in the specified client workspace to another specified directory.
# The directory structure of the workspace is duplicated in the target
# directory.  Furthermore, a file is not copied if it already exists in the
# target directory unless the file in the workspace is newer than the one
# in the target directory.

# Note: This script looks at *all* pending changelists in the specified
# workspace.
# Note: This script uses the client specification Root to get the local
# pathname of the files.  So if you are using a substituted drive for the
# client root, it must be properly substituted before running this script.

# Argument 1: Client workspace name
# Argument 2: Target directory (full path)

use File::Path;
# use File::Copy;
use File::Basename;
use Win32;

if ($#ARGV != 1) {
    die("usage: $0 client_name target_directory\n");
}

my $client = shift(@ARGV);
my $target_dir = shift(@ARGV);
my @opened_files = ();
my $client_root = "";
my $files_copied = 0;

# I need to know the root directory of the client, so that I can derive the
# local pathname of the file.  Strange that "p4 -ztag opened" doesn't give
# me the local pathname; I would have expected it to.

open(CLIENT_SPEC, "p4 -c $client client -o|")
        || die("Cannot retrieve client specification: $!");
while (<CLIENT_SPEC>) {
    my ($tag, $value) = split(/\s/, $_, 2);
    if ($tag eq "Root:") {
        $value = chop_line($value);
        $client_root = $value;
    }
}
close(CLIENT_SPEC);
if ($client_root eq "") {
    die("Unable to determine root of client $client\n");
} elsif (substr($client_root, -1) ne "\\") {
    $client_root = $client_root . "\\";
} 

# Use the -ztag option so that we can get the client file path as well as
# the depot path.

open(OPENED_FILES, "p4 -c $client -ztag opened|")
        || die("Cannot get list of opened files: $!");
while (<OPENED_FILES>) {
    # What we do is to get the client path and append it onto the
    # @opened_files array.  Then when we get the action, if it is a delete,
    # we pop the last entry back off the array.  This assumes that the tags
    # come out with clientFile before action.

    $_ = chop_line($_);
    my ($prefix, $tag, $value) = split(/\s/, $_, 3);
    if ($tag eq "clientFile") {
        push(@opened_files, $value);
    }
    if ( ($tag eq "action") && ($value eq "delete") ) {
        pop(@opened_files);
    }
}
close(OPENED_FILES);

# Okay, now we have the list of opened files.  Process each file to
# copy it to the destination.

foreach $client_path (@opened_files) {

    # Trim off the client name and replace it with the client root
    # directory.  Also replace forward slashes with backslashes.

    $client_path = substr($client_path, length($client) + 3);
    $client_path =~ s/\//\\/g;
    my $local_path = $client_root . $client_path;

    # Okay, now $client_path is the partial pathname starting at the
    # client's root.  That's the path we also want to use starting at the
    # target path for the destination.

    my $dest_path = $target_dir . "\\" . $client_path;
    my $copy_it = 0;

    if (-e $dest_path) {
        # Target exists.  Is the local path newer?
        my @target_stat = stat($dest_path);
        my @local_stat = stat($local_path);
        
        if ($local_stat[9] > $target_stat[9]) {
            $copy_it = 1;
        }
    } else {
        # Target does not exist, definitely copy it.  But we may have to
        # create some directories.  Use File::Path to do that.

        my ($basename, $dest_dir) = fileparse($dest_path);
        if (! (-e $dest_dir)) {
            mkpath($dest_dir) || die("Cannot create directory $dest_dir\n");
        }
        $copy_it = 1;
    }

    if ($copy_it) {
        Win32::CopyFile($local_path, $dest_path, 1)
                || warn("Could not copy file $local_path: $!\n");
        $files_copied++;
    }
}
print("$files_copied files copied.\n");

exit(0);

################ Subroutines #########################################

# chop_line removes any trailing carriage-returns or newlines from its
# argument and returns the possibly-modified string.

sub chop_line {
    my $string = shift;

    $string =~ s/[\r\n]*\z//;
    return $string;
}

To run:

REM Make sure that we are pointing to the current Perforce server
P4 set -s P4PORT=MyPerforceServer:ThePortThatPerforceIsOn
p4 set p4client=MyPerforceWorkspace

REM Copy checked out files to a local directory that will be backed up
.\p4backup.pl MyPerforceWorkspace c:\PerforceBackups\MyPerforceWorkspace_backup
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文