1
/* txn-table.c : operations on the `transactions' table
3
* ====================================================================
4
* Copyright (c) 2000-2004 CollabNet. All rights reserved.
6
* This software is licensed as described in the file COPYING, which
7
* you should have received as part of this distribution. The terms
8
* are also available at http://subversion.tigris.org/license-1.html.
9
* If newer versions of this license are posted there, you may use a
10
* newer version instead, at your option.
12
* This software consists of voluntary contributions made by many
13
* individuals. For exact contribution history, see the revision
14
* history and logs, available at http://subversion.tigris.org/.
15
* ====================================================================
20
#include "bdb_compat.h"
22
#include "svn_pools.h"
26
#include "../key-gen.h"
27
#include "../util/skel.h"
28
#include "../util/fs_skels.h"
30
#include "../../libsvn_fs/fs-loader.h"
32
#include "txn-table.h"
34
#include "svn_private_config.h"
38
is_committed (transaction_t *txn)
40
return (txn->kind == transaction_kind_committed) ? TRUE : FALSE;
45
svn_fs_bdb__open_transactions_table (DB **transactions_p,
49
const u_int32_t open_flags = (create ? (DB_CREATE | DB_EXCL) : 0);
52
BDB_ERR (svn_fs_bdb__check_version());
53
BDB_ERR (db_create (&txns, env, 0));
54
BDB_ERR (txns->open (SVN_BDB_OPEN_PARAMS(txns, NULL),
55
"transactions", 0, DB_BTREE,
56
open_flags | SVN_BDB_AUTO_COMMIT,
59
/* Create the `next-id' table entry. */
64
BDB_ERR (txns->put (txns, 0,
65
svn_fs_base__str_to_dbt (&key, NEXT_KEY_KEY),
66
svn_fs_base__str_to_dbt (&value, "0"),
67
SVN_BDB_AUTO_COMMIT));
70
*transactions_p = txns;
76
svn_fs_bdb__put_txn (svn_fs_t *fs,
77
const transaction_t *txn,
82
base_fs_data_t *bfd = fs->fsap_data;
86
/* Convert native type to skel. */
87
SVN_ERR (svn_fs_base__unparse_transaction_skel (&txn_skel, txn, pool));
89
/* Only in the context of this function do we know that the DB call
90
will not attempt to modify txn_name, so the cast belongs here. */
91
svn_fs_base__str_to_dbt (&key, txn_name);
92
svn_fs_base__skel_to_dbt (&value, txn_skel, pool);
93
svn_fs_base__trail_debug (trail, "transactions", "put");
94
SVN_ERR (BDB_WRAP (fs, _("storing transaction record"),
95
bfd->transactions->put (bfd->transactions, trail->db_txn,
102
/* Allocate a Subversion transaction ID in FS, as part of TRAIL. Set
103
*ID_P to the new transaction ID, allocated in POOL. */
105
allocate_txn_id (const char **id_p,
110
base_fs_data_t *bfd = fs->fsap_data;
113
char next_key[MAX_KEY_SIZE];
116
svn_fs_base__str_to_dbt (&query, NEXT_KEY_KEY);
118
/* Get the current value associated with the `next-key' key in the table. */
119
svn_fs_base__trail_debug (trail, "transactions", "get");
120
SVN_ERR (BDB_WRAP (fs, "allocating new transaction ID (getting 'next-key')",
121
bfd->transactions->get (bfd->transactions, trail->db_txn,
123
svn_fs_base__result_dbt (&result),
125
svn_fs_base__track_dbt (&result, pool);
127
/* Set our return value. */
128
*id_p = apr_pstrmemdup (pool, result.data, result.size);
130
/* Bump to future key. */
132
svn_fs_base__next_key (result.data, &len, next_key);
133
svn_fs_base__str_to_dbt (&query, NEXT_KEY_KEY);
134
svn_fs_base__str_to_dbt (&result, next_key);
135
svn_fs_base__trail_debug (trail, "transactions", "put");
136
db_err = bfd->transactions->put (bfd->transactions, trail->db_txn,
139
SVN_ERR (BDB_WRAP (fs, "bumping next transaction key", db_err));
145
svn_fs_bdb__create_txn (const char **txn_name_p,
147
const svn_fs_id_t *root_id,
151
const char *txn_name;
154
SVN_ERR (allocate_txn_id (&txn_name, fs, trail, pool));
155
txn.kind = transaction_kind_normal;
156
txn.root_id = root_id;
157
txn.base_id = root_id;
160
txn.revision = SVN_INVALID_REVNUM;
161
SVN_ERR (svn_fs_bdb__put_txn (fs, &txn, txn_name, trail, pool));
163
*txn_name_p = txn_name;
169
svn_fs_bdb__delete_txn (svn_fs_t *fs,
170
const char *txn_name,
174
base_fs_data_t *bfd = fs->fsap_data;
178
/* Make sure TXN is dead. */
179
SVN_ERR (svn_fs_bdb__get_txn (&txn, fs, txn_name, trail, pool));
180
if (is_committed (txn))
181
return svn_fs_base__err_txn_not_mutable (fs, txn_name);
183
/* Delete the transaction from the `transactions' table. */
184
svn_fs_base__str_to_dbt (&key, txn_name);
185
svn_fs_base__trail_debug (trail, "transactions", "del");
186
SVN_ERR (BDB_WRAP (fs, "deleting entry from 'transactions' table",
187
bfd->transactions->del (bfd->transactions,
188
trail->db_txn, &key, 0)));
195
svn_fs_bdb__get_txn (transaction_t **txn_p,
197
const char *txn_name,
201
base_fs_data_t *bfd = fs->fsap_data;
205
transaction_t *transaction;
207
/* Only in the context of this function do we know that the DB call
208
will not attempt to modify txn_name, so the cast belongs here. */
209
svn_fs_base__trail_debug (trail, "transactions", "get");
210
db_err = bfd->transactions->get (bfd->transactions, trail->db_txn,
211
svn_fs_base__str_to_dbt (&key, txn_name),
212
svn_fs_base__result_dbt (&value),
214
svn_fs_base__track_dbt (&value, pool);
216
if (db_err == DB_NOTFOUND)
217
return svn_fs_base__err_no_such_txn (fs, txn_name);
218
SVN_ERR (BDB_WRAP (fs, "reading transaction", db_err));
220
/* Parse TRANSACTION skel */
221
skel = svn_fs_base__parse_skel (value.data, value.size, pool);
223
return svn_fs_base__err_corrupt_txn (fs, txn_name);
225
/* Convert skel to native type. */
226
SVN_ERR (svn_fs_base__parse_transaction_skel (&transaction, skel, pool));
227
*txn_p = transaction;
233
svn_fs_bdb__get_txn_list (apr_array_header_t **names_p,
238
base_fs_data_t *bfd = fs->fsap_data;
239
apr_size_t const next_id_key_len = strlen (NEXT_KEY_KEY);
240
apr_pool_t *subpool = svn_pool_create (pool);
241
apr_array_header_t *names;
244
int db_err, db_c_err;
246
/* Allocate the initial names array */
247
names = apr_array_make (pool, 4, sizeof (const char *));
249
/* Create a database cursor to list the transaction names. */
250
svn_fs_base__trail_debug (trail, "transactions", "cursor");
251
SVN_ERR (BDB_WRAP (fs, "reading transaction list (opening cursor)",
252
bfd->transactions->cursor (bfd->transactions,
253
trail->db_txn, &cursor, 0)));
255
/* Build a null-terminated array of keys in the transactions table. */
256
for (db_err = cursor->c_get (cursor,
257
svn_fs_base__result_dbt (&key),
258
svn_fs_base__result_dbt (&value),
261
db_err = cursor->c_get (cursor,
262
svn_fs_base__result_dbt (&key),
263
svn_fs_base__result_dbt (&value),
270
/* Clear the per-iteration subpool */
271
svn_pool_clear (subpool);
273
/* Track the memory alloc'd for fetching the key and value here
274
so that when the containing pool is cleared, this memory is
276
svn_fs_base__track_dbt (&key, subpool);
277
svn_fs_base__track_dbt (&value, subpool);
279
/* Ignore the "next-id" key. */
280
if (key.size == next_id_key_len
281
&& 0 == memcmp (key.data, NEXT_KEY_KEY, next_id_key_len))
284
/* Parse TRANSACTION skel */
285
txn_skel = svn_fs_base__parse_skel (value.data, value.size, subpool);
288
cursor->c_close (cursor);
289
return svn_fs_base__err_corrupt_txn
290
(fs, apr_pstrmemdup (pool, key.data, key.size));
293
/* Convert skel to native type. */
294
if ((err = svn_fs_base__parse_transaction_skel (&txn, txn_skel,
297
cursor->c_close (cursor);
301
/* If this is an immutable "committed" transaction, ignore it. */
302
if (is_committed (txn))
305
/* Add the transaction name to the NAMES array, duping it into POOL. */
306
(*((const char **) apr_array_push (names)))
307
= apr_pstrmemdup (pool, key.data, key.size);
310
/* Check for errors, but close the cursor first. */
311
db_c_err = cursor->c_close (cursor);
312
if (db_err != DB_NOTFOUND)
314
SVN_ERR (BDB_WRAP (fs, "reading transaction list (listing keys)",
317
SVN_ERR (BDB_WRAP (fs, "reading transaction list (closing cursor)",
320
/* Destroy the per-iteration subpool */
321
svn_pool_destroy (subpool);