Perforce 性能备份问题

Perforce 性能备份问题,perforce,Perforce,为了安全起见,备份Performce server目录下的所有文件就足够了吗?简短回答:否 详细回答:有关Performce数据的备份和恢复,您需要了解的所有信息,请参阅。简而言之,对于不耐烦的人来说: p4验证//… (验证服务器的完整性) p4管理检查点 (创建检查点;确保此步骤成功) 备份检查点文件和旧日志文件 (如果使用日志文件运行Perforce,则应使用日志文件) 备份您的版本文件 (这是实际数据,不要与Perforce服务器目录中的db.*文件混淆。) 但请务必阅读手册,特别是有关

为了安全起见,备份Performce server目录下的所有文件就足够了吗?

简短回答:否
详细回答:有关Performce数据的备份和恢复,您需要了解的所有信息,请参阅。简而言之,对于不耐烦的人来说:

  • p4验证//…
    (验证服务器的完整性)
  • p4管理检查点
    (创建检查点;确保此步骤成功)
  • 备份检查点文件和旧日志文件
    (如果使用日志文件运行Perforce,则应使用日志文件)
  • 备份您的版本文件
    (这是实际数据,不要与Perforce服务器目录中的db.*文件混淆。)
  • 但请务必阅读手册,特别是有关各种恢复方案的内容。记得:
    备份通常工作正常,恢复失败。

    除了jhwist在p4手册答案中的正确答案()之外,我想补充几点我在使用Performance几年期间学到的东西

    根据存储库的大小,对p4数据库执行验证可能需要几个小时,在验证过程中将被锁定,并且没有人能够执行任何查询。锁定P4数据库可能会对您的用户产生一些流上效应,例如:如果有人正在使用或试图在此期间使用P4SCC插件(即用于visual studio集成),它将旋转,用户最终将不得不强制退出以重新获得控制权

    解决方案

  • 在不同端口上生成第二个P4D实例(P4D_2)
  • 挂起/终止主实例(p4d_1)
  • 使用p4d_2执行
    p4验证//…
    和检查点
  • 备份存储阵列上的物理版本文件
  • 杀死p4d_2
  • 重新启动p4d_1 另外:由于这很可能是一个在夜间或周末运行的自动化过程,因此您需要彻底阅读检查点日志文件以确保其成功,否则您将在需要执行恢复时遇到困难(阅读下一点)。备份不应是一个“一劳永逸”的过程

    有关Perforce备份的更多信息,请参阅Perforce白皮书:


    HTH,

    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;
    }
    

    步骤3是错误的,一旦创建了新的检查点,就不需要旧的日志文件。重新阅读文档。此外,您可以跳过第1步和第2步,如果不想创建新的检查点,只备份当前日志文件。对于单个用户不打算在备份运行时提交任何内容的简单安装,停止服务器(例如p4 admin stop)是否有问题,制作数据库和仓库文件的副本,并重新启动服务器?
    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