FreeBSD/contrib/subversion/subversion/libsvn_fs_fs/hotcopy.c
/* Perform a hotcopy, either normal or incremental.
 *
 * Normal hotcopy assumes that the destination exists as an empty
 * directory. It behaves like an incremental hotcopy except that
 * none of the copied files already exist in the destination.
 *
 * An incremental hotcopy copies only changed or new files to the destination,
 * and removes files from the destination no longer present in the source.
 * While the incremental hotcopy is running, readers should still be able
 * to access the destintation repository without error and should not see
 * revisions currently in progress of being copied. Readers are able to see
 * new fully copied revisions even if the entire incremental hotcopy procedure
 * has not yet completed.
 *
 * Writers are blocked out completely during the entire incremental hotcopy
 * process to ensure consistency. This function assumes that the repository
 * write-lock is held.
 */
Perform a hotcopy, either normal or incremental.
Normal hotcopy assumes that the destination exists as an empty
directory. It behaves like an incremental hotcopy except that
none of the copied files already exist in the destination.

An incremental hotcopy copies only changed or new files to the destination,
and removes files from the destination no longer present in the source.
While the incremental hotcopy is running, readers should still be able
to access the destintation repository without error and should not see
revisions currently in progress of being copied. Readers are able to see
new fully copied revisions even if the entire incremental hotcopy procedure
has not yet completed.

Writers are blocked out completely during the entire incremental hotcopy
process to ensure consistency. This function assumes that the repository
write-lock is held.
Perform a hotcopy either normal or incremental . Normal hotcopy assumes that the destination exists as an empty directory . It behaves like an incremental hotcopy except that none of the copied files already exist in the destination . An incremental hotcopy copies only changed or new files to the destination and removes files from the destination no longer present in the source . While the incremental hotcopy is running readers should still be able to access the destintation repository without error and should not see revisions currently in progress of being copied . Readers are able to see new fully copied revisions even if the entire incremental hotcopy procedure has not yet completed . Writers are blocked out completely during the entire incremental hotcopy process to ensure consistency . This function assumes that the repository write - lock is held .
static svn_error_t *
hotcopy_body(void *baton, apr_pool_t *pool)
{
  struct hotcopy_body_baton *hbb = baton;
  svn_fs_t *src_fs = hbb->src_fs;
  fs_fs_data_t *src_ffd = src_fs->fsap_data;
  svn_fs_t *dst_fs = hbb->dst_fs;
  fs_fs_data_t *dst_ffd = dst_fs->fsap_data;
  svn_boolean_t incremental = hbb->incremental;
  svn_fs_hotcopy_notify_t notify_func = hbb->notify_func;
  void* notify_baton = hbb->notify_baton;
  svn_cancel_func_t cancel_func = hbb->cancel_func;
  void* cancel_baton = hbb->cancel_baton;
  svn_revnum_t src_youngest;
  apr_uint64_t src_next_node_id;
  apr_uint64_t src_next_copy_id;
  svn_revnum_t dst_youngest;
  const char *src_revprops_dir;
  const char *dst_revprops_dir;
  const char *src_revs_dir;
  const char *dst_revs_dir;
  const char *src_subdir;
  const char *dst_subdir;
  svn_node_kind_t kind;
  if (src_ffd->format >= SVN_FS_FS__MIN_CONFIG_FILE)
    {
      svn_error_t *err;
      err = svn_io_dir_file_copy(src_fs->path, dst_fs->path, PATH_CONFIG,
                                 pool);
      if (err)
        {
          if (APR_STATUS_IS_ENOENT(err->apr_err))
            {
              const char *src_abspath;
              const char *dst_abspath;
              const char *config_relpath;
              svn_error_t *err2;
              config_relpath = svn_dirent_join(src_fs->path, PATH_CONFIG, pool);
              err2 = svn_dirent_get_absolute(&src_abspath, src_fs->path, pool);
              if (err2)
                return svn_error_trace(svn_error_compose_create(err, err2));
              err2 = svn_dirent_get_absolute(&dst_abspath, dst_fs->path, pool);
              if (err2)
                return svn_error_trace(svn_error_compose_create(err, err2));
              src_abspath = svn_dirent_dirname(src_abspath, pool);
              dst_abspath = svn_dirent_dirname(dst_abspath, pool);
              return svn_error_quick_wrapf(err,
                                 _("Failed to create hotcopy at '%s'. "
                                   "The file '%s' is missing from the source "
                                   "repository. Please create this file, for "
                                   "instance by running 'svnadmin upgrade %s'"),
                                 dst_abspath, config_relpath, src_abspath);
            }
          else
            return svn_error_trace(err);
        }
    }
  if (cancel_func)
    SVN_ERR(cancel_func(cancel_baton));
  SVN_ERR(svn_fs_fs__read_current(&src_youngest, &src_next_node_id,
                                  &src_next_copy_id, src_fs, pool));
  if (incremental)
    {
      SVN_ERR(svn_fs_fs__youngest_rev(&dst_youngest, dst_fs, pool));
      if (src_youngest < dst_youngest)
        return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                 _("The hotcopy destination already contains more revisions "
                   "(%lu) than the hotcopy source contains (%lu); are source "
                   "and destination swapped?"),
                   dst_youngest, src_youngest);
    }
  else
    dst_youngest = 0;
  src_revs_dir = svn_dirent_join(src_fs->path, PATH_REVS_DIR, pool);
  dst_revs_dir = svn_dirent_join(dst_fs->path, PATH_REVS_DIR, pool);
  src_revprops_dir = svn_dirent_join(src_fs->path, PATH_REVPROPS_DIR, pool);
  dst_revprops_dir = svn_dirent_join(dst_fs->path, PATH_REVPROPS_DIR, pool);
  SVN_ERR(svn_io_make_dir_recursively(dst_revs_dir, pool));
  SVN_ERR(svn_io_make_dir_recursively(dst_revprops_dir, pool));
  if (cancel_func)
    SVN_ERR(cancel_func(cancel_baton));
  if (src_ffd->format >= SVN_FS_FS__MIN_NO_GLOBAL_IDS_FORMAT)
    {
      SVN_ERR(hotcopy_revisions(src_fs, dst_fs, src_youngest, dst_youngest,
                                incremental, src_revs_dir, dst_revs_dir,
                                src_revprops_dir, dst_revprops_dir,
                                notify_func, notify_baton,
                                cancel_func, cancel_baton, pool));
      SVN_ERR(svn_fs_fs__write_current(dst_fs, src_youngest, 0, 0, pool));
    }
  else
    {
      SVN_ERR(hotcopy_revisions_old(src_fs, dst_fs, src_youngest,
                                    src_revs_dir, dst_revs_dir,
                                    src_revprops_dir, dst_revprops_dir,
                                    notify_func, notify_baton,
                                    cancel_func, cancel_baton, pool));
      SVN_ERR(svn_fs_fs__write_current(dst_fs, src_youngest, src_next_node_id,
                                       src_next_copy_id, pool));
    }
  dst_subdir = svn_dirent_join(dst_fs->path, PATH_LOCKS_DIR, pool);
  SVN_ERR(svn_io_remove_dir2(dst_subdir, TRUE, cancel_func, cancel_baton,
                             pool));
  src_subdir = svn_dirent_join(src_fs->path, PATH_LOCKS_DIR, pool);
  SVN_ERR(svn_io_check_path(src_subdir, &kind, pool));
  if (kind == svn_node_dir)
    SVN_ERR(svn_io_copy_dir_recursively(src_subdir, dst_fs->path,
                                        PATH_LOCKS_DIR, TRUE,
                                        cancel_func, cancel_baton, pool));
  src_subdir = svn_dirent_join(src_fs->path, PATH_NODE_ORIGINS_DIR, pool);
  SVN_ERR(svn_io_check_path(src_subdir, &kind, pool));
  if (kind == svn_node_dir)
    SVN_ERR(hotcopy_io_copy_dir_recursively(NULL, src_subdir, dst_fs->path,
                                            PATH_NODE_ORIGINS_DIR, TRUE,
                                            cancel_func, cancel_baton, pool));
  if (dst_ffd->format >= SVN_FS_FS__MIN_REP_SHARING_FORMAT)
    {
      src_subdir = svn_dirent_join(src_fs->path, REP_CACHE_DB_NAME, pool);
      dst_subdir = svn_dirent_join(dst_fs->path, REP_CACHE_DB_NAME, pool);
      SVN_ERR(svn_io_check_path(src_subdir, &kind, pool));
      if (kind == svn_node_file)
        {
          SVN_ERR(svn_sqlite__hotcopy(src_subdir, dst_subdir, pool));
          SVN_ERR(svn_io_set_file_read_write(dst_subdir, FALSE, pool));
          SVN_ERR(svn_fs_fs__del_rep_reference(dst_fs, src_youngest, pool));
        }
    }
  if (dst_ffd->format >= SVN_FS_FS__MIN_TXN_CURRENT_FORMAT)
    SVN_ERR(svn_io_dir_file_copy(src_fs->path, dst_fs->path,
                                 PATH_TXN_CURRENT, pool));
  return SVN_NO_ERROR;
}
static svn_error_t * hotcopy_body ( void * baton , apr_pool_t * pool ) { struct hotcopy_body_baton * hbb = baton ; svn_fs_t * src_fs = hbb -> src_fs ; fs_fs_data_t * src_ffd = src_fs -> fsap_data ; svn_fs_t * dst_fs = hbb -> dst_fs ; fs_fs_data_t * dst_ffd = dst_fs -> fsap_data ; svn_boolean_t incremental = hbb -> incremental ; svn_fs_hotcopy_notify_t notify_func = hbb -> notify_func ; void * notify_baton = hbb -> notify_baton ; svn_cancel_func_t cancel_func = hbb -> cancel_func ; void * cancel_baton = hbb -> cancel_baton ; svn_revnum_t src_youngest ; apr_uint64_t src_next_node_id ; apr_uint64_t src_next_copy_id ; svn_revnum_t dst_youngest ; const char * src_revprops_dir ; const char * dst_revprops_dir ; const char * src_revs_dir ; const char * dst_revs_dir ; const char * src_subdir ; const char * dst_subdir ; svn_node_kind_t kind ; if ( src_ffd -> format >= SVN_FS_FS__MIN_CONFIG_FILE ) { svn_error_t * err ; err = svn_io_dir_file_copy ( src_fs -> path , dst_fs -> path , PATH_CONFIG , pool ) ; if ( err ) { if ( APR_STATUS_IS_ENOENT ( err -> apr_err ) ) { const char * src_abspath ; const char * dst_abspath ; const char * config_relpath ; svn_error_t * err2 ; config_relpath = svn_dirent_join ( src_fs -> path , PATH_CONFIG , pool ) ; err2 = svn_dirent_get_absolute ( & src_abspath , src_fs -> path , pool ) ; if ( err2 ) return svn_error_trace ( svn_error_compose_create ( err , err2 ) ) ; err2 = svn_dirent_get_absolute ( & dst_abspath , dst_fs -> path , pool ) ; if ( err2 ) return svn_error_trace ( svn_error_compose_create ( err , err2 ) ) ; src_abspath = svn_dirent_dirname ( src_abspath , pool ) ; dst_abspath = svn_dirent_dirname ( dst_abspath , pool ) ; return svn_error_quick_wrapf ( err , _ ( " " " " " " " " ) , dst_abspath , config_relpath , src_abspath ) ; } else return svn_error_trace ( err ) ; } } if ( cancel_func ) SVN_ERR ( cancel_func ( cancel_baton ) ) ; SVN_ERR ( svn_fs_fs__read_current ( & src_youngest , & src_next_node_id , & src_next_copy_id , src_fs , pool ) ) ; if ( incremental ) { SVN_ERR ( svn_fs_fs__youngest_rev ( & dst_youngest , dst_fs , pool ) ) ; if ( src_youngest < dst_youngest ) return svn_error_createf ( SVN_ERR_UNSUPPORTED_FEATURE , NULL , _ ( " " " " " " ) , dst_youngest , src_youngest ) ; } else dst_youngest = 0 ; src_revs_dir = svn_dirent_join ( src_fs -> path , PATH_REVS_DIR , pool ) ; dst_revs_dir = svn_dirent_join ( dst_fs -> path , PATH_REVS_DIR , pool ) ; src_revprops_dir = svn_dirent_join ( src_fs -> path , PATH_REVPROPS_DIR , pool ) ; dst_revprops_dir = svn_dirent_join ( dst_fs -> path , PATH_REVPROPS_DIR , pool ) ; SVN_ERR ( svn_io_make_dir_recursively ( dst_revs_dir , pool ) ) ; SVN_ERR ( svn_io_make_dir_recursively ( dst_revprops_dir , pool ) ) ; if ( cancel_func ) SVN_ERR ( cancel_func ( cancel_baton ) ) ; if ( src_ffd -> format >= SVN_FS_FS__MIN_NO_GLOBAL_IDS_FORMAT ) { SVN_ERR ( hotcopy_revisions ( src_fs , dst_fs , src_youngest , dst_youngest , incremental , src_revs_dir , dst_revs_dir , src_revprops_dir , dst_revprops_dir , notify_func , notify_baton , cancel_func , cancel_baton , pool ) ) ; SVN_ERR ( svn_fs_fs__write_current ( dst_fs , src_youngest , 0 , 0 , pool ) ) ; } else { SVN_ERR ( hotcopy_revisions_old ( src_fs , dst_fs , src_youngest , src_revs_dir , dst_revs_dir , src_revprops_dir , dst_revprops_dir , notify_func , notify_baton , cancel_func , cancel_baton , pool ) ) ; SVN_ERR ( svn_fs_fs__write_current ( dst_fs , src_youngest , src_next_node_id , src_next_copy_id , pool ) ) ; } dst_subdir = svn_dirent_join ( dst_fs -> path , PATH_LOCKS_DIR , pool ) ; SVN_ERR ( svn_io_remove_dir2 ( dst_subdir , TRUE , cancel_func , cancel_baton , pool ) ) ; src_subdir = svn_dirent_join ( src_fs -> path , PATH_LOCKS_DIR , pool ) ; SVN_ERR ( svn_io_check_path ( src_subdir , & kind , pool ) ) ; if ( kind == svn_node_dir ) SVN_ERR ( svn_io_copy_dir_recursively ( src_subdir , dst_fs -> path , PATH_LOCKS_DIR , TRUE , cancel_func , cancel_baton , pool ) ) ; src_subdir = svn_dirent_join ( src_fs -> path , PATH_NODE_ORIGINS_DIR , pool ) ; SVN_ERR ( svn_io_check_path ( src_subdir , & kind , pool ) ) ; if ( kind == svn_node_dir ) SVN_ERR ( hotcopy_io_copy_dir_recursively ( NULL , src_subdir , dst_fs -> path , PATH_NODE_ORIGINS_DIR , TRUE , cancel_func , cancel_baton , pool ) ) ; if ( dst_ffd -> format >= SVN_FS_FS__MIN_REP_SHARING_FORMAT ) { src_subdir = svn_dirent_join ( src_fs -> path , REP_CACHE_DB_NAME , pool ) ; dst_subdir = svn_dirent_join ( dst_fs -> path , REP_CACHE_DB_NAME , pool ) ; SVN_ERR ( svn_io_check_path ( src_subdir , & kind , pool ) ) ; if ( kind == svn_node_file ) { SVN_ERR ( svn_sqlite__hotcopy ( src_subdir , dst_subdir , pool ) ) ; SVN_ERR ( svn_io_set_file_read_write ( dst_subdir , FALSE , pool ) ) ; SVN_ERR ( svn_fs_fs__del_rep_reference ( dst_fs , src_youngest , pool ) ) ; } } if ( dst_ffd -> format >= SVN_FS_FS__MIN_TXN_CURRENT_FORMAT ) SVN_ERR ( svn_io_dir_file_copy ( src_fs -> path , dst_fs -> path , PATH_TXN_CURRENT , pool ) ) ; return SVN_NO_ERROR ; }
Perform a hotcopy, either normal or incremental.
Perform a hotcopy either normal or incremental .
/* Try to copy the config.
   *
   * ### We try copying the config file before doing anything else,
   * ### because higher layers will abort the hotcopy if we throw
   * ### an error from this function, and that renders the hotcopy
   * ### unusable anyway. */ /* 1.6.0 to 1.6.11 did not copy the configuration file during
               * hotcopy. So if we're hotcopying a repository which has been
               * created as a hotcopy itself, it's possible that fsfs.conf
               * does not exist. Ask the user to re-create it.
               *
               * ### It would be nice to make this a non-fatal error,
               * ### but this function does not get an svn_fs_t object
               * ### so we have no way of just printing a warning via
               * ### the fs->warning() callback. */ /* ### hack: strip off the 'db/' directory from paths so
               * ### they make sense to the user */ /* Find the youngest revision in the source and destination.
   * We only support hotcopies from sources with an equal or greater amount
   * of revisions than the destination.
   * This also catches the case where users accidentally swap the
   * source and destination arguments. */ /* Ensure that the required folders exist in the destination
   * before actually copying the revisions and revprops. */ /* Split the logic for new and old FS formats. The latter is much simpler
   * due to the absense of sharding and packing. However, it requires special
   * care when updating the 'current' file (which contains not just the
   * revision number, but also the next-ID counters). */ /* Replace the locks tree.
   * This is racy in case readers are currently trying to list locks in
   * the destination. However, we need to get rid of stale locks.
   * This is the simplest way of doing this, so we accept this small race. */ /* Now copy the node-origins cache tree. */ /*
   * NB: Data copied below is only read by writers, not readers.
   *     Writers are still locked out at this point.
   */ /* Copy the rep cache and then remove entries for revisions
       * that did not make it into the destination. */ /* The source might have r/o flags set on it - which would be
             carried over to the copy. */ /* Copy the txn-current file. */