📄 strings-table.c
字号:
/* Get the current 'next-key' value and bump the record. */
static svn_error_t *
get_key_and_bump (svn_fs_t *fs, const char **key, trail_t *trail)
{
base_fs_data_t *bfd = fs->fsap_data;
DBC *cursor;
char next_key[MAX_KEY_SIZE];
apr_size_t key_len;
int db_err;
DBT query;
DBT result;
/* ### todo: see issue #409 for why bumping the key as part of this
trail is problematic. */
/* Open a cursor and move it to the 'next-key' value. We can then fetch
the contents and use the cursor to overwrite those contents. Since
this database allows duplicates, we can't do an arbitrary 'put' to
write the new value -- that would append, not overwrite. */
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)));
/* Advance the cursor to 'next-key' and read it. */
db_err = cursor->c_get (cursor,
svn_fs_base__str_to_dbt (&query, NEXT_KEY_KEY),
svn_fs_base__result_dbt (&result),
DB_SET);
if (db_err)
{
cursor->c_close (cursor);
return BDB_WRAP (fs, "getting next-key value", db_err);
}
svn_fs_base__track_dbt (&result, trail->pool);
*key = apr_pstrmemdup (trail->pool, result.data, result.size);
/* Bump to future key. */
key_len = result.size;
svn_fs_base__next_key (result.data, &key_len, next_key);
/* Shove the new key back into the database, at the cursor position. */
db_err = cursor->c_put (cursor, &query,
svn_fs_base__str_to_dbt (&result, next_key),
DB_CURRENT);
if (db_err)
{
cursor->c_close (cursor); /* ignore the error, the original is
more important. */
return BDB_WRAP (fs, "bumping next string key", db_err);
}
return BDB_WRAP (fs, "closing string-reading cursor",
cursor->c_close (cursor));
}
svn_error_t *
svn_fs_bdb__string_append (svn_fs_t *fs,
const char **key,
apr_size_t len,
const char *buf,
trail_t *trail)
{
base_fs_data_t *bfd = fs->fsap_data;
DBT query, result;
/* If the passed-in key is NULL, we graciously generate a new string
using the value of the `next-key' record in the strings table. */
if (*key == NULL)
{
SVN_ERR (get_key_and_bump (fs, key, trail));
}
/* Store a new record into the database. */
svn_fs_base__trail_debug (trail, "strings", "put");
SVN_ERR (BDB_WRAP (fs, "appending string",
bfd->strings->put
(bfd->strings, trail->db_txn,
svn_fs_base__str_to_dbt (&query, *key),
svn_fs_base__set_dbt (&result, buf, len),
0)));
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_bdb__string_clear (svn_fs_t *fs,
const char *key,
trail_t *trail)
{
base_fs_data_t *bfd = fs->fsap_data;
int db_err;
DBT query, result;
svn_fs_base__str_to_dbt (&query, key);
/* Torch the prior contents */
svn_fs_base__trail_debug (trail, "strings", "del");
db_err = bfd->strings->del (bfd->strings, trail->db_txn, &query, 0);
/* If there's no such node, return an appropriately specific error. */
if (db_err == DB_NOTFOUND)
return svn_error_createf
(SVN_ERR_FS_NO_SUCH_STRING, 0,
"No such string '%s'", key);
/* Handle any other error conditions. */
SVN_ERR (BDB_WRAP (fs, "clearing string", db_err));
/* Shove empty data back in for this key. */
svn_fs_base__clear_dbt (&result);
result.data = 0;
result.size = 0;
result.flags |= DB_DBT_USERMEM;
svn_fs_base__trail_debug (trail, "strings", "put");
return BDB_WRAP (fs, "storing empty contents",
bfd->strings->put (bfd->strings, trail->db_txn,
&query, &result, 0));
}
svn_error_t *
svn_fs_bdb__string_size (svn_filesize_t *size,
svn_fs_t *fs,
const char *key,
trail_t *trail)
{
int db_err;
DBT query;
DBC *cursor;
apr_size_t length;
svn_filesize_t total;
svn_fs_base__str_to_dbt (&query, key);
SVN_ERR (locate_key (&length, &cursor, &query, fs, trail));
total = length;
while (1)
{
db_err = get_next_length (&length, cursor, &query);
/* No more records? Then return the total length. */
if (db_err == DB_NOTFOUND)
{
*size = total;
return SVN_NO_ERROR;
}
if (db_err)
return BDB_WRAP (fs, "fetching string length", db_err);
total += length;
}
/* NOTREACHED */
}
svn_error_t *
svn_fs_bdb__string_delete (svn_fs_t *fs,
const char *key,
trail_t *trail)
{
base_fs_data_t *bfd = fs->fsap_data;
int db_err;
DBT query;
svn_fs_base__trail_debug (trail, "strings", "del");
db_err = bfd->strings->del (bfd->strings, trail->db_txn,
svn_fs_base__str_to_dbt (&query, key), 0);
/* If there's no such node, return an appropriately specific error. */
if (db_err == DB_NOTFOUND)
return svn_error_createf
(SVN_ERR_FS_NO_SUCH_STRING, 0,
"No such string '%s'", key);
/* Handle any other error conditions. */
SVN_ERR (BDB_WRAP (fs, "deleting string", db_err));
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_bdb__string_copy (svn_fs_t *fs,
const char **new_key,
const char *key,
trail_t *trail)
{
base_fs_data_t *bfd = fs->fsap_data;
DBT query;
DBT result;
DBT copykey;
DBC *cursor;
int db_err;
/* Copy off the old key in case the caller is sharing storage
between the old and new keys. */
const char *old_key = apr_pstrdup (trail->pool, key);
SVN_ERR (get_key_and_bump (fs, new_key, trail));
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)));
svn_fs_base__str_to_dbt (&query, old_key);
svn_fs_base__str_to_dbt (©key, *new_key);
svn_fs_base__clear_dbt (&result);
/* Move to the first record and fetch its data (under BDB's mem mgmt). */
db_err = cursor->c_get (cursor, &query, &result, DB_SET);
if (db_err)
{
cursor->c_close (cursor);
return BDB_WRAP (fs, "getting next-key value", db_err);
}
while (1)
{
/* ### can we pass a BDB-provided buffer to another BDB function?
### they are supposed to have a duration up to certain points
### of calling back into BDB, but I'm not sure what the exact
### rules are. it is definitely nicer to use BDB buffers here
### to simplify things and reduce copies, but... hrm.
*/
/* Write the data to the database */
svn_fs_base__trail_debug (trail, "strings", "put");
db_err = bfd->strings->put (bfd->strings, trail->db_txn,
©key, &result, 0);
if (db_err)
{
cursor->c_close (cursor);
return BDB_WRAP (fs, "writing copied data", db_err);
}
/* Read the next chunk. Terminate loop if we're done. */
svn_fs_base__clear_dbt (&result);
db_err = cursor->c_get (cursor, &query, &result, DB_NEXT_DUP);
if (db_err == DB_NOTFOUND)
break;
if (db_err)
{
cursor->c_close (cursor);
return BDB_WRAP (fs, "fetching string data for a copy", db_err);
}
}
return BDB_WRAP (fs, "closing string-reading cursor",
cursor->c_close (cursor));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -