1251881Speter/* nodes-table.c : working with the `nodes' table
2251881Speter *
3251881Speter * ====================================================================
4251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
5251881Speter *    or more contributor license agreements.  See the NOTICE file
6251881Speter *    distributed with this work for additional information
7251881Speter *    regarding copyright ownership.  The ASF licenses this file
8251881Speter *    to you under the Apache License, Version 2.0 (the
9251881Speter *    "License"); you may not use this file except in compliance
10251881Speter *    with the License.  You may obtain a copy of the License at
11251881Speter *
12251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
13251881Speter *
14251881Speter *    Unless required by applicable law or agreed to in writing,
15251881Speter *    software distributed under the License is distributed on an
16251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17251881Speter *    KIND, either express or implied.  See the License for the
18251881Speter *    specific language governing permissions and limitations
19251881Speter *    under the License.
20251881Speter * ====================================================================
21251881Speter */
22251881Speter
23251881Speter#include <string.h>
24251881Speter#include <assert.h>
25251881Speter
26251881Speter#include "bdb_compat.h"
27251881Speter
28251881Speter#include "svn_fs.h"
29251881Speter#include "private/svn_skel.h"
30251881Speter
31251881Speter#include "../fs.h"
32251881Speter#include "../err.h"
33251881Speter#include "dbt.h"
34251881Speter#include "../util/fs_skels.h"
35251881Speter#include "../trail.h"
36251881Speter#include "../key-gen.h"
37251881Speter#include "../id.h"
38251881Speter#include "../../libsvn_fs/fs-loader.h"
39251881Speter#include "bdb-err.h"
40251881Speter#include "nodes-table.h"
41251881Speter
42251881Speter#include "svn_private_config.h"
43251881Speter
44251881Speter
45251881Speter
46251881Speter/* Opening/creating the `nodes' table.  */
47251881Speter
48251881Speter
49251881Speterint
50251881Spetersvn_fs_bdb__open_nodes_table(DB **nodes_p,
51251881Speter                             DB_ENV *env,
52251881Speter                             svn_boolean_t create)
53251881Speter{
54251881Speter  const u_int32_t open_flags = (create ? (DB_CREATE | DB_EXCL) : 0);
55251881Speter  DB *nodes;
56251881Speter
57251881Speter  BDB_ERR(svn_fs_bdb__check_version());
58251881Speter  BDB_ERR(db_create(&nodes, env, 0));
59251881Speter  BDB_ERR((nodes->open)(SVN_BDB_OPEN_PARAMS(nodes, NULL),
60251881Speter                        "nodes", 0, DB_BTREE,
61251881Speter                        open_flags, 0666));
62251881Speter
63251881Speter  /* Create the `next-key' table entry (use '1' because '0' is
64251881Speter     reserved for the root directory to use). */
65251881Speter  if (create)
66251881Speter  {
67251881Speter    DBT key, value;
68251881Speter
69251881Speter    BDB_ERR(nodes->put(nodes, 0,
70251881Speter                       svn_fs_base__str_to_dbt(&key, NEXT_KEY_KEY),
71251881Speter                       svn_fs_base__str_to_dbt(&value, "1"), 0));
72251881Speter  }
73251881Speter
74251881Speter  *nodes_p = nodes;
75251881Speter  return 0;
76251881Speter}
77251881Speter
78251881Speter
79251881Speter
80251881Speter/* Choosing node revision ID's.  */
81251881Speter
82251881Spetersvn_error_t *
83251881Spetersvn_fs_bdb__new_node_id(svn_fs_id_t **id_p,
84251881Speter                        svn_fs_t *fs,
85251881Speter                        const char *copy_id,
86251881Speter                        const char *txn_id,
87251881Speter                        trail_t *trail,
88251881Speter                        apr_pool_t *pool)
89251881Speter{
90251881Speter  base_fs_data_t *bfd = fs->fsap_data;
91251881Speter  DBT query, result;
92251881Speter  apr_size_t len;
93251881Speter  char next_key[MAX_KEY_SIZE];
94251881Speter  int db_err;
95251881Speter  const char *next_node_id;
96251881Speter
97251881Speter  SVN_ERR_ASSERT(txn_id);
98251881Speter
99251881Speter  /* Get the current value associated with the `next-key' key in the table.  */
100251881Speter  svn_fs_base__str_to_dbt(&query, NEXT_KEY_KEY);
101251881Speter  svn_fs_base__trail_debug(trail, "nodes", "get");
102251881Speter  SVN_ERR(BDB_WRAP(fs, N_("allocating new node ID (getting 'next-key')"),
103251881Speter                   bfd->nodes->get(bfd->nodes, trail->db_txn,
104251881Speter                                   &query,
105251881Speter                                   svn_fs_base__result_dbt(&result),
106251881Speter                                   0)));
107251881Speter  svn_fs_base__track_dbt(&result, pool);
108251881Speter
109251881Speter  /* Squirrel away our next node id value. */
110251881Speter  next_node_id = apr_pstrmemdup(pool, result.data, result.size);
111251881Speter
112251881Speter  /* Bump to future key. */
113251881Speter  len = result.size;
114251881Speter  svn_fs_base__next_key(result.data, &len, next_key);
115251881Speter  svn_fs_base__trail_debug(trail, "nodes", "put");
116251881Speter  db_err = bfd->nodes->put(bfd->nodes, trail->db_txn,
117251881Speter                           svn_fs_base__str_to_dbt(&query, NEXT_KEY_KEY),
118251881Speter                           svn_fs_base__str_to_dbt(&result, next_key),
119251881Speter                           0);
120251881Speter  SVN_ERR(BDB_WRAP(fs, N_("bumping next node ID key"), db_err));
121251881Speter
122251881Speter  /* Create and return the new node id. */
123251881Speter  *id_p = svn_fs_base__id_create(next_node_id, copy_id, txn_id, pool);
124251881Speter  return SVN_NO_ERROR;
125251881Speter}
126251881Speter
127251881Speter
128251881Spetersvn_error_t *
129251881Spetersvn_fs_bdb__new_successor_id(svn_fs_id_t **successor_p,
130251881Speter                             svn_fs_t *fs,
131251881Speter                             const svn_fs_id_t *id,
132251881Speter                             const char *copy_id,
133251881Speter                             const char *txn_id,
134251881Speter                             trail_t *trail,
135251881Speter                             apr_pool_t *pool)
136251881Speter{
137251881Speter  svn_fs_id_t *new_id;
138251881Speter  svn_error_t *err;
139251881Speter
140251881Speter  SVN_ERR_ASSERT(txn_id);
141251881Speter
142251881Speter  /* Create and return the new successor ID.  */
143251881Speter  new_id = svn_fs_base__id_create(svn_fs_base__id_node_id(id),
144251881Speter                                  copy_id ? copy_id
145251881Speter                                  : svn_fs_base__id_copy_id(id),
146251881Speter                                  txn_id, pool);
147251881Speter
148251881Speter  /* Now, make sure this NEW_ID doesn't already exist in FS. */
149251881Speter  err = svn_fs_bdb__get_node_revision(NULL, fs, new_id, trail, trail->pool);
150251881Speter  if ((! err) || (err->apr_err != SVN_ERR_FS_ID_NOT_FOUND))
151251881Speter    {
152251881Speter      svn_string_t *id_str = svn_fs_base__id_unparse(id, pool);
153251881Speter      svn_string_t *new_id_str = svn_fs_base__id_unparse(new_id, pool);
154251881Speter      return svn_error_createf
155251881Speter        (SVN_ERR_FS_ALREADY_EXISTS, err,
156251881Speter         _("Successor id '%s' (for '%s') already exists in filesystem '%s'"),
157251881Speter         new_id_str->data, id_str->data, fs->path);
158251881Speter    }
159251881Speter
160251881Speter  /* err is SVN_ERR_FS_ID_NOT_FOUND, meaning the ID is available. But
161251881Speter     we don't want this error. */
162251881Speter  svn_error_clear(err);
163251881Speter
164251881Speter  /* Return the new node revision ID. */
165251881Speter  *successor_p = new_id;
166251881Speter  return SVN_NO_ERROR;
167251881Speter}
168251881Speter
169251881Speter
170251881Speter
171251881Speter/* Removing node revisions.  */
172251881Spetersvn_error_t *
173251881Spetersvn_fs_bdb__delete_nodes_entry(svn_fs_t *fs,
174251881Speter                               const svn_fs_id_t *id,
175251881Speter                               trail_t *trail,
176251881Speter                               apr_pool_t *pool)
177251881Speter{
178251881Speter  base_fs_data_t *bfd = fs->fsap_data;
179251881Speter  DBT key;
180251881Speter
181251881Speter  svn_fs_base__trail_debug(trail, "nodes", "del");
182251881Speter  return BDB_WRAP(fs, N_("deleting entry from 'nodes' table"),
183251881Speter                  bfd->nodes->del(bfd->nodes,
184251881Speter                                  trail->db_txn,
185251881Speter                                  svn_fs_base__id_to_dbt(&key, id, pool),
186251881Speter                                  0));
187251881Speter}
188251881Speter
189251881Speter
190251881Speter
191251881Speter
192251881Speter/* Storing and retrieving NODE-REVISIONs.  */
193251881Speter
194251881Speter
195251881Spetersvn_error_t *
196251881Spetersvn_fs_bdb__get_node_revision(node_revision_t **noderev_p,
197251881Speter                              svn_fs_t *fs,
198251881Speter                              const svn_fs_id_t *id,
199251881Speter                              trail_t *trail,
200251881Speter                              apr_pool_t *pool)
201251881Speter{
202251881Speter  base_fs_data_t *bfd = fs->fsap_data;
203251881Speter  node_revision_t *noderev;
204251881Speter  svn_skel_t *skel;
205251881Speter  int db_err;
206251881Speter  DBT key, value;
207251881Speter
208251881Speter  svn_fs_base__trail_debug(trail, "nodes", "get");
209251881Speter  db_err = bfd->nodes->get(bfd->nodes, trail->db_txn,
210251881Speter                           svn_fs_base__id_to_dbt(&key, id, pool),
211251881Speter                           svn_fs_base__result_dbt(&value),
212251881Speter                           0);
213251881Speter  svn_fs_base__track_dbt(&value, pool);
214251881Speter
215251881Speter  /* If there's no such node, return an appropriately specific error.  */
216251881Speter  if (db_err == DB_NOTFOUND)
217251881Speter    return svn_fs_base__err_dangling_id(fs, id);
218251881Speter
219251881Speter  /* Handle any other error conditions.  */
220251881Speter  SVN_ERR(BDB_WRAP(fs, N_("reading node revision"), db_err));
221251881Speter
222251881Speter  /* If our caller doesn't really care about the return value here,
223251881Speter     just return successfully. */
224251881Speter  if (! noderev_p)
225251881Speter    return SVN_NO_ERROR;
226251881Speter
227251881Speter  /* Parse and the NODE-REVISION skel.  */
228251881Speter  skel = svn_skel__parse(value.data, value.size, pool);
229251881Speter
230251881Speter  /* Convert to a native FS type. */
231251881Speter  SVN_ERR(svn_fs_base__parse_node_revision_skel(&noderev, skel, pool));
232251881Speter  *noderev_p = noderev;
233251881Speter  return SVN_NO_ERROR;
234251881Speter}
235251881Speter
236251881Speter
237251881Spetersvn_error_t *
238251881Spetersvn_fs_bdb__put_node_revision(svn_fs_t *fs,
239251881Speter                              const svn_fs_id_t *id,
240251881Speter                              node_revision_t *noderev,
241251881Speter                              trail_t *trail,
242251881Speter                              apr_pool_t *pool)
243251881Speter{
244251881Speter  base_fs_data_t *bfd = fs->fsap_data;
245251881Speter  DB_TXN *db_txn = trail->db_txn;
246251881Speter  DBT key, value;
247251881Speter  svn_skel_t *skel;
248251881Speter
249251881Speter  /* Convert from native type into skel */
250251881Speter  SVN_ERR(svn_fs_base__unparse_node_revision_skel(&skel, noderev,
251251881Speter                                                  bfd->format, pool));
252251881Speter  svn_fs_base__trail_debug(trail, "nodes", "put");
253251881Speter  return BDB_WRAP(fs, N_("storing node revision"),
254251881Speter                  bfd->nodes->put(bfd->nodes, db_txn,
255251881Speter                                  svn_fs_base__id_to_dbt(&key, id, pool),
256251881Speter                                  svn_fs_base__skel_to_dbt(&value, skel,
257251881Speter                                                           pool),
258251881Speter                                  0));
259251881Speter}
260