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

📄 tree.c

📁 subversion-1.4.3-1.tar.gz 配置svn的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* tree.c : tree-like filesystem, built on DAG filesystem * * ==================================================================== * Copyright (c) 2000-2006 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/. * ==================================================================== *//* The job of this layer is to take a filesystem with lots of node   sharing going on --- the real DAG filesystem as it appears in the   database --- and make it look and act like an ordinary tree   filesystem, with no sharing.   We do just-in-time cloning: you can walk from some unfinished   transaction's root down into directories and files shared with   committed revisions; as soon as you try to change something, the   appropriate nodes get cloned (and parent directory entries updated)   invisibly, behind your back.  Any other references you have to   nodes that have been cloned by other changes, even made by other   processes, are automatically updated to point to the right clones.  */#include <stdlib.h>#include <string.h>#include <assert.h>#include "svn_private_config.h"#include "svn_pools.h"#include "svn_error.h"#include "svn_path.h"#include "svn_md5.h"#include "svn_fs.h"#include "svn_sorts.h"#include "fs.h"#include "err.h"#include "trail.h"#include "node-rev.h"#include "key-gen.h"#include "dag.h"#include "tree.h"#include "lock.h"#include "revs-txns.h"#include "id.h"#include "bdb/txn-table.h"#include "bdb/rev-table.h"#include "bdb/nodes-table.h"#include "bdb/changes-table.h"#include "bdb/copies-table.h"#include "../libsvn_fs/fs-loader.h"/* ### I believe this constant will become internal to reps-strings.c.   ### see the comment in window_consumer() for more information. *//* ### the comment also seems to need tweaking: the log file stuff   ### is no longer an issue... *//* Data written to the filesystem through the svn_fs_apply_textdelta()   interface is cached in memory until the end of the data stream, or   until a size trigger is hit.  Define that trigger here (in bytes).   Setting the value to 0 will result in no filesystem buffering at   all.  The value only really matters when dealing with file contents   bigger than the value itself.  Above that point, large values here   allow the filesystem to buffer more data in memory before flushing   to the database, which increases memory usage but greatly decreases   the amount of disk access (and log-file generation) in database.   Smaller values will limit your overall memory consumption, but can   drastically hurt throughput by necessitating more write operations   to the database (which also generates more log-files).  */#define SVN_FS_WRITE_BUFFER_SIZE          512000/* The maximum number of cache items to maintain in the node cache. */#define SVN_FS_NODE_CACHE_MAX_KEYS        32/* The root structure.  *//* Structure for svn_fs_root_t's node_cache hash values. */struct dag_node_cache_t{  dag_node_t *node; /* NODE to be cached. */  int idx;          /* Index into the keys array for this cache item's key. */  apr_pool_t *pool; /* Pool in which NODE is allocated. */};typedef struct{  /* For revision roots, this is a dag node for the revision's root     directory.  For transaction roots, we open the root directory     afresh every time, since the root may have been cloned, or     the transaction may have disappeared altogether.  */  dag_node_t *root_dir;  /* Cache structures, for mapping const char * PATH to const     struct dag_node_cache_t * structures.     ### Currently this is only used for revision roots.  To be safe     for transaction roots, you must have the guarantee that there is     never more than a single transaction root per Subversion     transaction ever open at a given time -- having two roots open to     the same Subversion transaction would be a request for pain.     Also, you have to ensure that if a 'make_path_mutable()' fails for     any reason, you don't leave cached nodes for the portion of that     function that succeeded.  In other words, this cache must never,     ever, lie. */  apr_hash_t *node_cache;  const char *node_cache_keys[SVN_FS_NODE_CACHE_MAX_KEYS];  int node_cache_idx;} base_root_data_t;static svn_fs_root_t *make_revision_root(svn_fs_t *fs, svn_revnum_t rev,                                         dag_node_t *root_dir,                                         apr_pool_t *pool);static svn_fs_root_t *make_txn_root(svn_fs_t *fs, const char *txn,                                    apr_uint32_t flags, apr_pool_t *pool);/*** Node Caching in the Roots. ***//* Return NODE for PATH from ROOT's node cache, or NULL if the node   isn't cached. */static dag_node_t *dag_node_cache_get(svn_fs_root_t *root,                   const char *path,                   apr_pool_t *pool){  base_root_data_t *brd = root->fsap_data;  struct dag_node_cache_t *cache_item;  /* Assert valid input. */  assert(*path == '/');  /* Only allow revision roots. */  if (root->is_txn_root)    return NULL;  /* Look in the cache for our desired item. */  cache_item = apr_hash_get(brd->node_cache, path, APR_HASH_KEY_STRING);  if (cache_item)    return svn_fs_base__dag_dup(cache_item->node, pool);  return NULL;}/* Add the NODE for PATH to ROOT's node cache.  Callers should *NOT*   call this unless they are adding a currently un-cached item to the   cache, or are replacing the NODE for PATH with a new (different)   one. */static voiddag_node_cache_set(svn_fs_root_t *root,                   const char *path,                   dag_node_t *node){  base_root_data_t *brd = root->fsap_data;  const char *cache_path;  apr_pool_t *cache_pool;  struct dag_node_cache_t *cache_item;  int num_keys = apr_hash_count(brd->node_cache);  /* What?  No POOL passed to this function?     To ensure that our cache values live as long as the svn_fs_root_t     in which they are ultimately stored, and to allow us to free()     them individually without harming the rest, they are each     allocated from a subpool of ROOT's pool.  We'll keep one subpool     around for each cache slot -- as we start expiring stuff     to make room for more entries, we'll re-use the expired thing's     pool. */  /* Assert valid input and state. */  assert(*path == '/');  assert((brd->node_cache_idx <= num_keys)         && (num_keys <= SVN_FS_NODE_CACHE_MAX_KEYS));  /* Only allow revision roots. */  if (root->is_txn_root)    return;  /* Special case: the caller wants us to replace an existing cached     node with a new one.  If the callers aren't mindless, this should     only happen when a node is made mutable under a transaction     root, and that only happens once under that root.  So, we'll be a     little bit sloppy here, and count on callers doing the right     thing. */  cache_item = apr_hash_get(brd->node_cache, path, APR_HASH_KEY_STRING);  if (cache_item)    {      /* ### This section is somehow broken.  I don't know how, but it         ### is.  And I don't want to spend any more time on it.  So,         ### callers, use only revision root and don't try to update         ### an already-cached thing.  -- cmpilato */      abort();#if 0      int cache_index = cache_item->idx;      cache_path = brd->node_cache_keys[cache_index];      cache_pool = cache_item->pool;      cache_item->node = svn_fs_base__dag_dup(node, cache_pool);      /* Now, move the cache key reference to the end of the keys in         the keys array (unless it's already at the end).  ### Yes,         it's a memmove(), but we're not talking about pages of memory         here. */      if (cache_index != (num_keys - 1))        {          int move_num = SVN_FS_NODE_CACHE_MAX_KEYS - cache_index - 1;          memmove(brd->node_cache_keys + cache_index,                  brd->node_cache_keys + cache_index + 1,                  move_num * sizeof(const char *));          cache_index = num_keys - 1;          brd->node_cache_keys[cache_index] = cache_path;        }      /* Advance the cache pointers. */      cache_item->idx = cache_index;      brd->node_cache_idx = (cache_index + 1) % SVN_FS_NODE_CACHE_MAX_KEYS;      return;#endif    }  /* We're adding a new cache item.  First, see if we have room for it     (otherwise, make some room). */  if (apr_hash_count(brd->node_cache) == SVN_FS_NODE_CACHE_MAX_KEYS)    {      /* No room.  Expire the oldest thing. */      cache_path = brd->node_cache_keys[brd->node_cache_idx];      cache_item = apr_hash_get(brd->node_cache, cache_path,                                APR_HASH_KEY_STRING);      apr_hash_set(brd->node_cache, cache_path, APR_HASH_KEY_STRING, NULL);      cache_pool = cache_item->pool;      svn_pool_clear(cache_pool);    }  else    {      cache_pool = svn_pool_create(root->pool);    }  /* Make the cache item, allocated in its own pool. */  cache_item = apr_palloc(cache_pool, sizeof(*cache_item));  cache_item->node = svn_fs_base__dag_dup(node, cache_pool);  cache_item->idx = brd->node_cache_idx;  cache_item->pool = cache_pool;  /* Now add it to the cache. */  cache_path = apr_pstrdup(cache_pool, path);  apr_hash_set(brd->node_cache, cache_path, APR_HASH_KEY_STRING, cache_item);  brd->node_cache_keys[brd->node_cache_idx] = cache_path;  /* Advance the cache pointer. */  brd->node_cache_idx = (brd->node_cache_idx + 1) % SVN_FS_NODE_CACHE_MAX_KEYS;}/* Creating transaction and revision root nodes.  */struct txn_root_args{  svn_fs_root_t **root_p;  svn_fs_txn_t *txn;};static svn_error_t *txn_body_txn_root(void *baton,                  trail_t *trail){  struct txn_root_args *args = baton;  svn_fs_root_t **root_p = args->root_p;  svn_fs_txn_t *txn = args->txn;  svn_fs_t *fs = txn->fs;  const char *svn_txn_id = txn->id;  const svn_fs_id_t *root_id, *base_root_id;  svn_fs_root_t *root;  apr_hash_t *txnprops;  apr_uint32_t flags = 0;  /* Verify that the transaction actually exists.  */  SVN_ERR(svn_fs_base__get_txn_ids(&root_id, &base_root_id, fs,                                   svn_txn_id, trail, trail->pool));  /* Look for special txn props that represent the 'flags' behavior of     the transaction. */  SVN_ERR(svn_fs_base__txn_proplist_in_trail(&txnprops, svn_txn_id, trail));  if (txnprops)    {      if (apr_hash_get(txnprops, SVN_FS_PROP_TXN_CHECK_OOD,                       APR_HASH_KEY_STRING))        flags |= SVN_FS_TXN_CHECK_OOD;      if (apr_hash_get(txnprops, SVN_FS_PROP_TXN_CHECK_LOCKS,                       APR_HASH_KEY_STRING))        flags |= SVN_FS_TXN_CHECK_LOCKS;    }  root = make_txn_root(fs, svn_txn_id, flags, trail->pool);  *root_p = root;  return SVN_NO_ERROR;}svn_error_t *svn_fs_base__txn_root(svn_fs_root_t **root_p,                      svn_fs_txn_t *txn,                      apr_pool_t *pool){  svn_fs_root_t *root;  struct txn_root_args args;  args.root_p = &root;  args.txn = txn;  SVN_ERR(svn_fs_base__retry_txn(txn->fs, txn_body_txn_root, &args, pool));  *root_p = root;  return SVN_NO_ERROR;}struct revision_root_args{  svn_fs_root_t **root_p;  svn_revnum_t rev;};static svn_error_t *txn_body_revision_root(void *baton,                       trail_t *trail){  struct revision_root_args *args = baton;  dag_node_t *root_dir;  svn_fs_root_t *root;  SVN_ERR(svn_fs_base__dag_revision_root(&root_dir, trail->fs, args->rev,                                         trail, trail->pool));  root = make_revision_root(trail->fs, args->rev, root_dir, trail->pool);  *args->root_p = root;  return SVN_NO_ERROR;}svn_error_t *svn_fs_base__revision_root(svn_fs_root_t **root_p,                           svn_fs_t *fs,                           svn_revnum_t rev,                           apr_pool_t *pool){  struct revision_root_args args;  svn_fs_root_t *root;  SVN_ERR(svn_fs_base__check_fs(fs));  args.root_p = &root;  args.rev = rev;  SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_revision_root, &args, pool));  *root_p = root;  return SVN_NO_ERROR;}/* Constructing nice error messages for roots.  *//* Build an SVN_ERR_FS_NOT_FOUND error, with a detailed error text,   for PATH in ROOT. */#define NOT_FOUND(r, p) (                                \  r->is_txn_root ?                                       \    svn_error_createf                                    \      (SVN_ERR_FS_NOT_FOUND, 0,                          \       _("File not found: transaction '%s', path '%s'"), \       r->txn, p)                                        \  :                                                      \    svn_error_createf                                    \      (SVN_ERR_FS_NOT_FOUND, 0,                          \       _("File not found: revision %ld, path '%s'"),     \       r->rev, p)                                        \  )/* Build a detailed `file already exists' message for PATH in ROOT.  */#define ALREADY_EXISTS(r, p) (                                                 \  r->is_txn_root ?                                                             \    svn_error_createf                                                          \      (SVN_ERR_FS_ALREADY_EXISTS, 0,                                           \       _("File already exists: filesystem '%s', transaction '%s', path '%s'"), \       r->fs->path, r->txn, p)                                                 \

⌨️ 快捷键说明

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