]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/subversion/subversion/libsvn_fs_base/bdb/nodes-table.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / subversion / subversion / libsvn_fs_base / bdb / nodes-table.c
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 \f
46 /* Opening/creating the `nodes' table.  */
47
48
49 int
50 svn_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 \f
80 /* Choosing node revision ID's.  */
81
82 svn_error_t *
83 svn_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
128 svn_error_t *
129 svn_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 \f
171 /* Removing node revisions.  */
172 svn_error_t *
173 svn_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 \f
192 /* Storing and retrieving NODE-REVISIONs.  */
193
194
195 svn_error_t *
196 svn_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
237 svn_error_t *
238 svn_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 }