load-index-cmd.c revision 362181
1/* load-index-cmd.c -- implements the dump-index sub-command. 2 * 3 * ==================================================================== 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 * ==================================================================== 21 */ 22 23#include "svn_ctype.h" 24#include "svn_dirent_uri.h" 25#include "svn_io.h" 26#include "svn_pools.h" 27 28#include "private/svn_fs_fs_private.h" 29#include "private/svn_sorts_private.h" 30 31#include "svn_private_config.h" 32 33#include "svnfsfs.h" 34 35/* Map svn_fs_fs__p2l_entry_t.type to C string. */ 36static const char *item_type_str[] 37 = {"none", "frep", "drep", "fprop", "dprop", "node", "chgs", "rep"}; 38 39/* Reverse lookup in ITEM_TYPE_STR: Set *TYPE to the index that contains STR. 40 * Return an error for invalid strings. */ 41static svn_error_t * 42str_to_item_type(unsigned *type, 43 const char *str) 44{ 45 unsigned i; 46 for (i = 0; i < sizeof(item_type_str) / sizeof(item_type_str[0]); ++i) 47 if (strcmp(item_type_str[i], str) == 0) 48 { 49 *type = i; 50 return SVN_NO_ERROR; 51 } 52 53 return svn_error_createf(SVN_ERR_BAD_TOKEN, NULL, 54 _("Unknown item type '%s'"), str); 55} 56 57/* Parse the string given as const char * at IDX in TOKENS and return its 58 * value in *VALUE_P. Assume that the string an integer with base RADIX. 59 * Check for index overflows and non-hex chars. 60 */ 61static svn_error_t * 62token_to_i64(apr_int64_t *value_p, 63 apr_array_header_t *tokens, 64 int idx, 65 int radix) 66{ 67 const char *hex; 68 char *end; 69 apr_int64_t value; 70 71 /* Tell the user when there is not enough information. */ 72 SVN_ERR_ASSERT(idx >= 0); 73 if (tokens->nelts <= idx) 74 return svn_error_createf(SVN_ERR_INVALID_INPUT, NULL, 75 _("%i columns needed, %i provided"), 76 idx + 1, tokens->nelts); 77 78 /* hex -> int conversion */ 79 hex = APR_ARRAY_IDX(tokens, idx, const char *); 80 value = apr_strtoi64(hex, &end, radix); 81 82 /* Has the whole token be parsed without error? */ 83 if (errno || *end != '\0') 84 return svn_error_createf(SVN_ERR_INVALID_INPUT, NULL, 85 _("%s is not a value HEX string"), hex); 86 87 *value_p = value; 88 return SVN_NO_ERROR; 89} 90 91/* Parse the P2L entry given as space separated values in LINE and return it 92 * in *ENTRY. Ignore extra columns. Allocate the result in RESULT_POOL and 93 * use SCRATCH_POOL for temporaries. 94 */ 95static svn_error_t * 96parse_index_line(svn_fs_fs__p2l_entry_t **entry, 97 svn_stringbuf_t *line, 98 apr_pool_t *result_pool, 99 apr_pool_t *scratch_pool) 100{ 101 apr_array_header_t *tokens = svn_cstring_split(line->data, " ", TRUE, 102 scratch_pool); 103 svn_fs_fs__p2l_entry_t *result = apr_pcalloc(result_pool, sizeof(*result)); 104 apr_int64_t value; 105 106 /* Parse the hex columns. */ 107 SVN_ERR(token_to_i64(&value, tokens, 0, 16)); 108 result->offset = (apr_off_t)value; 109 SVN_ERR(token_to_i64(&value, tokens, 1, 16)); 110 result->size = (apr_off_t)value; 111 112 /* Parse the rightmost colum that we care of. */ 113 SVN_ERR(token_to_i64(&value, tokens, 4, 10)); 114 result->item.number = (apr_uint64_t)value; 115 116 /* We now know that there were at least 5 columns. 117 * Parse the non-hex columns without index check. */ 118 SVN_ERR(str_to_item_type(&result->type, 119 APR_ARRAY_IDX(tokens, 2, const char *))); 120 SVN_ERR(svn_revnum_parse(&result->item.revision, 121 APR_ARRAY_IDX(tokens, 3, const char *), NULL)); 122 123 *entry = result; 124 return SVN_NO_ERROR; 125} 126 127/* Parse the space separated P2L index table from INPUT, one entry per line. 128 * Rewrite the respective index files in PATH. Allocate from POOL. */ 129static svn_error_t * 130load_index(const char *path, 131 svn_stream_t *input, 132 apr_pool_t *pool) 133{ 134 svn_fs_t *fs; 135 svn_revnum_t revision = SVN_INVALID_REVNUM; 136 apr_array_header_t *entries = apr_array_make(pool, 16, sizeof(void*)); 137 apr_pool_t *iterpool = svn_pool_create(pool); 138 svn_fs_fs__ioctl_load_index_input_t ioctl_input = {0}; 139 140 /* Check repository type and open it. */ 141 SVN_ERR(open_fs(&fs, path, pool)); 142 143 while (TRUE) 144 { 145 svn_stringbuf_t *line; 146 svn_fs_fs__p2l_entry_t *entry; 147 svn_boolean_t eol; 148 149 /* Get the next line from the input and stop if there is none. */ 150 svn_pool_clear(iterpool); 151 SVN_ERR(svn_stream_readline(input, &line, "\n", &eol, iterpool)); 152 if (eol) 153 break; 154 155 /* Skip header line(s). They contain the sub-string [Ss]tart. */ 156 if (strstr(line->data, "tart")) 157 continue; 158 159 /* Ignore empty lines (mostly trailing ones but we don't really care). 160 */ 161 svn_stringbuf_strip_whitespace(line); 162 if (line->len == 0) 163 continue; 164 165 /* Parse the entry and append it to ENTRIES. */ 166 SVN_ERR(parse_index_line(&entry, line, pool, iterpool)); 167 APR_ARRAY_PUSH(entries, svn_fs_fs__p2l_entry_t *) = entry; 168 169 /* There should be at least one item that is not empty. 170 * Get a revision from (probably inside) the respective shard. */ 171 if ( revision == SVN_INVALID_REVNUM 172 && entry->item.revision != SVN_INVALID_REVNUM) 173 revision = entry->item.revision; 174 } 175 176 /* Rewrite the indexes. */ 177 ioctl_input.revision = revision; 178 ioctl_input.entries = entries; 179 SVN_ERR(svn_fs_ioctl(fs, SVN_FS_FS__IOCTL_LOAD_INDEX, &ioctl_input, NULL, 180 NULL, NULL, pool, pool)); 181 svn_pool_destroy(iterpool); 182 183 return SVN_NO_ERROR; 184} 185 186/* This implements `svn_opt_subcommand_t'. */ 187svn_error_t * 188subcommand__load_index(apr_getopt_t *os, void *baton, apr_pool_t *pool) 189{ 190 svnfsfs__opt_state *opt_state = baton; 191 svn_stream_t *input; 192 193 SVN_ERR(svn_stream_for_stdin2(&input, TRUE, pool)); 194 SVN_ERR(load_index(opt_state->repository_path, input, pool)); 195 196 return SVN_NO_ERROR; 197} 198