📄 strings-table.c
字号:
/* strings-table.c : operations on the `strings' table * * ==================================================================== * Copyright (c) 2000-2004 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== */#include "bdb_compat.h"#include "svn_fs.h"#include "svn_pools.h"#include "../fs.h"#include "../err.h"#include "dbt.h"#include "../trail.h"#include "../key-gen.h"#include "../../libsvn_fs/fs-loader.h"#include "bdb-err.h"#include "strings-table.h"#include "svn_private_config.h"/*** Creating and opening the strings table. ***/intsvn_fs_bdb__open_strings_table(DB **strings_p, DB_ENV *env, svn_boolean_t create){ const u_int32_t open_flags = (create ? (DB_CREATE | DB_EXCL) : 0); DB *strings; BDB_ERR(svn_fs_bdb__check_version()); BDB_ERR(db_create(&strings, env, 0)); /* Enable duplicate keys. This allows the data to be spread out across multiple records. Note: this must occur before ->open(). */ BDB_ERR(strings->set_flags(strings, DB_DUP)); BDB_ERR(strings->open(SVN_BDB_OPEN_PARAMS(strings, NULL), "strings", 0, DB_BTREE, open_flags, 0666)); if (create) { DBT key, value; /* Create the `next-key' table entry. */ BDB_ERR(strings->put (strings, 0, svn_fs_base__str_to_dbt(&key, NEXT_KEY_KEY), svn_fs_base__str_to_dbt(&value, "0"), 0)); } *strings_p = strings; return 0;}/*** Storing and retrieving strings. ***//* Allocate *CURSOR and advance it to first row in the set of rows whose key is defined by QUERY. Set *LENGTH to the size of that first row. */static svn_error_t *locate_key(apr_size_t *length, DBC **cursor, DBT *query, svn_fs_t *fs, trail_t *trail, apr_pool_t *pool){ base_fs_data_t *bfd = fs->fsap_data; int db_err; DBT result; svn_fs_base__trail_debug(trail, "strings", "cursor"); SVN_ERR(BDB_WRAP(fs, _("creating cursor for reading a string"), bfd->strings->cursor(bfd->strings, trail->db_txn, cursor, 0))); /* Set up the DBT for reading the length of the record. */ svn_fs_base__clear_dbt(&result); result.ulen = 0; result.flags |= DB_DBT_USERMEM; /* Advance the cursor to the key that we're looking for. */ db_err = (*cursor)->c_get(*cursor, query, &result, DB_SET); /* We don't need to svn_fs_base__track_dbt() the result, because nothing was allocated in it. */ /* If there's no such node, return an appropriately specific error. */ if (db_err == DB_NOTFOUND) { (*cursor)->c_close(*cursor); return svn_error_createf (SVN_ERR_FS_NO_SUCH_STRING, 0, "No such string '%s'", (const char *)query->data); } if (db_err) { DBT rerun; if (db_err != SVN_BDB_DB_BUFFER_SMALL) { (*cursor)->c_close(*cursor); return BDB_WRAP(fs, "moving cursor", db_err); } /* We got an SVN_BDB_DB_BUFFER_SMALL (typical since we have a zero length buf), so we need to re-run the operation to make it happen. */ svn_fs_base__clear_dbt(&rerun); rerun.flags |= DB_DBT_USERMEM | DB_DBT_PARTIAL; db_err = (*cursor)->c_get(*cursor, query, &rerun, DB_SET); if (db_err) { (*cursor)->c_close(*cursor); return BDB_WRAP(fs, "rerunning cursor move", db_err); } } /* ### this cast might not be safe? */ *length = (apr_size_t) result.size; return SVN_NO_ERROR;}/* Advance CURSOR by a single row in the set of rows whose keys match CURSOR's current location. Set *LENGTH to the size of that next row. If any error occurs, CURSOR will be destroyed. */static intget_next_length(apr_size_t *length, DBC *cursor, DBT *query){ DBT result; int db_err; /* Set up the DBT for reading the length of the record. */ svn_fs_base__clear_dbt(&result); result.ulen = 0; result.flags |= DB_DBT_USERMEM; /* Note: this may change the QUERY DBT, but that's okay: we're going to be sticking with the same key anyways. */ db_err = cursor->c_get(cursor, query, &result, DB_NEXT_DUP); /* Note that we exit on DB_NOTFOUND. The caller uses that to end a loop. */ if (db_err) { DBT rerun; if (db_err != SVN_BDB_DB_BUFFER_SMALL) { cursor->c_close(cursor); return db_err; } /* We got an SVN_BDB_DB_BUFFER_SMALL (typical since we have a zero length buf), so we need to re-run the operation to make it happen. */ svn_fs_base__clear_dbt(&rerun); rerun.flags |= DB_DBT_USERMEM | DB_DBT_PARTIAL; db_err = cursor->c_get(cursor, query, &rerun, DB_NEXT_DUP); if (db_err) cursor->c_close(cursor); } /* ### this cast might not be safe? */ *length = (apr_size_t) result.size; return db_err;}svn_error_t *svn_fs_bdb__string_read(svn_fs_t *fs, const char *key, char *buf, svn_filesize_t offset, apr_size_t *len, trail_t *trail, apr_pool_t *pool){ int db_err; DBT query, result; DBC *cursor; apr_size_t length, bytes_read = 0; svn_fs_base__str_to_dbt(&query, key); SVN_ERR(locate_key(&length, &cursor, &query, fs, trail, pool)); /* Seek through the records for this key, trying to find the record that includes OFFSET. Note that we don't require reading from more than one record since we're allowed to return partial reads. */ while (length <= offset) { offset -= length; /* Remember, if any error happens, our cursor has been closed for us. */ db_err = get_next_length(&length, cursor, &query); /* No more records? They tried to read past the end. */ if (db_err == DB_NOTFOUND) { *len = 0; return SVN_NO_ERROR; } if (db_err) return BDB_WRAP(fs, "reading string", db_err); } /* The current record contains OFFSET. Fetch the contents now. Note that OFFSET has been moved to be relative to this record. The length could quite easily extend past this record, so we use DB_DBT_PARTIAL and read successive records until we've filled the request. */ while (1) { svn_fs_base__clear_dbt(&result); result.data = buf + bytes_read; result.ulen = *len - bytes_read; result.doff = (u_int32_t)offset; result.dlen = *len - bytes_read; result.flags |= (DB_DBT_USERMEM | DB_DBT_PARTIAL); db_err = cursor->c_get(cursor, &query, &result, DB_CURRENT); if (db_err) { cursor->c_close(cursor); return BDB_WRAP(fs, "reading string", db_err); } bytes_read += result.size; if (bytes_read == *len) { /* Done with the cursor. */ SVN_ERR(BDB_WRAP(fs, "closing string-reading cursor", cursor->c_close(cursor))); break; } /* Remember, if any error happens, our cursor has been closed for us. */ db_err = get_next_length(&length, cursor, &query); if (db_err == DB_NOTFOUND) break; if (db_err) return BDB_WRAP(fs, "reading string", db_err); /* We'll be reading from the beginning of the next record */ offset = 0; } *len = bytes_read; return SVN_NO_ERROR;}/* Get the current 'next-key' value and bump the record. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -