A CVS repository can be backed up using the same backup tools and schedule that you use for ordinary text and binary files. You must be able to restore the repository with the same permissions and structure it had when it was backed up. You must restore the CVSROOT directory and its contents before the project directories are useful, but you can restore project root directories and their contents independently of each other.
If a file in a repository is being written to while a backup is in progress, it is possible that the file could be backed up in a state that might make it difficult for CVS to read it accurately when it is restored. For this reason, you should prevent processes from writing to the repository during a backup.
Freezing a repository is CVS-speak for the act of preventing users from changing the repository. The most common reason to freeze a repository is to ensure that a backup operation copies all the repository files in a consistent state.
The simplest way to freeze a repository is to block clients from accessing the CVS server. There are many ways to do this, such as shutting down the CVS server program, disallowing logins to the server system, blocking the server with a firewall rule, setting the server to single-user mode, or pulling out the network cable. Rather than blocking access to the server completely, you can use CVS's locks to read-lock the repository.
To keep the server running and allow clients to continue to read the repository files while a backup or other critical work takes place, use a script that creates lock files like CVS's internal locks. CVS honors these locks as if they were its own. Lock the directories you want to back up, make your backup, and then unlock the directories. See Section 6.4.2 in this chapter for a full explanation of CVS locks.
Example 6-7 shows a script that locks an entire repository. It attempts to lock the repository and backs off if it can't lock the whole repository. The backing off is necessary to prevent deadlocks. Example 6-8 shows a script that unlocks a repository.
#!/bin/sh # Freeze - Lock a whole repository for backup. KEYMAGIC=$$ TMPFILE=/tmp/freeze.$KEYMAGIC bail_out ( ) { # Exit abruptly. Return a failure code and display # an error message. echo "$1" rm -f $TMPFILE exit 1 } freeze_directory ( ) { echo "FREEZE: $1" # Obtain the master lock mkdir "$1/#cvslock" if [ $? != 0 ] then # Could not get master lock return 1 fi # Create the read lock touch "$1/#cvs.rfl.$KEYMAGIC" # Record it in case of trouble echo $1 >> $TMPFILE rmdir "$1/#cvslock" return 0 } thaw_repository ( ) { # If we encounter anyone else playing with the # CVS locks during this, then there's a small risk # of deadlock. In that event, we should undo everything # we've done to the repository, wait and try again. # This function removes all the locks we've produced during # the run so far. for dir in `cat $TMPFILE` do echo "** THAW ** $dir" mkdir "$dir/#cvslock" if [ $? ] then # Remove read lock rm -f "$dir/#cvs.rfl.$KEYMAGIC" # Remove masterlock rmdir "$dir/#cvslock" fi done return 0 } freeze_repository ( ) { for dirname in `find $CVSROOT/$REPOSITORY -type d ! -iname CVS ! \ -iname Attic ! -iname "#cvslock"` do freeze_directory $dirname if [ $? != 0 ] then # We couldn't get the master lock. # Someone else must be working on the # repository thaw_repository return 1 fi done return 0 } if [ "$CVSROOT" = = "" ] then echo "No CVSROOT specified in the environment" bail_out "Aborting" fi if [ "$KEYROOT" = = "" ] then KEYROOT="$CVSROOT" fi if [ "$1" = = "" ] then echo "No Repository specified." echo "Usage: $0 repository" bail_out "Aborting" else REPOSITORY="$1" fi # Double-check the validity of supplied paths KEYFILE=$KEYROOT/.$REPOSITORY test -d $CVSROOT || bail_out "Can't access $CVSROOT - is it a directory?" touch $KEYFILE || bail_out "Can't access $KEYFILE - aborting" TRIES=0 while ! freeze_repository do let TRIES=$TRIES+1 echo "Could not freeze. Repository in use. (Attempt $TRIES)" if [ $TRIES -gt 9 ] then bail_out "Giving up" fi echo " Sleeping 1 second." sleep 1 rm -f $TMPFILE echo "Trying again.." done echo "** Repository $REPOSITORY frozen" echo "$KEYMAGIC" >> $KEYROOT/.$REPOSITORY rm -f $TMPFILE exit 0
#!/bin/sh # Unfreeze - Unlock a whole repository. bail_out ( ) { # Exit abruptly. Return a failure code and display # an error message. echo "$*" rm -f $TMPFILE exit 1 } unfreeze_directory ( ) { echo "UNFREEZE: $1" mkdir "$1/#cvslock" if [ $? != 0 ] then # Could not get master lock return 1 fi test -f "$1/#cvs.rfl.$KEYMAGIC" || echo "THAW: Expected to find a lock file: \ # Proceed anyway. rm -f "$1/#cvs.rfl.$KEYMAGIC" rmdir "$1/#cvslock" return 0 } unfreeze_repository ( ) { TMPFILE=/tmp/freeze.$KEYMAGIC for dirname in `find $CVSROOT/$REPOSITORY -type d ! -iname CVS ! \ -iname Attic ! -iname "#cvslock"` do unfreeze_directory $dirname if [ $? != 0 ] then return 1 fi done return 0 } if [ "$CVSROOT" = = "" ] then echo "No CVSROOT specified in the environment" bail_out "Aborting" fi if [ "$KEYROOT" = = "" ] then KEYROOT="$CVSROOT" fi if [ "$1" = = "" ] then echo "No Repository specified." echo "Usage: $0 repository" bail_out "Aborting" else REPOSITORY="$1" fi # Double-check the validity of supplied paths KEYFILE=$KEYROOT/.$REPOSITORY test -d $CVSROOT || bail_out "Can't access $CVSROOT - is it a directory?" test -f $KEYFILE || bail_out "No $KEYFILE appears to exist. Repository does \ not appear to be frozen" TRIES=0 # Walk through each of the keys that the repository has been frozen with # and unlock each one in turn. A single run of unfreeze thaws multiple # runs of freeze. for KEYMAGIC in `cat $KEYFILE` do unfreeze_repository if [ "$?" = "1" ] then echo "** Unable to obtain master locks for all directories." let TRIES=$TRIES+1 if [ "$TRIES" = "10" ] then bail_out "Too many attempts. Giving up." fi sleep 1 echo "** Trying again." else echo "** Repository $REPOSITORY thawed from freeze $KEYMAGIC" fi done echo "** Unfreeze complete" echo "** Repository $REPOSITORY thawed" rm -f $KEYFILE exit 0
If you need to freeze the repository entirely, preventing anyone from either reading or writing, modify the scripts in Example 6-7 and 6-8 to create and remove write locks. For example, you need to do this when attempting to restore a backup of the whole repository.
A CVS repository can be restored using the same tools that you use to restore ordinary text and binary files. You must restore the CVSROOT directory and its contents to be able to use the project files reliably. You need not restore every project in the repository, but when you restore a project you should restore all its files and directories.
When you restore a repository, you must ensure that no one can write to it. You can do this by freezing the repository as described in Section 6.7.1, but if you use locks you must use write locks rather than the read locks described in that section. That's because the repository will be in an inconsistent state while the files are being restored; you don't want anyone to read from or write to the repository during the restore process.
After you have restored a CVS repository from a backup, it is safest to assume that any sandbox files are based on revisions that do not exist in the backup of the repository. This means that individual developers are likely to have changes in their sandboxes that need to be committed (or recommitted) to the repository in order to bring it up-to-date.
This is the simplest way to restore changes that have been preserved in sandboxes:
Check out a new sandbox from the restored repository.
Try to use commands such as cvs diff, cvs status, and cvs update on a sandbox from before the repository was restored, to determine which files have been changed and what the changes are. If this does not work, try using the Unix diff program to determine the differences between an old and the new sandbox.
Copy the old sandbox files you want to commit or recommit into the new sandbox.
Commit the changes as if they were ordinary changes.
Make sure the log message indicates what happened.
Many project teams have public, read-only CVS repositories. If you want to do likewise, you can copy the repository, reserve the original repository for your project work, and use the copy (or mirror) repository as a public repository.
The copy can be on the same computer as the original or it can be on a different computer or even a different network. Having two or more copies of a repository allows you to put one copy on a trusted network for your developers and another on a more public part of your network for the general public.
|
Mirror a repository by copying the repository files. To avoid getting part of one release and part of another due to the copy overlapping with a commit, freeze the repository with read locks before mirroring and unfreeze it afterward.
The Unix and Linux rsync program is a useful tool to use when mirroring. It allows you to recursively transfer only the changed files between any two directories and recovers properly if it's interrupted. It also has an optional CVS-exclusion mode, called with the --cvs-exclude option, which ignores the same files CVS ignores by default. Use the -e ssh option to rsync to transfer using the SSH protocol.
Top |