⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 revs-txns.c

📁 linux subdivision ying gai ke yi le ba
💻 C
📖 第 1 页 / 共 2 页
字号:
/* revs-txns.c : operations on revision and transactions
 *
 * ====================================================================
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at http://subversion.tigris.org/license-1.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://subversion.tigris.org/.
 * ====================================================================
 */

#include <assert.h>
#include <string.h>

#include <apr_strings.h>
#include <apr_tables.h>
#include <apr_pools.h>

#include "svn_pools.h"
#include "svn_time.h"
#include "svn_fs.h"

#include "fs.h"
#include "dag.h"
#include "err.h"
#include "trail.h"
#include "tree.h"
#include "revs-txns.h"
#include "key-gen.h"
#include "id.h"
#include "bdb/rev-table.h"
#include "bdb/txn-table.h"
#include "bdb/copies-table.h"
#include "bdb/changes-table.h"
#include "../libsvn_fs/fs-loader.h"



/*** Helpers ***/

/* Set *txn_p to a transaction object allocated in TRAIL->pool for the
   transaction in FS whose id is TXN_ID.  If EXPECT_DEAD is set, this
   transaction must be a dead one, else an error is returned.  If
   EXPECT_DEAD is not set, an error is thrown if the transaction is
   *not* dead. */
static svn_error_t *
get_txn (transaction_t **txn_p,
         svn_fs_t *fs,
         const char *txn_id,
         svn_boolean_t expect_dead,
         trail_t *trail)
{
  transaction_t *txn;
  SVN_ERR (svn_fs_bdb__get_txn (&txn, fs, txn_id, trail));
  if (expect_dead && (txn->kind != transaction_kind_dead))
    return svn_error_createf (SVN_ERR_FS_TRANSACTION_NOT_DEAD, 0,
                              "Transaction is not dead: '%s'", txn_id);
  if ((! expect_dead) && (txn->kind == transaction_kind_dead))
    return svn_error_createf (SVN_ERR_FS_TRANSACTION_DEAD, 0,
                              "Transaction is dead: '%s'", txn_id);
  *txn_p = txn;
  return SVN_NO_ERROR;
}


/* This is only for symmetry with the get_txn() helper. */
#define put_txn svn_fs_bdb__put_txn



/*** Revisions ***/

/* Return the committed transaction record *TXN_P and its ID *TXN_ID
   (as long as those parameters aren't NULL) for the revision REV in
   FS as part of TRAIL.  */
static svn_error_t *
get_rev_txn (transaction_t **txn_p,
             const char **txn_id,
             svn_fs_t *fs,
             svn_revnum_t rev,
             trail_t *trail)
{
  revision_t *revision;
  transaction_t *txn;

  SVN_ERR (svn_fs_bdb__get_rev (&revision, fs, rev, trail));
  if (revision->txn_id == NULL)
    return svn_fs_base__err_corrupt_fs_revision (fs, rev);

  SVN_ERR (get_txn (&txn, fs, revision->txn_id, FALSE, trail));
  if (txn->revision != rev)
    return svn_fs_base__err_corrupt_txn (fs, revision->txn_id);

  if (txn_p)
    *txn_p = txn;
  if (txn_id)
    *txn_id = revision->txn_id;
  return SVN_NO_ERROR;
}


svn_error_t *
svn_fs_base__rev_get_root (const svn_fs_id_t **root_id_p,
                           svn_fs_t *fs,
                           svn_revnum_t rev,
                           trail_t *trail)
{
  transaction_t *txn;

  SVN_ERR (get_rev_txn (&txn, NULL, fs, rev, trail));
  if (txn->root_id == NULL)
    return svn_fs_base__err_corrupt_fs_revision (fs, rev);

  *root_id_p = txn->root_id;
  return SVN_NO_ERROR;
}


svn_error_t *
svn_fs_base__rev_get_txn_id (const char **txn_id_p,
                             svn_fs_t *fs,
                             svn_revnum_t rev,
                             trail_t *trail)
{
  revision_t *revision;

  SVN_ERR (svn_fs_bdb__get_rev (&revision, fs, rev, trail));
  if (revision->txn_id == NULL)
    return svn_fs_base__err_corrupt_fs_revision (fs, rev);

  *txn_id_p = revision->txn_id;
  return SVN_NO_ERROR;
}


static svn_error_t *
txn_body_youngest_rev (void *baton,
                       trail_t *trail)
{
  return svn_fs_bdb__youngest_rev (baton, trail->fs, trail);
}


svn_error_t *
svn_fs_base__youngest_rev (svn_revnum_t *youngest_p,
                           svn_fs_t *fs,
                           apr_pool_t *pool)
{
  svn_revnum_t youngest;
  SVN_ERR (svn_fs_base__check_fs (fs));
  SVN_ERR (svn_fs_base__retry_txn (fs, txn_body_youngest_rev, &youngest,
                                   pool));
  *youngest_p = youngest;
  return SVN_NO_ERROR;
}


struct revision_proplist_args {
  apr_hash_t **table_p;
  svn_revnum_t rev;
};


static svn_error_t *
txn_body_revision_proplist (void *baton, trail_t *trail)
{
  struct revision_proplist_args *args = baton;
  transaction_t *txn;

  SVN_ERR (get_rev_txn (&txn, NULL, trail->fs, args->rev, trail));
  *(args->table_p) = txn->proplist;
  return SVN_NO_ERROR;
}


svn_error_t *
svn_fs_base__revision_proplist (apr_hash_t **table_p,
                                svn_fs_t *fs,
                                svn_revnum_t rev,
                                apr_pool_t *pool)
{
  struct revision_proplist_args args;
  apr_hash_t *table;

  SVN_ERR (svn_fs_base__check_fs (fs));

  args.table_p = &table;
  args.rev = rev;
  SVN_ERR (svn_fs_base__retry_txn (fs, txn_body_revision_proplist, &args,
                                   pool));

  *table_p = table ? table : apr_hash_make (pool);
  return SVN_NO_ERROR;
}


svn_error_t *
svn_fs_base__revision_prop (svn_string_t **value_p,
                            svn_fs_t *fs,
                            svn_revnum_t rev,
                            const char *propname,
                            apr_pool_t *pool)
{
  struct revision_proplist_args args;
  apr_hash_t *table;

  SVN_ERR (svn_fs_base__check_fs (fs));

  /* Get the proplist. */
  args.table_p = &table;
  args.rev = rev;
  SVN_ERR (svn_fs_base__retry_txn (fs, txn_body_revision_proplist, &args,
                                   pool));

  /* And then the prop from that list (if there was a list). */
  *value_p = NULL;
  if (table)
    *value_p = apr_hash_get (table, propname, APR_HASH_KEY_STRING);

  return SVN_NO_ERROR;
}


svn_error_t *
svn_fs_base__set_rev_prop (svn_fs_t *fs,
                           svn_revnum_t rev,
                           const char *name,
                           const svn_string_t *value,
                           trail_t *trail)
{
  transaction_t *txn;
  const char *txn_id;

  SVN_ERR (get_rev_txn (&txn, &txn_id, fs, rev, trail));

  /* If there's no proplist, but we're just deleting a property, exit now. */
  if ((! txn->proplist) && (! value))
    return SVN_NO_ERROR;

  /* Now, if there's no proplist, we know we need to make one. */
  if (! txn->proplist)
    txn->proplist = apr_hash_make (trail->pool);

  /* Set the property. */
  apr_hash_set (txn->proplist, name, APR_HASH_KEY_STRING, value);

  /* Overwrite the revision. */
  return put_txn (fs, txn, txn_id, trail);
}


struct change_rev_prop_args {
  svn_revnum_t rev;
  const char *name;
  const svn_string_t *value;
};


static svn_error_t *
txn_body_change_rev_prop (void *baton, trail_t *trail)
{
  struct change_rev_prop_args *args = baton;

  SVN_ERR (svn_fs_base__set_rev_prop (trail->fs, args->rev,
                                      args->name, args->value, trail));

  return SVN_NO_ERROR;
}


svn_error_t *
svn_fs_base__change_rev_prop (svn_fs_t *fs,
                              svn_revnum_t rev,
                              const char *name,
                              const svn_string_t *value,
                              apr_pool_t *pool)
{
  struct change_rev_prop_args args;

  SVN_ERR (svn_fs_base__check_fs (fs));

  args.rev = rev;
  args.name = name;
  args.value = value;
  SVN_ERR (svn_fs_base__retry_txn (fs, txn_body_change_rev_prop, &args, pool));

  return SVN_NO_ERROR;
}



/*** Transactions ***/

svn_error_t *
svn_fs_base__txn_make_committed (svn_fs_t *fs,
                                 const char *txn_name,
                                 svn_revnum_t revision,
                                 trail_t *trail)
{
  transaction_t *txn;

  /* Don't you dare call this with an invalid REVISION. */
  assert (SVN_IS_VALID_REVNUM (revision));

  /* Make sure the TXN is not committed already. */
  SVN_ERR (get_txn (&txn, fs, txn_name, FALSE, trail));
  if (txn->kind != transaction_kind_normal)
    return svn_fs_base__err_txn_not_mutable (fs, txn_name);

  /* Convert TXN to a committed transaction. */
  txn->base_id = NULL;
  txn->revision = revision;
  txn->kind = transaction_kind_committed;
  return put_txn (fs, txn, txn_name, trail);
}


svn_error_t *
svn_fs_base__txn_get_revision (svn_revnum_t *revision,
                               svn_fs_t *fs,
                               const char *txn_name,
                               trail_t *trail)
{
  transaction_t *txn;
  SVN_ERR (get_txn (&txn, fs, txn_name, FALSE, trail));
  *revision = txn->revision;
  return SVN_NO_ERROR;
}


svn_error_t *
svn_fs_base__get_txn_ids (const svn_fs_id_t **root_id_p,
                          const svn_fs_id_t **base_root_id_p,
                          svn_fs_t *fs,
                          const char *txn_name,
                          trail_t *trail)
{
  transaction_t *txn;

  SVN_ERR (get_txn (&txn, fs, txn_name, FALSE, trail));
  if (txn->kind != transaction_kind_normal)
    return svn_fs_base__err_txn_not_mutable (fs, txn_name);

  *root_id_p = txn->root_id;
  *base_root_id_p = txn->base_id;
  return SVN_NO_ERROR;
}


svn_error_t *
svn_fs_base__set_txn_root (svn_fs_t *fs,
                           const char *txn_name,
                           const svn_fs_id_t *new_id,
                           trail_t *trail)
{
  transaction_t *txn;

  SVN_ERR (get_txn (&txn, fs, txn_name, FALSE, trail));
  if (txn->kind != transaction_kind_normal)
    return svn_fs_base__err_txn_not_mutable (fs, txn_name);

  if (! svn_fs_base__id_eq (txn->root_id, new_id))
    {
      txn->root_id = new_id;
      SVN_ERR (put_txn (fs, txn, txn_name, trail));
    }
  return SVN_NO_ERROR;
}


svn_error_t *
svn_fs_base__set_txn_base (svn_fs_t *fs,
                           const char *txn_name,
                           const svn_fs_id_t *new_id,
                           trail_t *trail)
{
  transaction_t *txn;

  SVN_ERR (get_txn (&txn, fs, txn_name, FALSE, trail));
  if (txn->kind != transaction_kind_normal)
    return svn_fs_base__err_txn_not_mutable (fs, txn_name);

  if (! svn_fs_base__id_eq (txn->base_id, new_id))
    {
      txn->base_id = new_id;
      SVN_ERR (put_txn (fs, txn, txn_name, trail));
    }
  return SVN_NO_ERROR;
}


svn_error_t *
svn_fs_base__add_txn_copy (svn_fs_t *fs,
                           const char *txn_name,
                           const char *copy_id,
                           trail_t *trail)
{
  transaction_t *txn;

  /* Get the transaction and ensure its mutability. */
  SVN_ERR (get_txn (&txn, fs, txn_name, FALSE, trail));
  if (txn->kind != transaction_kind_normal)
    return svn_fs_base__err_txn_not_mutable (fs, txn_name);

  /* Allocate a new array if this transaction has no copies. */
  if (! txn->copies)
    txn->copies = apr_array_make (trail->pool, 1, sizeof (copy_id));

  /* Add COPY_ID to the array. */
  (*((const char **)(apr_array_push (txn->copies)))) = copy_id;

  /* Finally, write out the transaction. */
  return put_txn (fs, txn, txn_name, trail);
}



/* Generic transaction operations.  */

struct txn_proplist_args {
  apr_hash_t **table_p;
  const char *id;
  svn_revnum_t rev;
};


static svn_error_t *
txn_body_txn_proplist (void *baton, trail_t *trail)
{
  transaction_t *txn;
  struct txn_proplist_args *args = baton;

  SVN_ERR (get_txn (&txn, trail->fs, args->id, FALSE, trail));
  if (txn->kind != transaction_kind_normal)
    return svn_fs_base__err_txn_not_mutable (trail->fs, args->id);

  *(args->table_p) = txn->proplist;
  return SVN_NO_ERROR;
}


svn_error_t *
svn_fs_base__txn_proplist (apr_hash_t **table_p,
                           svn_fs_txn_t *txn,
                           apr_pool_t *pool)
{
  struct txn_proplist_args args;
  apr_hash_t *table;
  svn_fs_t *fs = txn->fs;

  SVN_ERR (svn_fs_base__check_fs (fs));

  args.table_p = &table;
  args.id = txn->id;
  SVN_ERR (svn_fs_base__retry_txn (fs, txn_body_txn_proplist, &args, pool));

  *table_p = table ? table : apr_hash_make (pool);
  return SVN_NO_ERROR;
}


svn_error_t *
svn_fs_base__txn_prop (svn_string_t **value_p,
                       svn_fs_txn_t *txn,
                       const char *propname,
                       apr_pool_t *pool)
{
  struct txn_proplist_args args;
  apr_hash_t *table;
  svn_fs_t *fs = txn->fs;

  SVN_ERR (svn_fs_base__check_fs (fs));

  /* Get the proplist. */
  args.table_p = &table;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -