开发者

perforce backup question

for safety purpose, is it enough to backup开发者_JS百科 all the files under perforce server directory?


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.


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,


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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜