FreeBSD/contrib/subversion/subversion/libsvn_fs_x/hotcopy.c
static svn_error_t *
hotcopy_body(void *baton,
             apr_pool_t *scratch_pool)
{
  hotcopy_body_baton_t *hbb = baton;
  svn_fs_t *src_fs = hbb->src_fs;
  svn_fs_t *dst_fs = hbb->dst_fs;
  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;
  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;

  /* 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. */
  SVN_ERR(svn_io_dir_file_copy(src_fs->path, dst_fs->path, PATH_CONFIG,
                               scratch_pool));

  if (cancel_func)
    SVN_ERR(cancel_func(cancel_baton));

  /* 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. */
  SVN_ERR(svn_fs_x__read_current(&src_youngest, src_fs, scratch_pool));
  if (incremental)
    {
      SVN_ERR(svn_fs_x__youngest_rev(&dst_youngest, dst_fs, scratch_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, scratch_pool);
  dst_revs_dir = svn_dirent_join(dst_fs->path, PATH_REVS_DIR, scratch_pool);
  src_revprops_dir = svn_dirent_join(src_fs->path, PATH_REVPROPS_DIR,
                                     scratch_pool);
  dst_revprops_dir = svn_dirent_join(dst_fs->path, PATH_REVPROPS_DIR,
                                     scratch_pool);

  /* Ensure that the required folders exist in the destination
   * before actually copying the revisions and revprops. */
  SVN_ERR(svn_io_make_dir_recursively(dst_revs_dir, scratch_pool));
  SVN_ERR(svn_io_make_dir_recursively(dst_revprops_dir, scratch_pool));

  if (cancel_func)
    SVN_ERR(cancel_func(cancel_baton));

  /* 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). */
  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, scratch_pool));
  SVN_ERR(svn_fs_x__write_current(dst_fs, src_youngest, scratch_pool));

  /* 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. */
  dst_subdir = svn_dirent_join(dst_fs->path, PATH_LOCKS_DIR, scratch_pool);
  SVN_ERR(svn_io_remove_dir2(dst_subdir, TRUE, cancel_func, cancel_baton,
                             scratch_pool));
  src_subdir = svn_dirent_join(src_fs->path, PATH_LOCKS_DIR, scratch_pool);
  SVN_ERR(svn_io_check_path(src_subdir, &kind, scratch_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,
                                        scratch_pool));

  /* Now copy the node-origins cache tree. */
  src_subdir = svn_dirent_join(src_fs->path, PATH_NODE_ORIGINS_DIR,
                               scratch_pool);
  SVN_ERR(svn_io_check_path(src_subdir, &kind, scratch_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,
                                            scratch_pool));

  /*
   * 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
   * younger than the destination's youngest revision. */
  src_subdir = svn_dirent_join(src_fs->path, REP_CACHE_DB_NAME, scratch_pool);
  dst_subdir = svn_dirent_join(dst_fs->path, REP_CACHE_DB_NAME, scratch_pool);
  SVN_ERR(svn_io_check_path(src_subdir, &kind, scratch_pool));
  if (kind == svn_node_file)
    {
      /* Copy the rep cache and then remove entries for revisions
       * that did not make it into the destination. */
      SVN_ERR(svn_sqlite__hotcopy(src_subdir, dst_subdir, scratch_pool));
      SVN_ERR(svn_fs_x__del_rep_reference(dst_fs, src_youngest,
                                          scratch_pool));
    }

  /* Copy the txn-current file. */
  SVN_ERR(svn_io_dir_file_copy(src_fs->path, dst_fs->path,
                                PATH_TXN_CURRENT, scratch_pool));

  /* If a revprop generation file exists in the source filesystem,
   * reset it to zero (since this is on a different path, it will not
   * overlap with data already in cache).  Also, clean up stale files
   * used for the named atomics implementation. */
  SVN_ERR(svn_fs_x__reset_revprop_generation_file(dst_fs, scratch_pool));

  return SVN_NO_ERROR;
}
/* 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 *scratch_pool)
{
  hotcopy_body_baton_t *hbb = baton;
  svn_fs_t *src_fs = hbb->src_fs;
  svn_fs_t *dst_fs = hbb->dst_fs;
  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;
  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;
  SVN_ERR(svn_io_dir_file_copy(src_fs->path, dst_fs->path, PATH_CONFIG,
                               scratch_pool));
  if (cancel_func)
    SVN_ERR(cancel_func(cancel_baton));
  SVN_ERR(svn_fs_x__read_current(&src_youngest, src_fs, scratch_pool));
  if (incremental)
    {
      SVN_ERR(svn_fs_x__youngest_rev(&dst_youngest, dst_fs, scratch_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, scratch_pool);
  dst_revs_dir = svn_dirent_join(dst_fs->path, PATH_REVS_DIR, scratch_pool);
  src_revprops_dir = svn_dirent_join(src_fs->path, PATH_REVPROPS_DIR,
                                     scratch_pool);
  dst_revprops_dir = svn_dirent_join(dst_fs->path, PATH_REVPROPS_DIR,
                                     scratch_pool);
  SVN_ERR(svn_io_make_dir_recursively(dst_revs_dir, scratch_pool));
  SVN_ERR(svn_io_make_dir_recursively(dst_revprops_dir, scratch_pool));
  if (cancel_func)
    SVN_ERR(cancel_func(cancel_baton));
  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, scratch_pool));
  SVN_ERR(svn_fs_x__write_current(dst_fs, src_youngest, scratch_pool));
  dst_subdir = svn_dirent_join(dst_fs->path, PATH_LOCKS_DIR, scratch_pool);
  SVN_ERR(svn_io_remove_dir2(dst_subdir, TRUE, cancel_func, cancel_baton,
                             scratch_pool));
  src_subdir = svn_dirent_join(src_fs->path, PATH_LOCKS_DIR, scratch_pool);
  SVN_ERR(svn_io_check_path(src_subdir, &kind, scratch_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,
                                        scratch_pool));
  src_subdir = svn_dirent_join(src_fs->path, PATH_NODE_ORIGINS_DIR,
                               scratch_pool);
  SVN_ERR(svn_io_check_path(src_subdir, &kind, scratch_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,
                                            scratch_pool));
  src_subdir = svn_dirent_join(src_fs->path, REP_CACHE_DB_NAME, scratch_pool);
  dst_subdir = svn_dirent_join(dst_fs->path, REP_CACHE_DB_NAME, scratch_pool);
  SVN_ERR(svn_io_check_path(src_subdir, &kind, scratch_pool));
  if (kind == svn_node_file)
    {
      SVN_ERR(svn_sqlite__hotcopy(src_subdir, dst_subdir, scratch_pool));
      SVN_ERR(svn_fs_x__del_rep_reference(dst_fs, src_youngest,
                                          scratch_pool));
    }
  SVN_ERR(svn_io_dir_file_copy(src_fs->path, dst_fs->path,
                                PATH_TXN_CURRENT, scratch_pool));
  SVN_ERR(svn_fs_x__reset_revprop_generation_file(dst_fs, scratch_pool));
  return SVN_NO_ERROR;
}
static svn_error_t * hotcopy_body ( void * baton , apr_pool_t * scratch_pool ) { hotcopy_body_baton_t * hbb = baton ; svn_fs_t * src_fs = hbb -> src_fs ; svn_fs_t * dst_fs = hbb -> dst_fs ; 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 ; 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 ; SVN_ERR ( svn_io_dir_file_copy ( src_fs -> path , dst_fs -> path , PATH_CONFIG , scratch_pool ) ) ; if ( cancel_func ) SVN_ERR ( cancel_func ( cancel_baton ) ) ; SVN_ERR ( svn_fs_x__read_current ( & src_youngest , src_fs , scratch_pool ) ) ; if ( incremental ) { SVN_ERR ( svn_fs_x__youngest_rev ( & dst_youngest , dst_fs , scratch_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 , scratch_pool ) ; dst_revs_dir = svn_dirent_join ( dst_fs -> path , PATH_REVS_DIR , scratch_pool ) ; src_revprops_dir = svn_dirent_join ( src_fs -> path , PATH_REVPROPS_DIR , scratch_pool ) ; dst_revprops_dir = svn_dirent_join ( dst_fs -> path , PATH_REVPROPS_DIR , scratch_pool ) ; SVN_ERR ( svn_io_make_dir_recursively ( dst_revs_dir , scratch_pool ) ) ; SVN_ERR ( svn_io_make_dir_recursively ( dst_revprops_dir , scratch_pool ) ) ; if ( cancel_func ) SVN_ERR ( cancel_func ( cancel_baton ) ) ; 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 , scratch_pool ) ) ; SVN_ERR ( svn_fs_x__write_current ( dst_fs , src_youngest , scratch_pool ) ) ; dst_subdir = svn_dirent_join ( dst_fs -> path , PATH_LOCKS_DIR , scratch_pool ) ; SVN_ERR ( svn_io_remove_dir2 ( dst_subdir , TRUE , cancel_func , cancel_baton , scratch_pool ) ) ; src_subdir = svn_dirent_join ( src_fs -> path , PATH_LOCKS_DIR , scratch_pool ) ; SVN_ERR ( svn_io_check_path ( src_subdir , & kind , scratch_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 , scratch_pool ) ) ; src_subdir = svn_dirent_join ( src_fs -> path , PATH_NODE_ORIGINS_DIR , scratch_pool ) ; SVN_ERR ( svn_io_check_path ( src_subdir , & kind , scratch_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 , scratch_pool ) ) ; src_subdir = svn_dirent_join ( src_fs -> path , REP_CACHE_DB_NAME , scratch_pool ) ; dst_subdir = svn_dirent_join ( dst_fs -> path , REP_CACHE_DB_NAME , scratch_pool ) ; SVN_ERR ( svn_io_check_path ( src_subdir , & kind , scratch_pool ) ) ; if ( kind == svn_node_file ) { SVN_ERR ( svn_sqlite__hotcopy ( src_subdir , dst_subdir , scratch_pool ) ) ; SVN_ERR ( svn_fs_x__del_rep_reference ( dst_fs , src_youngest , scratch_pool ) ) ; } SVN_ERR ( svn_io_dir_file_copy ( src_fs -> path , dst_fs -> path , PATH_TXN_CURRENT , scratch_pool ) ) ; SVN_ERR ( svn_fs_x__reset_revprop_generation_file ( dst_fs , scratch_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. */ /* 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
   * younger than the destination's youngest revision. */ /* Copy the rep cache and then remove entries for revisions
       * that did not make it into the destination. */ /* Copy the txn-current file. */ /* If a revprop generation file exists in the source filesystem,
   * reset it to zero (since this is on a different path, it will not
   * overlap with data already in cache).  Also, clean up stale files
   * used for the named atomics implementation. */