1251881Speter /* rev-table.c : working with the `revisions' 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 "bdb_compat.h" 24251881Speter 25251881Speter#include "svn_fs.h" 26251881Speter#include "private/svn_skel.h" 27251881Speter 28251881Speter#include "../fs.h" 29251881Speter#include "../err.h" 30251881Speter#include "../util/fs_skels.h" 31251881Speter#include "../../libsvn_fs/fs-loader.h" 32251881Speter#include "bdb-err.h" 33251881Speter#include "dbt.h" 34251881Speter#include "rev-table.h" 35251881Speter 36251881Speter#include "svn_private_config.h" 37251881Speter#include "private/svn_fs_util.h" 38251881Speter 39251881Speter 40251881Speter/* Opening/creating the `revisions' table. */ 41251881Speter 42251881Speterint svn_fs_bdb__open_revisions_table(DB **revisions_p, 43251881Speter DB_ENV *env, 44251881Speter svn_boolean_t create) 45251881Speter{ 46251881Speter const u_int32_t open_flags = (create ? (DB_CREATE | DB_EXCL) : 0); 47251881Speter DB *revisions; 48251881Speter 49251881Speter BDB_ERR(svn_fs_bdb__check_version()); 50251881Speter BDB_ERR(db_create(&revisions, env, 0)); 51251881Speter BDB_ERR((revisions->open)(SVN_BDB_OPEN_PARAMS(revisions, NULL), 52251881Speter "revisions", 0, DB_RECNO, 53251881Speter open_flags, 0666)); 54251881Speter 55251881Speter *revisions_p = revisions; 56251881Speter return 0; 57251881Speter} 58251881Speter 59251881Speter 60251881Speter 61251881Speter/* Storing and retrieving filesystem revisions. */ 62251881Speter 63251881Speter 64251881Spetersvn_error_t * 65251881Spetersvn_fs_bdb__get_rev(revision_t **revision_p, 66251881Speter svn_fs_t *fs, 67251881Speter svn_revnum_t rev, 68251881Speter trail_t *trail, 69251881Speter apr_pool_t *pool) 70251881Speter{ 71251881Speter base_fs_data_t *bfd = fs->fsap_data; 72251881Speter int db_err; 73251881Speter DBT key, value; 74251881Speter svn_skel_t *skel; 75251881Speter revision_t *revision; 76251881Speter 77251881Speter /* Turn the revision number into a Berkeley DB record number. 78251881Speter Revisions are numbered starting with zero; Berkeley DB record 79251881Speter numbers begin with one. */ 80251881Speter db_recno_t recno = (db_recno_t) rev + 1; 81251881Speter 82251881Speter svn_fs_base__trail_debug(trail, "revisions", "get"); 83251881Speter db_err = bfd->revisions->get(bfd->revisions, trail->db_txn, 84251881Speter svn_fs_base__set_dbt(&key, &recno, 85251881Speter sizeof(recno)), 86251881Speter svn_fs_base__result_dbt(&value), 87251881Speter 0); 88251881Speter svn_fs_base__track_dbt(&value, pool); 89251881Speter 90251881Speter /* If there's no such revision, return an appropriately specific error. */ 91251881Speter if (db_err == DB_NOTFOUND) 92251881Speter return svn_fs_base__err_dangling_rev(fs, rev); 93251881Speter 94251881Speter /* Handle any other error conditions. */ 95251881Speter SVN_ERR(BDB_WRAP(fs, N_("reading filesystem revision"), db_err)); 96251881Speter 97251881Speter /* Parse REVISION skel. */ 98251881Speter skel = svn_skel__parse(value.data, value.size, pool); 99251881Speter if (! skel) 100251881Speter return svn_fs_base__err_corrupt_fs_revision(fs, rev); 101251881Speter 102251881Speter /* Convert skel to native type. */ 103251881Speter SVN_ERR(svn_fs_base__parse_revision_skel(&revision, skel, pool)); 104251881Speter 105251881Speter *revision_p = revision; 106251881Speter return SVN_NO_ERROR; 107251881Speter} 108251881Speter 109251881Speter 110251881Speter/* Write REVISION to FS as part of TRAIL. If *REV is a valid revision 111251881Speter number, write this revision as one that corresponds to *REV, else 112251881Speter write a new revision and return its newly created revision number 113251881Speter in *REV. */ 114251881Spetersvn_error_t * 115251881Spetersvn_fs_bdb__put_rev(svn_revnum_t *rev, 116251881Speter svn_fs_t *fs, 117251881Speter const revision_t *revision, 118251881Speter trail_t *trail, 119251881Speter apr_pool_t *pool) 120251881Speter{ 121251881Speter base_fs_data_t *bfd = fs->fsap_data; 122251881Speter int db_err; 123251881Speter db_recno_t recno = 0; 124251881Speter svn_skel_t *skel; 125251881Speter DBT key, value; 126251881Speter 127251881Speter /* Convert native type to skel. */ 128251881Speter SVN_ERR(svn_fs_base__unparse_revision_skel(&skel, revision, pool)); 129251881Speter 130251881Speter if (SVN_IS_VALID_REVNUM(*rev)) 131251881Speter { 132251881Speter DBT query, result; 133251881Speter 134251881Speter /* Update the filesystem revision with the new skel. */ 135251881Speter recno = (db_recno_t) *rev + 1; 136251881Speter svn_fs_base__trail_debug(trail, "revisions", "put"); 137251881Speter db_err = bfd->revisions->put 138251881Speter (bfd->revisions, trail->db_txn, 139251881Speter svn_fs_base__set_dbt(&query, &recno, sizeof(recno)), 140251881Speter svn_fs_base__skel_to_dbt(&result, skel, pool), 0); 141251881Speter return BDB_WRAP(fs, N_("updating filesystem revision"), db_err); 142251881Speter } 143251881Speter 144251881Speter svn_fs_base__trail_debug(trail, "revisions", "put"); 145251881Speter db_err = bfd->revisions->put(bfd->revisions, trail->db_txn, 146251881Speter svn_fs_base__recno_dbt(&key, &recno), 147251881Speter svn_fs_base__skel_to_dbt(&value, skel, pool), 148251881Speter DB_APPEND); 149251881Speter SVN_ERR(BDB_WRAP(fs, N_("storing filesystem revision"), db_err)); 150251881Speter 151251881Speter /* Turn the record number into a Subversion revision number. 152251881Speter Revisions are numbered starting with zero; Berkeley DB record 153251881Speter numbers begin with one. */ 154251881Speter *rev = recno - 1; 155251881Speter return SVN_NO_ERROR; 156251881Speter} 157251881Speter 158251881Speter 159251881Speter 160251881Speter/* Getting the youngest revision. */ 161251881Speter 162251881Speter 163251881Spetersvn_error_t * 164251881Spetersvn_fs_bdb__youngest_rev(svn_revnum_t *youngest_p, 165251881Speter svn_fs_t *fs, 166251881Speter trail_t *trail, 167251881Speter apr_pool_t *pool) 168251881Speter{ 169251881Speter base_fs_data_t *bfd = fs->fsap_data; 170251881Speter int db_err; 171251881Speter DBC *cursor = 0; 172251881Speter DBT key, value; 173251881Speter db_recno_t recno; 174251881Speter 175251881Speter SVN_ERR(svn_fs__check_fs(fs, TRUE)); 176251881Speter 177251881Speter /* Create a database cursor. */ 178251881Speter svn_fs_base__trail_debug(trail, "revisions", "cursor"); 179251881Speter SVN_ERR(BDB_WRAP(fs, N_("getting youngest revision (creating cursor)"), 180251881Speter bfd->revisions->cursor(bfd->revisions, trail->db_txn, 181251881Speter &cursor, 0))); 182251881Speter 183251881Speter /* Find the last entry in the `revisions' table. */ 184251881Speter db_err = svn_bdb_dbc_get(cursor, 185251881Speter svn_fs_base__recno_dbt(&key, &recno), 186251881Speter svn_fs_base__nodata_dbt(&value), 187251881Speter DB_LAST); 188251881Speter 189251881Speter if (db_err) 190251881Speter { 191251881Speter /* Free the cursor. Ignore any error value --- the error above 192251881Speter is more interesting. */ 193251881Speter svn_bdb_dbc_close(cursor); 194251881Speter 195251881Speter if (db_err == DB_NOTFOUND) 196251881Speter /* The revision 0 should always be present, at least. */ 197251881Speter return 198251881Speter svn_error_createf 199251881Speter (SVN_ERR_FS_CORRUPT, 0, 200251881Speter "Corrupt DB: revision 0 missing from 'revisions' table, in " 201251881Speter "filesystem '%s'", fs->path); 202251881Speter 203251881Speter SVN_ERR(BDB_WRAP(fs, N_("getting youngest revision (finding last entry)"), 204251881Speter db_err)); 205251881Speter } 206251881Speter 207251881Speter /* You can't commit a transaction with open cursors, because: 208251881Speter 1) key/value pairs don't get deleted until the cursors referring 209251881Speter to them are closed, so closing a cursor can fail for various 210251881Speter reasons, and txn_commit shouldn't fail that way, and 211251881Speter 2) using a cursor after committing its transaction can cause 212251881Speter undetectable database corruption. */ 213251881Speter SVN_ERR(BDB_WRAP(fs, N_("getting youngest revision (closing cursor)"), 214251881Speter svn_bdb_dbc_close(cursor))); 215251881Speter 216251881Speter /* Turn the record number into a Subversion revision number. 217251881Speter Revisions are numbered starting with zero; Berkeley DB record 218251881Speter numbers begin with one. */ 219251881Speter *youngest_p = recno - 1; 220251881Speter return SVN_NO_ERROR; 221251881Speter} 222