1 /* locks-table.c : operations on the `locks' 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 "../util/skel.h"
27 #include "../util/fs_skels.h"
29 #include "../../libsvn_fs/fs-loader.h"
31 #include "locks-table.h"
32 #include "lock-tokens-table.h"
34 #include "private/svn_fs_util.h"
38 svn_fs_bdb__open_locks_table(DB
**locks_p
,
42 const u_int32_t open_flags
= (create
? (DB_CREATE
| DB_EXCL
) : 0);
46 BDB_ERR(svn_fs_bdb__check_version());
47 BDB_ERR(db_create(&locks
, env
, 0));
48 error
= (locks
->open
)(SVN_BDB_OPEN_PARAMS(locks
, NULL
),
52 /* Create the table if it doesn't yet exist. This is a form of
53 automagical repository upgrading. */
54 if (error
== ENOENT
&& (! create
))
56 BDB_ERR(locks
->close(locks
, 0));
57 return svn_fs_bdb__open_locks_table(locks_p
, env
, TRUE
);
68 svn_fs_bdb__lock_add(svn_fs_t
*fs
,
69 const char *lock_token
,
74 base_fs_data_t
*bfd
= fs
->fsap_data
;
78 /* Convert native type to skel. */
79 SVN_ERR(svn_fs_base__unparse_lock_skel(&lock_skel
, lock
, pool
));
81 svn_fs_base__str_to_dbt(&key
, lock_token
);
82 svn_fs_base__skel_to_dbt(&value
, lock_skel
, pool
);
83 svn_fs_base__trail_debug(trail
, "lock", "add");
84 SVN_ERR(BDB_WRAP(fs
, "storing lock record",
85 bfd
->locks
->put(bfd
->locks
, trail
->db_txn
,
94 svn_fs_bdb__lock_delete(svn_fs_t
*fs
,
95 const char *lock_token
,
99 base_fs_data_t
*bfd
= fs
->fsap_data
;
103 svn_fs_base__str_to_dbt(&key
, lock_token
);
104 svn_fs_base__trail_debug(trail
, "locks", "del");
105 db_err
= bfd
->locks
->del(bfd
->locks
, trail
->db_txn
, &key
, 0);
107 if (db_err
== DB_NOTFOUND
)
108 return svn_fs_base__err_bad_lock_token(fs
, lock_token
);
109 SVN_ERR(BDB_WRAP(fs
, "deleting lock from 'locks' table", db_err
));
117 svn_fs_bdb__lock_get(svn_lock_t
**lock_p
,
119 const char *lock_token
,
123 base_fs_data_t
*bfd
= fs
->fsap_data
;
129 svn_fs_base__trail_debug(trail
, "lock", "get");
130 db_err
= bfd
->locks
->get(bfd
->locks
, trail
->db_txn
,
131 svn_fs_base__str_to_dbt(&key
, lock_token
),
132 svn_fs_base__result_dbt(&value
),
134 svn_fs_base__track_dbt(&value
, pool
);
136 if (db_err
== DB_NOTFOUND
)
137 return svn_fs_base__err_bad_lock_token(fs
, lock_token
);
138 SVN_ERR(BDB_WRAP(fs
, "reading lock", db_err
));
140 /* Parse TRANSACTION skel */
141 skel
= svn_fs_base__parse_skel(value
.data
, value
.size
, pool
);
143 return svn_fs_base__err_corrupt_lock(fs
, lock_token
);
145 /* Convert skel to native type. */
146 SVN_ERR(svn_fs_base__parse_lock_skel(&lock
, skel
, pool
));
148 /* Possibly auto-expire the lock. */
149 if (lock
->expiration_date
&& (apr_time_now() > lock
->expiration_date
))
151 SVN_ERR(svn_fs_bdb__lock_delete(fs
, lock_token
, trail
, pool
));
152 return SVN_FS__ERR_LOCK_EXPIRED(fs
, lock_token
);
161 get_lock(svn_lock_t
**lock_p
,
164 const char *lock_token
,
168 svn_error_t
*err
= SVN_NO_ERROR
;
171 /* Make sure the token points to an existing, non-expired lock, by
172 doing a lookup in the `locks' table. Use 'pool'. */
173 err
= svn_fs_bdb__lock_get(lock_p
, fs
, lock_token
, trail
, pool
);
174 if (err
&& ((err
->apr_err
== SVN_ERR_FS_LOCK_EXPIRED
)
175 || (err
->apr_err
== SVN_ERR_FS_BAD_LOCK_TOKEN
)))
177 svn_error_clear(err
);
179 /* If `locks' doesn't have the lock, then we should lose it
180 from `lock-tokens' table as well, then skip to the next
181 matching path-key. */
182 err
= svn_fs_bdb__lock_token_delete(fs
, path
, trail
, pool
);
189 svn_fs_bdb__locks_get(svn_fs_t
*fs
,
191 svn_fs_get_locks_callback_t get_locks_func
,
192 void *get_locks_baton
,
196 base_fs_data_t
*bfd
= fs
->fsap_data
;
199 int db_err
, db_c_err
;
200 apr_pool_t
*subpool
= svn_pool_create(pool
);
201 const char *lock_token
;
204 const char *lookup_path
= path
;
206 /* First, try to lookup PATH itself. */
207 err
= svn_fs_bdb__lock_token_get(&lock_token
, fs
, path
, trail
, pool
);
208 if (err
&& ((err
->apr_err
== SVN_ERR_FS_LOCK_EXPIRED
)
209 || (err
->apr_err
== SVN_ERR_FS_BAD_LOCK_TOKEN
)
210 || (err
->apr_err
== SVN_ERR_FS_NO_SUCH_LOCK
)))
212 svn_error_clear(err
);
220 SVN_ERR(get_lock(&lock
, fs
, path
, lock_token
, trail
, pool
));
221 if (lock
&& get_locks_func
)
222 SVN_ERR(get_locks_func(get_locks_baton
, lock
, pool
));
225 /* Now go hunt for possible children of PATH. */
226 if (strcmp(path
, "/") != 0)
227 lookup_path
= apr_pstrcat(pool
, path
, "/", NULL
);
229 svn_fs_base__trail_debug(trail
, "lock-tokens", "cursor");
230 db_err
= bfd
->lock_tokens
->cursor(bfd
->lock_tokens
, trail
->db_txn
,
232 SVN_ERR(BDB_WRAP(fs
, "creating cursor for reading lock tokens", db_err
));
234 /* Since the key is going to be returned as well as the value make
235 sure BDB malloc's the returned key. */
236 svn_fs_base__str_to_dbt(&key
, lookup_path
);
237 key
.flags
|= DB_DBT_MALLOC
;
239 /* Get the first matching key that is either equal or greater than
240 the one passed in, by passing in the DB_RANGE_SET flag. */
241 db_err
= svn_bdb_dbc_get(cursor
, &key
, svn_fs_base__result_dbt(&value
),
244 /* As long as the prefix of the returned KEY matches LOOKUP_PATH we
245 know it is either LOOKUP_PATH or a decendant thereof. */
247 && strncmp(lookup_path
, key
.data
, strlen(lookup_path
)) == 0)
249 const char *child_path
;
251 svn_pool_clear(subpool
);
253 svn_fs_base__track_dbt(&key
, subpool
);
254 svn_fs_base__track_dbt(&value
, subpool
);
256 /* Create a usable path and token in temporary memory. */
257 child_path
= apr_pstrmemdup(subpool
, key
.data
, key
.size
);
258 lock_token
= apr_pstrmemdup(subpool
, value
.data
, value
.size
);
260 /* Get the lock for CHILD_PATH. */
261 err
= get_lock(&lock
, fs
, child_path
, lock_token
, trail
, subpool
);
264 svn_bdb_dbc_close(cursor
);
268 /* Lock is verified, hand it off to our callback. */
269 if (lock
&& get_locks_func
)
271 err
= get_locks_func(get_locks_baton
, lock
, subpool
);
274 svn_bdb_dbc_close(cursor
);
279 svn_fs_base__result_dbt(&key
);
280 svn_fs_base__result_dbt(&value
);
281 db_err
= svn_bdb_dbc_get(cursor
, &key
, &value
, DB_NEXT
);
284 svn_pool_destroy(subpool
);
285 db_c_err
= svn_bdb_dbc_close(cursor
);
287 if (db_err
&& (db_err
!= DB_NOTFOUND
))
288 SVN_ERR(BDB_WRAP(fs
, "fetching lock tokens", db_err
));
290 SVN_ERR(BDB_WRAP(fs
, "fetching lock tokens (closing cursor)", db_c_err
));