Follow-up to r29036: Now that the "mergeinfo" transaction file is no
[svn.git] / tools / server-side / svn-populate-node-origins-index.c
blobc972a508ed98ab27bef14e08719e9888fee5baf3
1 /*
2 * svn-populate-node-origins-index.c : Populate the repository's node
3 * origins index.
5 * ====================================================================
6 * Copyright (c) 2007 CollabNet. All rights reserved.
8 * This software is licensed as described in the file COPYING, which
9 * you should have received as part of this distribution. The terms
10 * are also available at http://subversion.tigris.org/license-1.html.
11 * If newer versions of this license are posted there, you may use a
12 * newer version instead, at your option.
14 * This software consists of voluntary contributions made by many
15 * individuals. For exact contribution history, see the revision
16 * history and logs, available at http://subversion.tigris.org/.
17 * ====================================================================
20 #include "svn_pools.h"
21 #include "svn_error.h"
22 #include "svn_cmdline.h"
23 #include "svn_path.h"
24 #include "svn_repos.h"
25 #include "svn_fs.h"
27 /* Used to terminate lines in large multi-line string literals. */
28 #define NL APR_EOL_STR
30 static const char *usage_summary =
31 "Crawl the Subversion repository located at REPOS-PATH in an attempt to" NL
32 "populate that repository's index of node origins. " NL
33 "" NL
34 "The node origins index is new as of Subversion 1.5, and behaves as a" NL
35 "cache to vastly speed up certain history-querying operations. For" NL
36 "compatibility with repositories created with pre-1.5 versions of" NL
37 "Subversion, Subversion will gracefully handle cache misses by doing a" NL
38 "brute-force calculation of the query answer and lazily populating the" NL
39 "index with answers it calculates. Unfortunately, calculating that" NL
40 "information using the brute-force method (instead of having the" NL
41 "information appear in the index organically) can be very costly." NL
42 "" NL
43 "This tool triggers the lazy index population logic built into" NL
44 "Subversion in a fashion far more efficient than is likely to happen" NL
45 "during typical repository usage. It can be run while the repository" NL
46 "is online, too, without interrupting normal Subversion activities." NL;
48 /* Print a usage message for this program (PROGNAME), possibly with an
49 error message ERR_MSG, if not NULL. */
50 static void
51 usage_maybe_with_err(const char *progname, const char *err_msg)
53 FILE *out;
55 out = err_msg ? stderr : stdout;
56 fprintf(out, "Usage: %s REPOS-PATH\n\n%s", progname, usage_summary);
57 if (err_msg)
58 fprintf(out, "\nERROR: %s\n", err_msg);
61 /* Build the node-origins index any newly added items introduced in
62 REVISION in FS. Set *COUNT to the number of new items found. */
63 static svn_error_t *
64 index_revision_adds(int *count, svn_fs_t *fs,
65 svn_revnum_t revision, apr_pool_t *pool)
67 svn_fs_root_t *root;
68 apr_hash_t *changes;
69 apr_hash_index_t *hi;
70 apr_pool_t *subpool;
72 *count = 0;
73 SVN_ERR(svn_fs_revision_root(&root, fs, revision, pool));
74 SVN_ERR(svn_fs_paths_changed(&changes, root, pool));
76 /* No paths changed in this revision? Nothing to do. */
77 if (apr_hash_count(changes) == 0)
78 return SVN_NO_ERROR;
80 subpool = svn_pool_create(pool);
81 for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
83 const void *path;
84 void *val;
85 svn_fs_path_change_t *change;
87 svn_pool_clear(subpool);
88 apr_hash_this(hi, &path, NULL, &val);
89 change = val;
90 if ((change->change_kind == svn_fs_path_change_add)
91 || (change->change_kind == svn_fs_path_change_replace))
93 const char *copyfrom_path;
94 svn_revnum_t copyfrom_rev;
96 SVN_ERR(svn_fs_copied_from(&copyfrom_rev, &copyfrom_path,
97 root, path, subpool));
98 if (! (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_rev)))
100 svn_revnum_t origin;
101 SVN_ERR(svn_fs_node_origin_rev(&origin, root, path, subpool));
102 (*count)++;
106 svn_pool_destroy(subpool);
108 return SVN_NO_ERROR;
111 /* Build the node-origins index for the repository located at REPOS_PATH. */
112 static svn_error_t *
113 build_index(const char *repos_path, apr_pool_t *pool)
115 svn_repos_t *repos;
116 svn_fs_t *fs;
117 svn_revnum_t youngest_rev;
118 int i, slotsize;
119 const char *progress_fmt;
120 apr_pool_t *subpool;
122 /* Open the repository. */
123 SVN_ERR(svn_repos_open(&repos, repos_path, pool));
125 /* Get a filesystem object. */
126 fs = svn_repos_fs(repos);
128 /* Fetch the youngest revision of the repository. */
129 SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, pool));
130 slotsize = strlen(apr_ltoa(pool, youngest_rev));
131 progress_fmt = apr_psprintf(pool,
132 "[%%%dd/%%%dd] Found %%d new lines of history."
133 "\n", slotsize, slotsize);
135 /* Now, iterate over all the revisions, calling index_revision_adds(). */
136 subpool = svn_pool_create(pool);
137 for (i = 0; i < youngest_rev; i++)
139 int count;
140 svn_pool_clear(subpool);
141 SVN_ERR(index_revision_adds(&count, fs, i + 1, subpool));
142 printf(progress_fmt, i + 1, youngest_rev, count);
144 svn_pool_destroy(subpool);
146 return SVN_NO_ERROR;
151 main(int argc, const char **argv)
153 apr_pool_t *pool;
154 svn_error_t *err = SVN_NO_ERROR;
155 const char *repos_path;
157 /* Initialize the app. Send all error messages to 'stderr'. */
158 if (svn_cmdline_init(argv[0], stderr) == EXIT_FAILURE)
159 return EXIT_FAILURE;
161 pool = svn_pool_create(NULL);
163 if (argc <= 1)
165 usage_maybe_with_err(argv[0], "Not enough arguments.");
166 goto cleanup;
169 /* Convert argv[1] into a UTF8, internal-format, canonicalized path. */
170 if ((err = svn_utf_cstring_to_utf8(&repos_path, argv[1], pool)))
171 goto cleanup;
172 repos_path = svn_path_internal_style(repos_path, pool);
173 repos_path = svn_path_canonicalize(repos_path, pool);
175 if ((err = build_index(repos_path, pool)))
176 goto cleanup;
178 cleanup:
179 svn_pool_destroy(pool);
181 if (err)
183 svn_handle_error2(err, stderr, FALSE,
184 "svn-populate-node-origins-index: ");
185 return EXIT_FAILURE;
187 return EXIT_SUCCESS;