static svn_error_t * write_new_rep(const svn_test_opts_t *opts, apr_pool_t *pool) { struct rep_args args; const char *rep = "((fulltext 0 ) a83t2Z0q)"; svn_fs_t *fs; /* Create a new fs and repos */ SVN_ERR(svn_test__create_bdb_fs (&fs, "test-repo-write-new-rep", opts, pool)); /* Set up transaction baton */ args.fs = fs; args.skel = svn_skel__parse(rep, strlen(rep), pool); args.key = NULL; /* Write new rep to reps table. */ SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_write_new_rep, &args, FALSE, pool)); if (args.key == NULL) return svn_error_create(SVN_ERR_FS_GENERAL, NULL, "error writing new representation"); return SVN_NO_ERROR; }
svn_error_t * svn_fs_bdb__read_rep(representation_t **rep_p, svn_fs_t *fs, const char *key, trail_t *trail, apr_pool_t *pool) { base_fs_data_t *bfd = fs->fsap_data; svn_skel_t *skel; int db_err; DBT query, result; svn_fs_base__trail_debug(trail, "representations", "get"); db_err = bfd->representations->get(bfd->representations, trail->db_txn, svn_fs_base__str_to_dbt(&query, key), svn_fs_base__result_dbt(&result), 0); svn_fs_base__track_dbt(&result, pool); /* 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_REPRESENTATION, 0, _("No such representation '%s'"), key); /* Handle any other error conditions. */ SVN_ERR(BDB_WRAP(fs, _("reading representation"), db_err)); /* Parse the REPRESENTATION skel. */ skel = svn_skel__parse(result.data, result.size, pool); /* Convert to a native type. */ return svn_fs_base__parse_representation_skel(rep_p, skel, pool); }
static svn_error_t * write_rep(const svn_test_opts_t *opts, apr_pool_t *pool) { struct rep_args new_args; struct rep_args args; const char *new_rep = "((fulltext 0 ) a83t2Z0q)"; const char *rep = "((fulltext 0 ) kfogel31337)"; svn_fs_t *fs; /* Create a new fs and repos */ SVN_ERR(svn_test__create_bdb_fs (&fs, "test-repo-write-rep", opts, pool)); /* Set up transaction baton */ new_args.fs = fs; new_args.skel = svn_skel__parse(new_rep, strlen(new_rep), pool); new_args.key = NULL; /* Write new rep to reps table. */ SVN_ERR(svn_fs_base__retry_txn(new_args.fs, txn_body_write_new_rep, &new_args, FALSE, pool)); /* Make sure we got a valid key. */ if (new_args.key == NULL) return svn_error_create(SVN_ERR_FS_GENERAL, NULL, "error writing new representation"); /* Set up transaction baton for re-writing reps. */ args.fs = new_args.fs; args.skel = svn_skel__parse(rep, strlen(rep), pool); args.key = new_args.key; /* Overwrite first rep in reps table. */ SVN_ERR(svn_fs_base__retry_txn(new_args.fs, txn_body_write_rep, &args, FALSE, pool)); return SVN_NO_ERROR; }
static svn_error_t * delete_rep(const svn_test_opts_t *opts, apr_pool_t *pool) { struct rep_args new_args; struct rep_args delete_args; struct rep_args read_args; const char *new_rep = "((fulltext 0 ) a83t2Z0q)"; svn_fs_t *fs; svn_error_t *err; /* Create a new fs and repos */ SVN_ERR(svn_test__create_bdb_fs (&fs, "test-repo-delete-rep", opts, pool)); /* Set up transaction baton */ new_args.fs = fs; new_args.skel = svn_skel__parse(new_rep, strlen(new_rep), pool); new_args.key = NULL; /* Write new rep to reps table. */ SVN_ERR(svn_fs_base__retry_txn(new_args.fs, txn_body_write_new_rep, &new_args, FALSE, pool)); /* Make sure we got a valid key. */ if (new_args.key == NULL) return svn_error_create(SVN_ERR_FS_GENERAL, NULL, "error writing new representation"); /* Delete the rep we just wrote. */ delete_args.fs = new_args.fs; delete_args.key = new_args.key; SVN_ERR(svn_fs_base__retry_txn(new_args.fs, txn_body_delete_rep, &delete_args, FALSE, pool)); /* Try to read the new rep back from the reps table. */ read_args.fs = new_args.fs; read_args.skel = NULL; read_args.key = new_args.key; err = svn_fs_base__retry_txn(new_args.fs, txn_body_read_rep, &read_args, FALSE, pool); /* We better have an error... */ if ((! err) && (read_args.skel)) return svn_error_create(SVN_ERR_FS_GENERAL, NULL, "error deleting representation"); svn_error_clear(err); return SVN_NO_ERROR; }
/* Parse SKEL_CSTR according to the description in USAGE_MSG. */ static svn_error_t * extract_values_from_skel(svn_string_t **old_propval_p, svn_string_t **propval_p, const char *skel_cstr, apr_pool_t *pool) { apr_hash_t *proplist; svn_skel_t *skel; skel = svn_skel__parse(skel_cstr, strlen(skel_cstr), pool); SVN_ERR(svn_skel__parse_proplist(&proplist, skel, pool)); *old_propval_p = apr_hash_get(proplist, KEY_OLD_PROPVAL, APR_HASH_KEY_STRING); *propval_p = apr_hash_get(proplist, KEY_NEW_PROPVAL, APR_HASH_KEY_STRING); return SVN_NO_ERROR; }
svn_error_t * svn_fs_bdb__lock_get(svn_lock_t **lock_p, svn_fs_t *fs, const char *lock_token, trail_t *trail, apr_pool_t *pool) { base_fs_data_t *bfd = fs->fsap_data; DBT key, value; int db_err; svn_skel_t *skel; svn_lock_t *lock; svn_fs_base__trail_debug(trail, "lock", "get"); db_err = bfd->locks->get(bfd->locks, trail->db_txn, svn_fs_base__str_to_dbt(&key, lock_token), svn_fs_base__result_dbt(&value), 0); svn_fs_base__track_dbt(&value, pool); if (db_err == DB_NOTFOUND) return svn_fs_base__err_bad_lock_token(fs, lock_token); SVN_ERR(BDB_WRAP(fs, "reading lock", db_err)); /* Parse TRANSACTION skel */ skel = svn_skel__parse(value.data, value.size, pool); if (! skel) return svn_fs_base__err_corrupt_lock(fs, lock_token); /* Convert skel to native type. */ SVN_ERR(svn_fs_base__parse_lock_skel(&lock, skel, pool)); /* Possibly auto-expire the lock. */ if (lock->expiration_date && (apr_time_now() > lock->expiration_date)) { SVN_ERR(svn_fs_bdb__lock_delete(fs, lock_token, trail, pool)); return SVN_FS__ERR_LOCK_EXPIRED(fs, lock_token); } *lock_p = lock; return SVN_NO_ERROR; }
svn_error_t * svn_fs_bdb__get_node_revision(node_revision_t **noderev_p, svn_fs_t *fs, const svn_fs_id_t *id, trail_t *trail, apr_pool_t *pool) { base_fs_data_t *bfd = fs->fsap_data; node_revision_t *noderev; svn_skel_t *skel; int db_err; DBT key, value; svn_fs_base__trail_debug(trail, "nodes", "get"); db_err = bfd->nodes->get(bfd->nodes, trail->db_txn, svn_fs_base__id_to_dbt(&key, id, pool), svn_fs_base__result_dbt(&value), 0); svn_fs_base__track_dbt(&value, pool); /* If there's no such node, return an appropriately specific error. */ if (db_err == DB_NOTFOUND) return svn_fs_base__err_dangling_id(fs, id); /* Handle any other error conditions. */ SVN_ERR(BDB_WRAP(fs, N_("reading node revision"), db_err)); /* If our caller doesn't really care about the return value here, just return successfully. */ if (! noderev_p) return SVN_NO_ERROR; /* Parse and the NODE-REVISION skel. */ skel = svn_skel__parse(value.data, value.size, pool); /* Convert to a native FS type. */ SVN_ERR(svn_fs_base__parse_node_revision_skel(&noderev, skel, pool)); *noderev_p = noderev; return SVN_NO_ERROR; }
svn_error_t * svn_sqlite__column_properties(apr_hash_t **props, svn_sqlite__stmt_t *stmt, int column, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { apr_size_t len; const void *val; /* svn_skel__parse_proplist copies everything needed to result_pool */ val = svn_sqlite__column_blob(stmt, column, &len, NULL); if (val == NULL) { *props = NULL; return SVN_NO_ERROR; } SVN_ERR(svn_skel__parse_proplist(props, svn_skel__parse(val, len, scratch_pool), result_pool)); return SVN_NO_ERROR; }
svn_error_t * svn_fs_bdb__get_copy(copy_t **copy_p, svn_fs_t *fs, const char *copy_id, trail_t *trail, apr_pool_t *pool) { base_fs_data_t *bfd = fs->fsap_data; DBT key, value; int db_err; svn_skel_t *skel; copy_t *copy; /* Only in the context of this function do we know that the DB call will not attempt to modify copy_id, so the cast belongs here. */ svn_fs_base__trail_debug(trail, "copies", "get"); db_err = bfd->copies->get(bfd->copies, trail->db_txn, svn_fs_base__str_to_dbt(&key, copy_id), svn_fs_base__result_dbt(&value), 0); svn_fs_base__track_dbt(&value, pool); if (db_err == DB_NOTFOUND) return svn_fs_base__err_no_such_copy(fs, copy_id); SVN_ERR(BDB_WRAP(fs, N_("reading copy"), db_err)); /* Unparse COPY skel */ skel = svn_skel__parse(value.data, value.size, pool); if (! skel) return svn_fs_base__err_corrupt_copy(fs, copy_id); /* Convert skel to native type. */ SVN_ERR(svn_fs_base__parse_copy_skel(©, skel, pool)); *copy_p = copy; return SVN_NO_ERROR; }
svn_error_t * svn_fs_bdb__get_txn(transaction_t **txn_p, svn_fs_t *fs, const char *txn_name, trail_t *trail, apr_pool_t *pool) { base_fs_data_t *bfd = fs->fsap_data; DBT key, value; int db_err; svn_skel_t *skel; transaction_t *transaction; /* Only in the context of this function do we know that the DB call will not attempt to modify txn_name, so the cast belongs here. */ svn_fs_base__trail_debug(trail, "transactions", "get"); db_err = bfd->transactions->get(bfd->transactions, trail->db_txn, svn_fs_base__str_to_dbt(&key, txn_name), svn_fs_base__result_dbt(&value), 0); svn_fs_base__track_dbt(&value, pool); if (db_err == DB_NOTFOUND) return svn_fs_base__err_no_such_txn(fs, txn_name); SVN_ERR(BDB_WRAP(fs, "reading transaction", db_err)); /* Parse TRANSACTION skel */ skel = svn_skel__parse(value.data, value.size, pool); if (! skel) return svn_fs_base__err_corrupt_txn(fs, txn_name); /* Convert skel to native type. */ SVN_ERR(svn_fs_base__parse_transaction_skel(&transaction, skel, pool)); *txn_p = transaction; return SVN_NO_ERROR; }
/* Parse a skeleton from a Subversion string. */ static svn_skel_t * parse_str(svn_stringbuf_t *str, apr_pool_t *pool) { return svn_skel__parse(str->data, str->len, pool); }
svn_error_t * svn_fs_bdb__changes_fetch_raw(apr_array_header_t **changes_p, svn_fs_t *fs, const char *key, trail_t *trail, apr_pool_t *pool) { base_fs_data_t *bfd = fs->fsap_data; DBC *cursor; DBT query, result; int db_err = 0, db_c_err = 0; svn_error_t *err = SVN_NO_ERROR; change_t *change; apr_array_header_t *changes = apr_array_make(pool, 4, sizeof(change)); /* Get a cursor on the first record matching KEY, and then loop over the records, adding them to the return array. */ svn_fs_base__trail_debug(trail, "changes", "cursor"); SVN_ERR(BDB_WRAP(fs, N_("creating cursor for reading changes"), bfd->changes->cursor(bfd->changes, trail->db_txn, &cursor, 0))); /* Advance the cursor to the key that we're looking for. */ svn_fs_base__str_to_dbt(&query, key); svn_fs_base__result_dbt(&result); db_err = svn_bdb_dbc_get(cursor, &query, &result, DB_SET); if (! db_err) svn_fs_base__track_dbt(&result, pool); while (! db_err) { svn_skel_t *result_skel; /* RESULT now contains a change record associated with KEY. We need to parse that skel into an change_t structure ... */ result_skel = svn_skel__parse(result.data, result.size, pool); if (! result_skel) { err = svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Error reading changes for key '%s'"), key); goto cleanup; } err = svn_fs_base__parse_change_skel(&change, result_skel, pool); if (err) goto cleanup; /* ... and add it to our return array. */ APR_ARRAY_PUSH(changes, change_t *) = change; /* Advance the cursor to the next record with this same KEY, and fetch that record. */ svn_fs_base__result_dbt(&result); db_err = svn_bdb_dbc_get(cursor, &query, &result, DB_NEXT_DUP); if (! db_err) svn_fs_base__track_dbt(&result, pool); } /* If there are no (more) change records for this KEY, we're finished. Just return the (possibly empty) array. Any other error, however, needs to get handled appropriately. */ if (db_err && (db_err != DB_NOTFOUND)) err = BDB_WRAP(fs, N_("fetching changes"), db_err); cleanup: /* Close the cursor. */ db_c_err = svn_bdb_dbc_close(cursor); /* If we had an error prior to closing the cursor, return the error. */ if (err) return svn_error_trace(err); /* If our only error thus far was when we closed the cursor, return that error. */ if (db_c_err) SVN_ERR(BDB_WRAP(fs, N_("closing changes cursor"), db_c_err)); /* Finally, set our return variable and get outta here. */ *changes_p = changes; return SVN_NO_ERROR; }
svn_error_t * svn_fs_bdb__changes_fetch(apr_hash_t **changes_p, svn_fs_t *fs, const char *key, trail_t *trail, apr_pool_t *pool) { base_fs_data_t *bfd = fs->fsap_data; DBC *cursor; DBT query, result; int db_err = 0, db_c_err = 0; svn_error_t *err = SVN_NO_ERROR; apr_hash_t *changes = apr_hash_make(pool); apr_pool_t *subpool = svn_pool_create(pool); /* Get a cursor on the first record matching KEY, and then loop over the records, adding them to the return array. */ svn_fs_base__trail_debug(trail, "changes", "cursor"); SVN_ERR(BDB_WRAP(fs, N_("creating cursor for reading changes"), bfd->changes->cursor(bfd->changes, trail->db_txn, &cursor, 0))); /* Advance the cursor to the key that we're looking for. */ svn_fs_base__str_to_dbt(&query, key); svn_fs_base__result_dbt(&result); db_err = svn_bdb_dbc_get(cursor, &query, &result, DB_SET); if (! db_err) svn_fs_base__track_dbt(&result, pool); while (! db_err) { change_t *change; svn_skel_t *result_skel; /* Clear the per-iteration subpool. */ svn_pool_clear(subpool); /* RESULT now contains a change record associated with KEY. We need to parse that skel into an change_t structure ... */ result_skel = svn_skel__parse(result.data, result.size, subpool); if (! result_skel) { err = svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Error reading changes for key '%s'"), key); goto cleanup; } err = svn_fs_base__parse_change_skel(&change, result_skel, subpool); if (err) goto cleanup; /* ... and merge it with our return hash. */ err = fold_change(changes, change); if (err) goto cleanup; /* Now, if our change was a deletion or replacement, we have to blow away any changes thus far on paths that are (or, were) children of this path. ### i won't bother with another iteration pool here -- at most we talking about a few extra dups of paths into what is already a temporary subpool. */ if ((change->kind == svn_fs_path_change_delete) || (change->kind == svn_fs_path_change_replace)) { apr_hash_index_t *hi; for (hi = apr_hash_first(subpool, changes); hi; hi = apr_hash_next(hi)) { /* KEY is the path. */ const void *hashkey; apr_ssize_t klen; const char *child_relpath; apr_hash_this(hi, &hashkey, &klen, NULL); /* If we come across our own path, ignore it. If we come across a child of our path, remove it. */ child_relpath = svn_fspath__skip_ancestor(change->path, hashkey); if (child_relpath && *child_relpath) apr_hash_set(changes, hashkey, klen, NULL); } } /* Advance the cursor to the next record with this same KEY, and fetch that record. */ svn_fs_base__result_dbt(&result); db_err = svn_bdb_dbc_get(cursor, &query, &result, DB_NEXT_DUP); if (! db_err) svn_fs_base__track_dbt(&result, pool); } /* Destroy the per-iteration subpool. */ svn_pool_destroy(subpool); /* If there are no (more) change records for this KEY, we're finished. Just return the (possibly empty) array. Any other error, however, needs to get handled appropriately. */ if (db_err && (db_err != DB_NOTFOUND)) err = BDB_WRAP(fs, N_("fetching changes"), db_err); cleanup: /* Close the cursor. */ db_c_err = svn_bdb_dbc_close(cursor); /* If we had an error prior to closing the cursor, return the error. */ if (err) return svn_error_trace(err); /* If our only error thus far was when we closed the cursor, return that error. */ if (db_c_err) SVN_ERR(BDB_WRAP(fs, N_("closing changes cursor"), db_c_err)); /* Finally, set our return variable and get outta here. */ *changes_p = changes; return SVN_NO_ERROR; }
static svn_error_t * unparse_list(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "unparse lists"; if (msg_only) return SVN_NO_ERROR; /* Make a list of all the single-byte implicit-length atoms. */ { svn_stringbuf_t *str = get_empty_string(pool); int byte; svn_skel_t *list = empty(pool); svn_skel_t *reparsed, *elt; for (byte = 0; byte < 256; byte++) if (skel_is_name( (apr_byte_t)byte)) { char buf = byte; add(build_atom(1, &buf, pool), list); } /* Unparse that, parse it again, and see if we got the same thing back. */ str = svn_skel__unparse(list, pool); reparsed = svn_skel__parse(str->data, str->len, pool); if (! reparsed || reparsed->is_atom) return fail(pool, "result is syntactically misformed, or not a list"); if (! skel_equal(list, reparsed)) return fail(pool, "unparsing and parsing didn't preserve contents"); elt = reparsed->children; for (byte = 255; byte >= 0; byte--) if (skel_is_name( (apr_byte_t)byte)) { if (! (elt && elt->is_atom && elt->len == 1 && elt->data[0] == byte)) return fail(pool, "bad element"); /* Verify that each element's data falls within the string. */ if (elt->data < str->data || elt->data + elt->len > str->data + str->len) return fail(pool, "bad element"); elt = elt->next; } /* We should have reached the end of the list at this point. */ if (elt) return fail(pool, "list too long"); } /* Make a list of lists. */ { svn_stringbuf_t *str = get_empty_string(pool); svn_skel_t *top = empty(pool); svn_skel_t *reparsed; int i; for (i = 0; i < 10; i++) { svn_skel_t *middle = empty(pool); int j; for (j = 0; j < 10; j++) { char buf[10]; apr_size_t k; int val; /* Make some interesting atom, containing lots of binary characters. */ val = i * 10 + j; for (k = 0; k < sizeof(buf); k++) { buf[k] = val; val += j; } add(build_atom(sizeof(buf), buf, pool), middle); } add(middle, top); } str = svn_skel__unparse(top, pool); reparsed = svn_skel__parse(str->data, str->len, pool); if (! skel_equal(top, reparsed)) return fail(pool, "failed to reparse list of lists"); } return SVN_NO_ERROR; }
static svn_error_t * read_rep(const svn_test_opts_t *opts, apr_pool_t *pool) { struct rep_args new_args; struct rep_args args; struct rep_args read_args; svn_stringbuf_t *skel_data; svn_fs_t *fs; const char *rep = "((fulltext 0 ) kfogel31337)"; const char *new_rep_before = "((fulltext 0 ) a83t2Z0)"; /* This test also tests the introduction of checksums into skels that didn't have them. */ /* Get writeable strings. */ char *rep_after = apr_pstrdup (pool, "((fulltext 0 (md5 16 XXXXXXXXXXXXXXXX)) kfogel31337"); char *new_rep_after = apr_pstrdup (pool, "((fulltext 0 (md5 16 XXXXXXXXXXXXXXXX)) a83t2Z0"); size_t rep_after_len = strlen(rep_after); size_t new_rep_after_len = strlen(new_rep_after); /* Replace the fake fake checksums with the real fake checksums. And someday, when checksums are actually calculated, we can replace the real fake checksums with real real checksums. */ { char *p; for (p = rep_after; *p; p++) if (*p == 'X') *p = '\0'; for (p = new_rep_after; *p; p++) if (*p == 'X') *p = '\0'; } /* Create a new fs and repos */ SVN_ERR(svn_test__create_bdb_fs (&fs, "test-repo-read-rep", opts, pool)); /* Set up transaction baton */ new_args.fs = fs; new_args.skel = svn_skel__parse(new_rep_before, strlen(new_rep_before), pool); new_args.key = NULL; /* Write new rep to reps table. */ SVN_ERR(svn_fs_base__retry_txn(new_args.fs, txn_body_write_new_rep, &new_args, FALSE, pool)); /* Make sure we got a valid key. */ if (new_args.key == NULL) return svn_error_create(SVN_ERR_FS_GENERAL, NULL, "error writing new representation"); /* Read the new rep back from the reps table. */ read_args.fs = new_args.fs; read_args.skel = NULL; read_args.key = new_args.key; SVN_ERR(svn_fs_base__retry_txn(new_args.fs, txn_body_read_rep, &read_args, FALSE, pool)); /* Make sure the skel matches. */ if (! read_args.skel) return svn_error_create(SVN_ERR_FS_GENERAL, NULL, "error reading new representation"); skel_data = svn_skel__unparse(read_args.skel, pool); if (memcmp(skel_data->data, new_rep_after, new_rep_after_len) != 0) return svn_error_createf(SVN_ERR_FS_GENERAL, NULL, "representation corrupted (first check)"); /* Set up transaction baton for re-writing reps. */ args.fs = new_args.fs; args.skel = svn_skel__parse(rep, strlen(rep), pool); args.key = new_args.key; /* Overwrite first rep in reps table. */ SVN_ERR(svn_fs_base__retry_txn(new_args.fs, txn_body_write_rep, &args, FALSE, pool)); /* Read the new rep back from the reps table (using the same FS and key as the first read...let's make sure this thing didn't get written to the wrong place). */ read_args.skel = NULL; SVN_ERR(svn_fs_base__retry_txn(new_args.fs, txn_body_read_rep, &read_args, FALSE, pool)); /* Make sure the skel matches. */ if (! read_args.skel) return svn_error_create(SVN_ERR_FS_GENERAL, NULL, "error reading new representation"); skel_data = svn_skel__unparse(read_args.skel, pool); if (memcmp(skel_data->data, rep_after, rep_after_len) != 0) return svn_error_createf(SVN_ERR_FS_GENERAL, NULL, "representation corrupted (second check)"); return SVN_NO_ERROR; }
/* Parse a skeleton from a C string. */ static svn_skel_t * parse_cstr(const char *str, apr_pool_t *pool) { return svn_skel__parse(str, strlen(str), pool); }
svn_error_t * svn_fs_bdb__get_txn_list(apr_array_header_t **names_p, svn_fs_t *fs, trail_t *trail, apr_pool_t *pool) { base_fs_data_t *bfd = fs->fsap_data; apr_size_t const next_key_key_len = strlen(NEXT_KEY_KEY); apr_pool_t *subpool = svn_pool_create(pool); apr_array_header_t *names; DBC *cursor; DBT key, value; int db_err, db_c_err; /* Allocate the initial names array */ names = apr_array_make(pool, 4, sizeof(const char *)); /* Create a database cursor to list the transaction names. */ svn_fs_base__trail_debug(trail, "transactions", "cursor"); SVN_ERR(BDB_WRAP(fs, "reading transaction list (opening cursor)", bfd->transactions->cursor(bfd->transactions, trail->db_txn, &cursor, 0))); /* Build a null-terminated array of keys in the transactions table. */ for (db_err = svn_bdb_dbc_get(cursor, svn_fs_base__result_dbt(&key), svn_fs_base__result_dbt(&value), DB_FIRST); db_err == 0; db_err = svn_bdb_dbc_get(cursor, svn_fs_base__result_dbt(&key), svn_fs_base__result_dbt(&value), DB_NEXT)) { transaction_t *txn; svn_skel_t *txn_skel; svn_error_t *err; /* Clear the per-iteration subpool */ svn_pool_clear(subpool); /* Track the memory alloc'd for fetching the key and value here so that when the containing pool is cleared, this memory is freed. */ svn_fs_base__track_dbt(&key, subpool); svn_fs_base__track_dbt(&value, subpool); /* Ignore the "next-key" key. */ if (key.size == next_key_key_len && 0 == memcmp(key.data, NEXT_KEY_KEY, next_key_key_len)) continue; /* Parse TRANSACTION skel */ txn_skel = svn_skel__parse(value.data, value.size, subpool); if (! txn_skel) { svn_bdb_dbc_close(cursor); return svn_fs_base__err_corrupt_txn (fs, apr_pstrmemdup(pool, key.data, key.size)); } /* Convert skel to native type. */ if ((err = svn_fs_base__parse_transaction_skel(&txn, txn_skel, subpool))) { svn_bdb_dbc_close(cursor); return err; } /* If this is an immutable "committed" transaction, ignore it. */ if (is_committed(txn)) continue; /* Add the transaction name to the NAMES array, duping it into POOL. */ APR_ARRAY_PUSH(names, const char *) = apr_pstrmemdup(pool, key.data, key.size); } /* Check for errors, but close the cursor first. */ db_c_err = svn_bdb_dbc_close(cursor); if (db_err != DB_NOTFOUND) { SVN_ERR(BDB_WRAP(fs, "reading transaction list (listing keys)", db_err)); } SVN_ERR(BDB_WRAP(fs, "reading transaction list (closing cursor)", db_c_err)); /* Destroy the per-iteration subpool */ svn_pool_destroy(subpool); *names_p = names; return SVN_NO_ERROR; }