1/* nodes-table.c : working with the `nodes' table 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 <string.h> 24#include <assert.h> 25 26#include "bdb_compat.h" 27 28#include "svn_fs.h" 29#include "private/svn_skel.h" 30 31#include "../fs.h" 32#include "../err.h" 33#include "dbt.h" 34#include "../util/fs_skels.h" 35#include "../trail.h" 36#include "../key-gen.h" 37#include "../id.h" 38#include "../../libsvn_fs/fs-loader.h" 39#include "bdb-err.h" 40#include "nodes-table.h" 41 42#include "svn_private_config.h" 43 44 45 46/* Opening/creating the `nodes' table. */ 47 48 49int 50svn_fs_bdb__open_nodes_table(DB **nodes_p, 51 DB_ENV *env, 52 svn_boolean_t create) 53{ 54 const u_int32_t open_flags = (create ? (DB_CREATE | DB_EXCL) : 0); 55 DB *nodes; 56 57 BDB_ERR(svn_fs_bdb__check_version()); 58 BDB_ERR(db_create(&nodes, env, 0)); 59 BDB_ERR((nodes->open)(SVN_BDB_OPEN_PARAMS(nodes, NULL), 60 "nodes", 0, DB_BTREE, 61 open_flags, 0666)); 62 63 /* Create the `next-key' table entry (use '1' because '0' is 64 reserved for the root directory to use). */ 65 if (create) 66 { 67 DBT key, value; 68 69 BDB_ERR(nodes->put(nodes, 0, 70 svn_fs_base__str_to_dbt(&key, NEXT_KEY_KEY), 71 svn_fs_base__str_to_dbt(&value, "1"), 0)); 72 } 73 74 *nodes_p = nodes; 75 return 0; 76} 77 78 79 80/* Choosing node revision ID's. */ 81 82svn_error_t * 83svn_fs_bdb__new_node_id(svn_fs_id_t **id_p, 84 svn_fs_t *fs, 85 const char *copy_id, 86 const char *txn_id, 87 trail_t *trail, 88 apr_pool_t *pool) 89{ 90 base_fs_data_t *bfd = fs->fsap_data; 91 DBT query, result; 92 apr_size_t len; 93 char next_key[MAX_KEY_SIZE]; 94 int db_err; 95 const char *next_node_id; 96 97 SVN_ERR_ASSERT(txn_id); 98 99 /* Get the current value associated with the `next-key' key in the table. */ 100 svn_fs_base__str_to_dbt(&query, NEXT_KEY_KEY); 101 svn_fs_base__trail_debug(trail, "nodes", "get"); 102 SVN_ERR(BDB_WRAP(fs, N_("allocating new node ID (getting 'next-key')"), 103 bfd->nodes->get(bfd->nodes, trail->db_txn, 104 &query, 105 svn_fs_base__result_dbt(&result), 106 0))); 107 svn_fs_base__track_dbt(&result, pool); 108 109 /* Squirrel away our next node id value. */ 110 next_node_id = apr_pstrmemdup(pool, result.data, result.size); 111 112 /* Bump to future key. */ 113 len = result.size; 114 svn_fs_base__next_key(result.data, &len, next_key); 115 svn_fs_base__trail_debug(trail, "nodes", "put"); 116 db_err = bfd->nodes->put(bfd->nodes, trail->db_txn, 117 svn_fs_base__str_to_dbt(&query, NEXT_KEY_KEY), 118 svn_fs_base__str_to_dbt(&result, next_key), 119 0); 120 SVN_ERR(BDB_WRAP(fs, N_("bumping next node ID key"), db_err)); 121 122 /* Create and return the new node id. */ 123 *id_p = svn_fs_base__id_create(next_node_id, copy_id, txn_id, pool); 124 return SVN_NO_ERROR; 125} 126 127 128svn_error_t * 129svn_fs_bdb__new_successor_id(svn_fs_id_t **successor_p, 130 svn_fs_t *fs, 131 const svn_fs_id_t *id, 132 const char *copy_id, 133 const char *txn_id, 134 trail_t *trail, 135 apr_pool_t *pool) 136{ 137 svn_fs_id_t *new_id; 138 svn_error_t *err; 139 140 SVN_ERR_ASSERT(txn_id); 141 142 /* Create and return the new successor ID. */ 143 new_id = svn_fs_base__id_create(svn_fs_base__id_node_id(id), 144 copy_id ? copy_id 145 : svn_fs_base__id_copy_id(id), 146 txn_id, pool); 147 148 /* Now, make sure this NEW_ID doesn't already exist in FS. */ 149 err = svn_fs_bdb__get_node_revision(NULL, fs, new_id, trail, trail->pool); 150 if ((! err) || (err->apr_err != SVN_ERR_FS_ID_NOT_FOUND)) 151 { 152 svn_string_t *id_str = svn_fs_base__id_unparse(id, pool); 153 svn_string_t *new_id_str = svn_fs_base__id_unparse(new_id, pool); 154 return svn_error_createf 155 (SVN_ERR_FS_ALREADY_EXISTS, err, 156 _("Successor id '%s' (for '%s') already exists in filesystem '%s'"), 157 new_id_str->data, id_str->data, fs->path); 158 } 159 160 /* err is SVN_ERR_FS_ID_NOT_FOUND, meaning the ID is available. But 161 we don't want this error. */ 162 svn_error_clear(err); 163 164 /* Return the new node revision ID. */ 165 *successor_p = new_id; 166 return SVN_NO_ERROR; 167} 168 169 170 171/* Removing node revisions. */ 172svn_error_t * 173svn_fs_bdb__delete_nodes_entry(svn_fs_t *fs, 174 const svn_fs_id_t *id, 175 trail_t *trail, 176 apr_pool_t *pool) 177{ 178 base_fs_data_t *bfd = fs->fsap_data; 179 DBT key; 180 181 svn_fs_base__trail_debug(trail, "nodes", "del"); 182 return BDB_WRAP(fs, N_("deleting entry from 'nodes' table"), 183 bfd->nodes->del(bfd->nodes, 184 trail->db_txn, 185 svn_fs_base__id_to_dbt(&key, id, pool), 186 0)); 187} 188 189 190 191 192/* Storing and retrieving NODE-REVISIONs. */ 193 194 195svn_error_t * 196svn_fs_bdb__get_node_revision(node_revision_t **noderev_p, 197 svn_fs_t *fs, 198 const svn_fs_id_t *id, 199 trail_t *trail, 200 apr_pool_t *pool) 201{ 202 base_fs_data_t *bfd = fs->fsap_data; 203 node_revision_t *noderev; 204 svn_skel_t *skel; 205 int db_err; 206 DBT key, value; 207 208 svn_fs_base__trail_debug(trail, "nodes", "get"); 209 db_err = bfd->nodes->get(bfd->nodes, trail->db_txn, 210 svn_fs_base__id_to_dbt(&key, id, pool), 211 svn_fs_base__result_dbt(&value), 212 0); 213 svn_fs_base__track_dbt(&value, pool); 214 215 /* If there's no such node, return an appropriately specific error. */ 216 if (db_err == DB_NOTFOUND) 217 return svn_fs_base__err_dangling_id(fs, id); 218 219 /* Handle any other error conditions. */ 220 SVN_ERR(BDB_WRAP(fs, N_("reading node revision"), db_err)); 221 222 /* If our caller doesn't really care about the return value here, 223 just return successfully. */ 224 if (! noderev_p) 225 return SVN_NO_ERROR; 226 227 /* Parse and the NODE-REVISION skel. */ 228 skel = svn_skel__parse(value.data, value.size, pool); 229 230 /* Convert to a native FS type. */ 231 SVN_ERR(svn_fs_base__parse_node_revision_skel(&noderev, skel, pool)); 232 *noderev_p = noderev; 233 return SVN_NO_ERROR; 234} 235 236 237svn_error_t * 238svn_fs_bdb__put_node_revision(svn_fs_t *fs, 239 const svn_fs_id_t *id, 240 node_revision_t *noderev, 241 trail_t *trail, 242 apr_pool_t *pool) 243{ 244 base_fs_data_t *bfd = fs->fsap_data; 245 DB_TXN *db_txn = trail->db_txn; 246 DBT key, value; 247 svn_skel_t *skel; 248 249 /* Convert from native type into skel */ 250 SVN_ERR(svn_fs_base__unparse_node_revision_skel(&skel, noderev, 251 bfd->format, pool)); 252 svn_fs_base__trail_debug(trail, "nodes", "put"); 253 return BDB_WRAP(fs, N_("storing node revision"), 254 bfd->nodes->put(bfd->nodes, db_txn, 255 svn_fs_base__id_to_dbt(&key, id, pool), 256 svn_fs_base__skel_to_dbt(&value, skel, 257 pool), 258 0)); 259} 260