Author: julianfoad Date: Mon Mar 1 10:29:50 2010 New Revision: 917450 URL: http://svn.apache.org/viewvc?rev=917450&view=rev Log: >From Philip Martin's "obliterate-like-deltify" branch, bring in a new kind of obliterate function which obliterates the changes made by a particular rep. This is here to experiment with; there are no calls to it yet.
* subversion/libsvn_fs_base/dag.c, subversion/libsvn_fs_base/dag.h (svn_fs_base__dag_obliterate_rep): New function, renamed from the function svn_fs_base__dag_obliterate() on the branch. * subversion/libsvn_fs_base/reps-strings.c, subversion/libsvn_fs_base/reps-strings.h (svn_fs_base__rep_obliterate): New function. * subversion/libsvn_fs_base/tree.c (txn_obliterate_rep_args): New struct. (txn_body_obliterate_rep, svn_fs_base__obliterate_rep): New functions. Modified: subversion/trunk/subversion/libsvn_fs_base/dag.c subversion/trunk/subversion/libsvn_fs_base/dag.h subversion/trunk/subversion/libsvn_fs_base/reps-strings.c subversion/trunk/subversion/libsvn_fs_base/reps-strings.h subversion/trunk/subversion/libsvn_fs_base/tree.c Modified: subversion/trunk/subversion/libsvn_fs_base/dag.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_base/dag.c?rev=917450&r1=917449&r2=917450&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_fs_base/dag.c (original) +++ subversion/trunk/subversion/libsvn_fs_base/dag.c Mon Mar 1 10:29:50 2010 @@ -1530,6 +1530,33 @@ } +svn_error_t * +svn_fs_base__dag_obliterate_rep(dag_node_t *node, + dag_node_t *pred_node, + trail_t *trail, + apr_pool_t *pool) +{ + node_revision_t *node_rev, *pred_node_rev; + svn_fs_t *fs = svn_fs_base__dag_get_fs(node); + const char *pred_key; + + SVN_ERR(svn_fs_bdb__get_node_revision(&node_rev, fs, node->id, trail, pool)); + if (pred_node) + { + SVN_ERR(svn_fs_bdb__get_node_revision(&pred_node_rev, fs, pred_node->id, + trail, pool)); + pred_key = pred_node_rev->data_key; + } + else + { + pred_key = NULL; + } + + return svn_fs_base__rep_obliterate(trail->fs, node_rev->data_key, pred_key, + trail, pool); +} + + /* Maybe store a `checksum-reps' index record for the representation whose key is REP. (If there's already a rep for this checksum, we don't bother overwriting it.) */ Modified: subversion/trunk/subversion/libsvn_fs_base/dag.h URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_base/dag.h?rev=917450&r1=917449&r2=917450&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_fs_base/dag.h (original) +++ subversion/trunk/subversion/libsvn_fs_base/dag.h Mon Mar 1 10:29:50 2010 @@ -558,6 +558,15 @@ trail_t *trail, apr_pool_t *pool); +/* Obliterate NODE's data by constructing a new representation that + consists of a no-change delta from PRED_NODE, and changing NODE to + use that new rep, and leaving the old rep alone in case it is used + by other nodes. If PRED_NODE is null + then construct a representation with an empty fulltext instead. */ +svn_error_t *svn_fs_base__dag_obliterate_rep(dag_node_t *node, + dag_node_t *pred_node, + trail_t *trail, + apr_pool_t *pool); /* Index NODE's backing data representations by their checksum. Do this as part of TRAIL. Use POOL for allocations. */ Modified: subversion/trunk/subversion/libsvn_fs_base/reps-strings.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_base/reps-strings.c?rev=917450&r1=917449&r2=917450&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_fs_base/reps-strings.c (original) +++ subversion/trunk/subversion/libsvn_fs_base/reps-strings.c Mon Mar 1 10:29:50 2010 @@ -1621,3 +1621,132 @@ return SVN_NO_ERROR; } + +svn_error_t *svn_fs_base__rep_obliterate(svn_fs_t *fs, + const char *key, + const char *pred_key, + trail_t *trail, + apr_pool_t *pool) +{ + const char *new_str = NULL; + representation_t *empty; + svn_stream_t *new_stream; + struct write_svndiff_strings_baton new_baton; + svn_stream_t *pred_stream1, *pred_stream2; + svn_txdelta_stream_t *txdelta_stream; + base_fs_data_t *bfd = fs->fsap_data; + svn_txdelta_window_handler_t new_handler; + void *new_handler_baton; + apr_pool_t *wpool; + apr_array_header_t *windows; + window_write_t *ww; + svn_txdelta_window_t *window; + svn_filesize_t tview_off = 0; + svn_filesize_t diffsize = 0; + const unsigned char *digest; + representation_t *pred_rep; + representation_t new_rep; + rep_delta_chunk_t *chunk; + apr_array_header_t *chunks; + int i; + + if (!pred_key) + { + /* No predecessor so just write a new empty rep */ + SVN_ERR(svn_fs_bdb__string_append(fs, &new_str, 0, NULL, trail, pool)); + empty = make_fulltext_rep(new_str, NULL, + svn_checksum_empty_checksum(svn_checksum_md5, + pool), + svn_checksum_empty_checksum(svn_checksum_sha1, + pool), + pool); + SVN_ERR(svn_fs_bdb__write_rep(fs, key, empty, trail, pool)); + + return SVN_NO_ERROR; + } + + if (!strcmp(key, pred_key)) + return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, + _("Attempt to obliterate '%s' using itself "), + key); + + new_baton.fs = fs; + new_baton.trail = trail; + new_baton.header_read = FALSE; + new_stream = svn_stream_create(&new_baton, pool); + svn_stream_set_write(new_stream, write_svndiff_strings); + + /* ### Is there a simpler way to write a no-change delta? */ + SVN_ERR(svn_fs_base__rep_contents_read_stream(&pred_stream1, fs, pred_key, + TRUE, trail, pool)); + SVN_ERR(svn_fs_base__rep_contents_read_stream(&pred_stream2, fs, pred_key, + TRUE, trail, pool)); + svn_txdelta(&txdelta_stream, pred_stream1, pred_stream2, pool); + + if (bfd->format >= SVN_FS_BASE__MIN_SVNDIFF1_FORMAT) + svn_txdelta_to_svndiff2(&new_handler, &new_handler_baton, + new_stream, 1, pool); + else + svn_txdelta_to_svndiff2(&new_handler, &new_handler_baton, + new_stream, 0, pool); + + wpool = svn_pool_create(pool); + windows = apr_array_make(pool, 1, sizeof(ww)); + do + { + new_baton.size = 0; + new_baton.key = NULL; + svn_pool_clear(wpool); + + SVN_ERR(svn_txdelta_next_window(&window, txdelta_stream, wpool)); + SVN_ERR(new_handler(window, new_handler_baton)); + if (window) + { + ww = apr_pcalloc(pool, sizeof(*ww)); + ww->key = new_baton.key; + ww->svndiff_len = new_baton.size; + ww->text_off = tview_off; + ww->text_len = window->tview_len; + APR_ARRAY_PUSH(windows, window_write_t *) = ww; + tview_off += window->tview_len; + diffsize += ww->svndiff_len; + } + } while (window); + + svn_pool_destroy(wpool); + + digest = svn_txdelta_md5_digest(txdelta_stream); + if (!digest) + return svn_error_createf(SVN_ERR_DELTA_MD5_CHECKSUM_ABSENT, NULL, + _("Failed to calculate MD5 digest for '%s'"), + pred_key); + /* ### Check the digest against something? pred_rep->md5_checksum? */ + + SVN_ERR(svn_fs_bdb__read_rep(&pred_rep, fs, pred_key, trail, pool)); + new_rep.md5_checksum = svn_checksum_dup(pred_rep->md5_checksum, pool); + new_rep.sha1_checksum = svn_checksum_dup(pred_rep->sha1_checksum, pool); + new_rep.kind = rep_kind_delta; + new_rep.txn_id = NULL; + + chunks = apr_array_make(pool, windows->nelts, sizeof(chunk)); + + for (i = 0; i < windows->nelts; i++) + { + ww = APR_ARRAY_IDX(windows, i, window_write_t *); + + chunk = apr_palloc(pool, sizeof(*chunk)); + chunk->offset = ww->text_off; + + chunk->version = new_baton.version; + chunk->string_key = ww->key; + chunk->size = ww->text_len; + chunk->rep_key = pred_key; + + APR_ARRAY_PUSH(chunks, rep_delta_chunk_t *) = chunk; + } + + new_rep.contents.delta.chunks = chunks; + SVN_ERR(svn_fs_bdb__write_rep(fs, key, &new_rep, trail, pool)); + + return SVN_NO_ERROR; +} Modified: subversion/trunk/subversion/libsvn_fs_base/reps-strings.h URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_base/reps-strings.h?rev=917450&r1=917449&r2=917450&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_fs_base/reps-strings.h (original) +++ subversion/trunk/subversion/libsvn_fs_base/reps-strings.h Mon Mar 1 10:29:50 2010 @@ -168,6 +168,18 @@ trail_t *trail, apr_pool_t *pool); +/* Obliterate KEY's data by creating a new rep that consists of a + no-change delta from PRED_KEY's data. If PRED_KEY is null then + construct an empty fulltext instead of a delta. KEY's old data + remains in the database in case some other key's data is derived + from it. */ +/* ### TODO: clarify. What kind of objects are KEY and PRED_KEY, and what + does it do with the new rep? */ +svn_error_t *svn_fs_base__rep_obliterate(svn_fs_t *fs, + const char *key, + const char *pred_key, + trail_t *trail, + apr_pool_t *pool); #ifdef __cplusplus Modified: subversion/trunk/subversion/libsvn_fs_base/tree.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_base/tree.c?rev=917450&r1=917449&r2=917450&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_fs_base/tree.c (original) +++ subversion/trunk/subversion/libsvn_fs_base/tree.c Mon Mar 1 10:29:50 2010 @@ -2940,6 +2940,94 @@ } +struct txn_obliterate_rep_args +{ + const svn_fs_id_t *id; + svn_boolean_t has_pred; + const svn_fs_id_t *pred_id; +}; + +static svn_error_t * +txn_body_obliterate_rep(void *baton, trail_t *trail) +{ + struct txn_obliterate_rep_args *args = baton; + dag_node_t *node, *pred_node; + + SVN_ERR(svn_fs_base__dag_get_node(&node, trail->fs, args->id, + trail, trail->pool)); + if (args->has_pred) + { + SVN_ERR(svn_fs_base__dag_get_node(&pred_node, trail->fs, args->pred_id, + trail, trail->pool)); + } + else + { + pred_node = NULL; + } + + SVN_ERR(svn_fs_base__dag_obliterate_rep(node, pred_node, trail, trail->pool)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_fs_base__obliterate_rep(svn_fs_t *fs, + const char *path, + svn_revnum_t revision, + apr_pool_t *pool) +{ + svn_fs_root_t *root; + const char *txn_id; + struct rev_get_txn_id_args get_txn_args; + const svn_fs_id_t *id; + svn_node_kind_t kind; + struct txn_pred_count_args pred_count_args; + struct txn_obliterate_rep_args oblit_args; + + SVN_ERR(svn_fs_base__revision_root(&root, fs, revision, pool)); + get_txn_args.txn_id = &txn_id; + get_txn_args.revision = revision; + SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_rev_get_txn_id, &get_txn_args, + FALSE, pool)); + + SVN_ERR(base_node_id(&id, root, path, pool)); + if (strcmp(svn_fs_base__id_txn_id(id), txn_id)) + return svn_error_createf(SVN_ERR_FS_NOT_MUTABLE, NULL, + _("Unexpected immutable node at '%s'"), path); + + SVN_ERR(base_check_path(&kind, root, path, pool)); + if (kind != svn_node_file) + return svn_error_createf(SVN_ERR_FS_NOT_FILE, NULL, + _("Cannot obliterate '%s' as it is not a file"), + path); + + pred_count_args.id = id; + SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_pred_count, &pred_count_args, + FALSE, pool)); + + if (pred_count_args.pred_count > 0) + { + struct txn_pred_id_args pred_id_args; + + pred_id_args.id = id; + pred_id_args.pool = pool; + SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_pred_id, &pred_id_args, + FALSE, pool)); + + oblit_args.has_pred = TRUE; + oblit_args.pred_id = pred_id_args.pred_id; + } + else + { + oblit_args.has_pred = FALSE; + } + oblit_args.id = id; + + return svn_fs_base__retry_txn(fs, txn_body_obliterate_rep, &oblit_args, + TRUE, pool); +} + + /* Modifying directories */