You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2015/11/09 12:06:43 UTC
svn commit: r1713386 - in /subversion/branches/move-tracking-2: ./
subversion/ subversion/include/ subversion/include/private/
subversion/libsvn_fs_fs/ subversion/libsvn_fs_x/ subversion/libsvn_subr/
subversion/mod_dav_svn/
Author: julianfoad
Date: Mon Nov 9 11:06:42 2015
New Revision: 1713386
URL: http://svn.apache.org/viewvc?rev=1713386&view=rev
Log:
On the 'move-tracking-2' branch: catch up to trunk@1713385.
Modified:
subversion/branches/move-tracking-2/ (props changed)
subversion/branches/move-tracking-2/subversion/ (props changed)
subversion/branches/move-tracking-2/subversion/include/private/svn_subr_private.h
subversion/branches/move-tracking-2/subversion/include/svn_error_codes.h
subversion/branches/move-tracking-2/subversion/include/svn_fs.h
subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/fs_fs.c
subversion/branches/move-tracking-2/subversion/libsvn_fs_x/ (props changed)
subversion/branches/move-tracking-2/subversion/libsvn_fs_x/cached_data.c
subversion/branches/move-tracking-2/subversion/libsvn_fs_x/caching.c
subversion/branches/move-tracking-2/subversion/libsvn_fs_x/fs.h
subversion/branches/move-tracking-2/subversion/libsvn_fs_x/recovery.c
subversion/branches/move-tracking-2/subversion/libsvn_fs_x/revprops.c
subversion/branches/move-tracking-2/subversion/libsvn_fs_x/transaction.c
subversion/branches/move-tracking-2/subversion/libsvn_fs_x/util.c
subversion/branches/move-tracking-2/subversion/libsvn_fs_x/util.h
subversion/branches/move-tracking-2/subversion/libsvn_subr/compress.c
subversion/branches/move-tracking-2/subversion/libsvn_subr/packed_data.c
subversion/branches/move-tracking-2/subversion/mod_dav_svn/util.c
Propchange: subversion/branches/move-tracking-2/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Nov 9 11:06:42 2015
@@ -94,4 +94,4 @@
/subversion/branches/verify-at-commit:1462039-1462408
/subversion/branches/verify-keep-going:1439280-1546110
/subversion/branches/wc-collate-path:1402685-1480384
-/subversion/trunk:1606692-1712079
+/subversion/trunk:1606692-1713385
Propchange: subversion/branches/move-tracking-2/subversion/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Nov 9 11:06:42 2015
@@ -82,4 +82,4 @@
/subversion/branches/verify-at-commit/subversion:1462039-1462408
/subversion/branches/verify-keep-going/subversion:1439280-1546110
/subversion/branches/wc-collate-path/subversion:1402685-1480384
-/subversion/trunk/subversion:1606692-1712079
+/subversion/trunk/subversion:1606692-1713385
Modified: subversion/branches/move-tracking-2/subversion/include/private/svn_subr_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/include/private/svn_subr_private.h?rev=1713386&r1=1713385&r2=1713386&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/include/private/svn_subr_private.h (original)
+++ subversion/branches/move-tracking-2/subversion/include/private/svn_subr_private.h Mon Nov 9 11:06:42 2015
@@ -525,6 +525,16 @@ svn_version__at_least(svn_version_t *ver
unsigned char *
svn__encode_uint(unsigned char *p, apr_uint64_t val);
+/* Wrapper around svn__encode_uint using the LSB to store the sign:
+ *
+ * If VAL >= 0
+ * UINT_VAL = 2 * VAL
+ * else
+ * UINT_VAL = (- 2 * VAL) - 1
+ */
+unsigned char *
+svn__encode_int(unsigned char *p, apr_int64_t val);
+
/* Decode an unsigned 7b/8b-encoded integer into *VAL and return a pointer
to the byte after the integer. The bytes to be decoded live in the
range [P..END-1]. If these bytes do not contain a whole encoded
@@ -537,6 +547,14 @@ svn__decode_uint(apr_uint64_t *val,
const unsigned char *p,
const unsigned char *end);
+/* Wrapper around svn__decode_uint, reversing the transformation performed
+ * by svn__encode_int.
+ */
+const unsigned char *
+svn__decode_int(apr_int64_t *val,
+ const unsigned char *p,
+ const unsigned char *end);
+
/* Compress the data from DATA with length LEN, it according to the
* specified COMPRESSION_METHOD and write the result to OUT.
* SVN__COMPRESSION_NONE is valid for COMPRESSION_METHOD.
Modified: subversion/branches/move-tracking-2/subversion/include/svn_error_codes.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/include/svn_error_codes.h?rev=1713386&r1=1713385&r2=1713386&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/include/svn_error_codes.h (original)
+++ subversion/branches/move-tracking-2/subversion/include/svn_error_codes.h Mon Nov 9 11:06:42 2015
@@ -868,6 +868,11 @@ SVN_ERROR_START
SVN_ERR_FS_CATEGORY_START + 63,
"Invalid generation number data.")
+ /** @since New in 1.10. */
+ SVN_ERRDEF(SVN_ERR_FS_CORRUPT_REVPROP_MANIFEST,
+ SVN_ERR_FS_CATEGORY_START + 64,
+ "Revprop manifest corrupt.")
+
/* repos errors */
SVN_ERRDEF(SVN_ERR_REPOS_LOCKED,
Modified: subversion/branches/move-tracking-2/subversion/include/svn_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/include/svn_fs.h?rev=1713386&r1=1713385&r2=1713386&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/include/svn_fs.h (original)
+++ subversion/branches/move-tracking-2/subversion/include/svn_fs.h Mon Nov 9 11:06:42 2015
@@ -1081,7 +1081,7 @@ svn_fs_unparse_id(const svn_fs_id_t *id,
* database. Each new transaction increments the counter. The
* current value of the counter is not serialized into a filesystem
* dump file, so dumping and restoring the repository will reset the
- * sequence and reuse transaction names.
+ * sequence and so may reuse transaction names.
*
* @defgroup svn_fs_txns Filesystem transactions
* @{
Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/fs_fs.c?rev=1713386&r1=1713385&r2=1713386&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/fs_fs.c Mon Nov 9 11:06:42 2015
@@ -1416,8 +1416,8 @@ svn_fs_fs__file_text_rep_equal(svn_boole
svn_stream_t *contents_a, *contents_b;
representation_t *rep_a = a->data_rep;
representation_t *rep_b = b->data_rep;
- svn_boolean_t a_empty = !rep_a || rep_a->expanded_size == 0;
- svn_boolean_t b_empty = !rep_b || rep_b->expanded_size == 0;
+ svn_boolean_t a_empty = !rep_a;
+ svn_boolean_t b_empty = !rep_b;
/* This makes sure that neither rep will be NULL later on */
if (a_empty && b_empty)
Propchange: subversion/branches/move-tracking-2/subversion/libsvn_fs_x/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Nov 9 11:06:42 2015
@@ -94,4 +94,4 @@
/subversion/branches/verify-keep-going/subversion/libsvn_fs_x:1439280-1492639,1546002-1546110
/subversion/branches/wc-collate-path/subversion/libsvn_fs_x:1402685-1480384
/subversion/trunk/subversion/libsvn_fs_fs:1415133-1596500,1596567,1597414,1597989,1598273,1599140,1600872,1601633,1603485-1603487,1603499,1603605,1604128,1604188,1604413-1604414,1604416-1604417,1604421,1604442,1604700,1604717,1604720,1604726,1604755,1604794,1604802,1604824,1604836,1604844,1604902-1604903,1604911,1604925,1604933,1604947,1605059-1605060,1605064-1605065,1605068,1605071-1605073,1605075,1605123,1605188-1605189,1605191,1605197,1605444,1605633,1606132,1606142,1606144,1606514,1606526,1606528,1606551,1606554,1606564,1606598-1606599,1606656,1606658,1606662,1606744,1606840,1607085,1607572,1612407,1612810,1613339,1613872,1614611,1615348,1615351-1615352,1615356,1616338-1616339,1616613,1617586,1617688,1618138,1618151,1618153,1618226,1618641,1618653,1618662,1619068,1619358,1619413,1619769,1619774,1620602,1620909,1620912,1620928,1620930,1621275,1621635,1622931,1622937,1622942,1622946,1622959-1622960,1622963,1622987,1623007,1623368,1623373,1623377,1623379,1623381,1623398,1623402,162
4011,1624265,1624512,1626246,1626871,1626873,1626886,1627497-1627498,1627502,1627947-1627949,1627966,1628083,1628093,1628158-1628159,1628161,1628392-1628393,1628415,1628427,1628676,1628738,1628762,1628764,1629854-1629855,1629857,1629865,1629873,1629875,1629879,1630067,1630070,1631049-1631051,1631075,1631115,1631171,1631180,1631185-1631186,1631196-1631197,1631239-1631240,1631548,1631550,1631563,1631567,1631588,1631598,1632646,1632776,1632849,1632851-1632853,1632856-1632857,1632868,1632908,1632926,1633232,1633617-1633618,1634872,1634875,1634879-1634880,1634920,1636478,1636483,1636629,1636644,1637184,1637186,1637330,1637358,1637363,1637393,1639319,1639322,1639335,1639348,1639352,1639355,1639358,1639414,1639419,1639426,1639430,1639436,1639440,1639549,1640061-1640062,1640197,1640915,1640966,1641013,1643139,1643233,1645567,1646021,1646712,1646716,1647537,1647540-1647541,1647820,1647905,1648230,1648238,1648241-1648243,1648253,1648272,1648532,1648537-1648539,1648542,1648591,1648612,1649590,
1651567,1652068,1652076,1652441,1652451,1653608,1654932,1654934,1654937,1655635,1655649,1655651,1655664,1656176,1657525,1657972,1657978,1658482,1659212,1659217,1659314,1659509,1662668,1665318,1665854,1665894,1667090,1667101,1667538,1669743,1669746,1669749,1669945,1670139,1670953,1673170,1673197,1673202,1673204,1673445,1673454,1673685,1673689,1673875,1674165,1674341,1674400,1674404,1674631,1674669,1674673,1675396,1676667,1677431,1678149,1678151,1678718,1678725,1679169,1679907,1679920-1679924,1679926,1680347,1680460,1680464,1680476,1680819,1681949,1681966,1681974,1681994,1682008,1682076,1682086,1682093,1682259,1682265,1682739,1682864,1683311,1683330,1683378,1683544,1683553,1684047,1686232,1686542,1686546,1686554,1686557,1687061,1687064,1687070-1687071,1687074,1687078-1687079,1688270,1688425,1692650,1693886,1694489,1694848,1696171,1696185,1696627-1696628,1696630,1696758,1697372,1697381,1697387,1697393,1697403,1697405,1701017,1701053,1702600,1702922,1703069,1703142,1703237,1703240,17052
66,1705638,1705643,1705646,1705724,1705730,1705739,1706612,1706615,1706617,1706619,1706675-1706676,1706679,1706979-1706980,1707308,1707971-1707973,1707986,1707988-1707989,1708004
-/subversion/trunk/subversion/libsvn_fs_x:1414756-1509914,1606692-1712079
+/subversion/trunk/subversion/libsvn_fs_x:1414756-1509914,1606692-1713385
Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_x/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_x/cached_data.c?rev=1713386&r1=1713385&r2=1713386&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_x/cached_data.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_x/cached_data.c Mon Nov 9 11:06:42 2015
@@ -2366,108 +2366,107 @@ compare_dirent_name(const void *a,
return strcmp(lhs->name, rhs);
}
-/* Into ENTRIES, read all directories entries from the key-value text in
- * STREAM. If INCREMENTAL is TRUE, read until the end of the STREAM and
+/* Into ENTRIES, parse all directories entries from the serialized form in
+ * DATA. If INCREMENTAL is TRUE, read until the end of the STREAM and
* update the data. ID is provided for nicer error messages.
+ *
+ * The contents of DATA will be shared with the items in ENTRIES, i.e. it
+ * must not be modified afterwards and must remain valid as long as ENTRIES
+ * is valid. Use SCRATCH_POOL for temporary allocations.
*/
static svn_error_t *
-read_dir_entries(apr_array_header_t *entries,
- svn_stream_t *stream,
- svn_boolean_t incremental,
- const svn_fs_x__id_t *id,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+parse_dir_entries(apr_array_header_t **entries_p,
+ const svn_stringbuf_t *data,
+ svn_boolean_t incremental,
+ const svn_fs_x__id_t *id,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ const apr_byte_t *p = (const apr_byte_t *)data->data;
+ const apr_byte_t *end = p + data->len;
+ apr_uint64_t count;
apr_hash_t *hash = incremental ? svn_hash__make(scratch_pool) : NULL;
- const char *terminator = SVN_HASH_TERMINATOR;
-
- /* Read until the terminator (non-incremental) or the end of STREAM
- (incremental mode). In the latter mode, we use a temporary HASH
- to make updating and removing entries cheaper. */
- while (1)
- {
- svn_hash__entry_t entry;
- svn_fs_x__dirent_t *dirent;
- char *str;
+ apr_array_header_t *entries;
- svn_pool_clear(iterpool);
- SVN_ERR(svn_hash__read_entry(&entry, stream, terminator,
- incremental, iterpool));
-
- /* End of directory? */
- if (entry.key == NULL)
- {
- /* In incremental mode, we skip the terminator and read the
- increments following it until the end of the stream. */
- if (incremental && terminator)
- terminator = NULL;
- else
- break;
- }
+ /* Construct the resulting container. */
+ p = svn__decode_uint(&count, p, end);
+ if (count > INT_MAX)
+ return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+ _("Directory for '%s' is too large"),
+ svn_fs_x__id_unparse(id, scratch_pool)->data);
- /* Deleted entry? */
- if (entry.val == NULL)
- {
- /* We must be in incremental mode */
- assert(hash);
- apr_hash_set(hash, entry.key, entry.keylen, NULL);
- continue;
- }
+ entries = apr_array_make(result_pool, (int)count,
+ sizeof(svn_fs_x__dirent_t *));
- /* Add a new directory entry. */
+ while (p != end)
+ {
+ apr_size_t len;
+ svn_fs_x__dirent_t *dirent;
dirent = apr_pcalloc(result_pool, sizeof(*dirent));
- dirent->name = apr_pstrmemdup(result_pool, entry.key, entry.keylen);
- str = svn_cstring_tokenize(" ", &entry.val);
- if (str == NULL)
+ /* The part of the serialized entry that is not the name will be
+ * about 6 bytes or less. Since APR allocates with an 8 byte
+ * alignment (4 bytes loss on average per string), simply using
+ * the name string in DATA already gives us near-optimal memory
+ * usage. */
+ dirent->name = (const char *)p;
+ len = strlen(dirent->name);
+ p += len + 1;
+ if (p == end)
return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
- _("Directory entry corrupt in '%s'"),
- svn_fs_x__id_unparse(id, scratch_pool)->data);
+ _("Directory entry missing kind in '%s'"),
+ svn_fs_x__id_unparse(id, scratch_pool)->data);
- if (strcmp(str, SVN_FS_X__KIND_FILE) == 0)
- {
- dirent->kind = svn_node_file;
- }
- else if (strcmp(str, SVN_FS_X__KIND_DIR) == 0)
- {
- dirent->kind = svn_node_dir;
- }
- else
- {
- return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
- _("Directory entry corrupt in '%s'"),
- svn_fs_x__id_unparse(id, scratch_pool)->data);
- }
+ dirent->kind = (svn_node_kind_t)*(p++);
+ if (p == end)
+ return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+ _("Directory entry missing change set in '%s'"),
+ svn_fs_x__id_unparse(id, scratch_pool)->data);
- str = svn_cstring_tokenize(" ", &entry.val);
- if (str == NULL)
+ p = svn__decode_int(&dirent->id.change_set, p, end);
+ if (p == end)
return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
- _("Directory entry corrupt in '%s'"),
- svn_fs_x__id_unparse(id, scratch_pool)->data);
+ _("Directory entry missing item number in '%s'"),
+ svn_fs_x__id_unparse(id, scratch_pool)->data);
- SVN_ERR(svn_fs_x__id_parse(&dirent->id, str));
+ p = svn__decode_uint(&dirent->id.number, p, end);
/* In incremental mode, update the hash; otherwise, write to the
* final array. */
if (incremental)
- apr_hash_set(hash, dirent->name, entry.keylen, dirent);
+ {
+ /* Insertion / update or a deletion? */
+ if (svn_fs_x__id_used(&dirent->id))
+ apr_hash_set(hash, dirent->name, len, dirent);
+ else
+ apr_hash_set(hash, dirent->name, len, NULL);
+ }
else
- APR_ARRAY_PUSH(entries, svn_fs_x__dirent_t *) = dirent;
+ {
+ APR_ARRAY_PUSH(entries, svn_fs_x__dirent_t *) = dirent;
+ }
}
- /* Convert container to a sorted array. */
if (incremental)
{
+ /* Convert container into a sorted array. */
apr_hash_index_t *hi;
- for (hi = apr_hash_first(iterpool, hash); hi; hi = apr_hash_next(hi))
+ for (hi = apr_hash_first(scratch_pool, hash); hi; hi = apr_hash_next(hi))
APR_ARRAY_PUSH(entries, svn_fs_x__dirent_t *) = apr_hash_this_val(hi);
- }
- if (!sorted(entries))
- svn_sort__array(entries, compare_dirents);
+ if (!sorted(entries))
+ svn_sort__array(entries, compare_dirents);
+ }
+ else
+ {
+ /* Check that we read the expected amount of entries. */
+ if ((apr_uint64_t)entries->nelts != count)
+ return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+ _("Directory length mismatch in '%s'"),
+ svn_fs_x__id_unparse(id, scratch_pool)->data);
+ }
- svn_pool_destroy(iterpool);
+ *entries_p = entries;
return SVN_NO_ERROR;
}
@@ -2515,9 +2514,11 @@ get_dir_contents(svn_fs_x__dir_data_t *d
{
svn_stream_t *contents;
const svn_fs_x__id_t *id = &noderev->noderev_id;
+ apr_size_t len;
+ svn_stringbuf_t *text;
+ svn_boolean_t incremental;
/* Initialize the result. */
- dir->entries = apr_array_make(result_pool, 16, sizeof(svn_fs_x__dirent_t *));
dir->txn_filesize = SVN_INVALID_FILESIZE;
/* Read dir contents - unless there is none in which case we are done. */
@@ -2539,31 +2540,40 @@ get_dir_contents(svn_fs_x__dir_data_t *d
/* Obtain txn children file size. */
SVN_ERR(svn_io_file_size_get(&dir->txn_filesize, file, scratch_pool));
+ len = (apr_size_t)dir->txn_filesize;
+ /* Finally, provide stream access to FILE. */
contents = svn_stream_from_aprfile2(file, FALSE, scratch_pool);
- SVN_ERR(read_dir_entries(dir->entries, contents, TRUE, id,
- result_pool, scratch_pool));
- SVN_ERR(svn_stream_close(contents));
+ incremental = TRUE;
}
else if (noderev->data_rep)
{
- /* Undeltify content before parsing it. Otherwise, we could only
- * parse it byte-by-byte.
- */
- apr_size_t len = noderev->data_rep->expanded_size;
- svn_stringbuf_t *text;
-
/* The representation is immutable. Read it normally. */
+ len = noderev->data_rep->expanded_size;
SVN_ERR(svn_fs_x__get_contents(&contents, fs, noderev->data_rep,
FALSE, scratch_pool));
- SVN_ERR(svn_stringbuf_from_stream(&text, contents, len, scratch_pool));
- SVN_ERR(svn_stream_close(contents));
-
- /* de-serialize hash */
- contents = svn_stream_from_stringbuf(text, scratch_pool);
- SVN_ERR(read_dir_entries(dir->entries, contents, FALSE, id,
- result_pool, scratch_pool));
+ incremental = FALSE;
}
+ else
+ {
+ /* Empty representation == empty directory. */
+ dir->entries = apr_array_make(result_pool, 0,
+ sizeof(svn_fs_x__dirent_t *));
+ return SVN_NO_ERROR;
+ }
+
+ /* Read the whole stream contents into a single buffer.
+ * Due to our LEN hint, no allocation overhead occurs.
+ *
+ * Also, a large portion of TEXT will be file / dir names which we
+ * directly reference from DIR->ENTRIES instead of copying them.
+ * Hence, we need to use the RESULT_POOL here. */
+ SVN_ERR(svn_stringbuf_from_stream(&text, contents, len, result_pool));
+ SVN_ERR(svn_stream_close(contents));
+
+ /* de-serialize hash */
+ SVN_ERR(parse_dir_entries(&dir->entries, text, incremental, id,
+ result_pool, scratch_pool));
return SVN_NO_ERROR;
}
Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_x/caching.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_x/caching.c?rev=1713386&r1=1713385&r2=1713386&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_x/caching.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_x/caching.c Mon Nov 9 11:06:42 2015
@@ -370,6 +370,7 @@ svn_fs_x__initialize_caches(svn_fs_t *fs
svn_fs_x__data_t *ffd = fs->fsap_data;
const char *prefix = apr_pstrcat(scratch_pool,
"fsx:", fs->uuid,
+ "--", ffd->instance_id,
"/", normalize_key_part(fs->path,
scratch_pool),
":",
Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_x/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_x/fs.h?rev=1713386&r1=1713385&r2=1713386&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_x/fs.h (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_x/fs.h Mon Nov 9 11:06:42 2015
@@ -60,7 +60,6 @@ extern "C" {
#define PATH_TXNS_DIR "transactions" /* Directory of transactions */
#define PATH_TXN_PROTOS_DIR "txn-protorevs" /* Directory of proto-revs */
#define PATH_TXN_CURRENT "txn-current" /* File with next txn key */
-#define PATH_TXN_NEXT "txn-next" /* Will become txn-current */
#define PATH_TXN_CURRENT_LOCK "txn-current-lock" /* Lock for txn-current */
#define PATH_LOCKS_DIR "locks" /* Directory of locks */
#define PATH_MIN_UNPACKED_REV "min-unpacked-rev" /* Oldest revision which
@@ -403,9 +402,6 @@ typedef struct svn_fs_x__data_t
svn_error_t *(*svn_fs_open_)(svn_fs_t **, const char *, apr_hash_t *,
apr_pool_t *, apr_pool_t *);
- /* If not 0, this is a pre-allocated transaction ID that can just be
- used for a new txn without needing to consult 'txn-current'. */
- apr_uint64_t next_txn_id;
} svn_fs_x__data_t;
Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_x/recovery.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_x/recovery.c?rev=1713386&r1=1713385&r2=1713386&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_x/recovery.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_x/recovery.c Mon Nov 9 11:06:42 2015
@@ -22,6 +22,7 @@
#include "recovery.h"
+#include "svn_dirent_uri.h"
#include "svn_hash.h"
#include "svn_pools.h"
#include "private/svn_string_private.h"
@@ -106,6 +107,86 @@ recover_get_largest_revision(svn_fs_t *f
return SVN_NO_ERROR;
}
+/* Delete all files and sub-directories (recursively) of DIR_PATH but
+ leave DIR_PATH itself in place. Use SCRATCH_POOL for temporaries. */
+static svn_error_t *
+clear_directory(const char *dir_path,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_t *dirents;
+ apr_hash_index_t *hi;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+ SVN_ERR(svn_io_get_dirents3(&dirents, dir_path, TRUE, scratch_pool,
+ scratch_pool));
+
+ for (hi = apr_hash_first(scratch_pool, dirents);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *path;
+ const char *name;
+ svn_dirent_t *dirent;
+
+ svn_pool_clear(iterpool);
+ apr_hash_this(hi, (const void **)&name, NULL, (void **)&dirent);
+
+ path = svn_dirent_join(dir_path, name, iterpool);
+ if (dirent->kind == svn_node_dir)
+ SVN_ERR(svn_io_remove_dir2(path, TRUE, NULL, NULL, iterpool));
+ else
+ SVN_ERR(svn_io_remove_file2(path, TRUE, iterpool));
+ }
+
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
+/* Delete all uncommitted transaction data from FS.
+ Use SCRATCH_POOL for temporaries. */
+static svn_error_t *
+discard_transactions(svn_fs_t *fs,
+ apr_pool_t *scratch_pool)
+{
+ svn_fs_x__data_t *ffd = fs->fsap_data;
+ svn_fs_x__shared_data_t *ffsd = ffd->shared;
+
+ /* In case this FS has been opened more than once in this process,
+ we should purge their shared transaction data as well. We do the
+ same as abort_txn would, except that we don't expect all txn files
+ to be complete on disk. */
+ while (ffsd->txns)
+ {
+ svn_fs_x__shared_txn_data_t *txn = ffsd->txns;
+ ffsd->txns = txn->next;
+
+ svn_pool_destroy(txn->pool);
+ }
+
+ /* Remove anything from the transaction folders. */
+ SVN_ERR(clear_directory(svn_fs_x__path_txns_dir(fs, scratch_pool),
+ scratch_pool));
+ SVN_ERR(clear_directory(svn_fs_x__path_txn_proto_revs(fs, scratch_pool),
+ scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+/* Reset txn-current in FS. Use SCRATCH_POOL for temporaries. */
+static svn_error_t *
+reset_txn_number(svn_fs_t *fs,
+ apr_pool_t *scratch_pool)
+{
+ const char *initial_txn = "0\n";
+ SVN_ERR(svn_io_write_atomic2(svn_fs_x__path_txn_current(fs, scratch_pool),
+ initial_txn, strlen(initial_txn),
+ svn_fs_x__path_uuid(fs, scratch_pool),
+ FALSE, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
/* Baton used for recover_body below. */
typedef struct recover_baton_t {
svn_fs_t *fs;
@@ -136,6 +217,12 @@ recover_body(void *baton,
Bump the instance ID. */
SVN_ERR(svn_fs_x__set_uuid(fs, fs->uuid, NULL, TRUE, scratch_pool));
+ /* Because transactions are not resilient against system crashes,
+ any existing transaction is suspect (and would probably not be
+ reopened anyway). Get rid of those. */
+ SVN_ERR(discard_transactions(fs, scratch_pool));
+ SVN_ERR(reset_txn_number(fs, scratch_pool));
+
/* We need to know the largest revision in the filesystem. */
SVN_ERR(recover_get_largest_revision(fs, &max_rev, scratch_pool));
Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_x/revprops.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_x/revprops.c?rev=1713386&r1=1713385&r2=1713386&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_x/revprops.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_x/revprops.c Mon Nov 9 11:06:42 2015
@@ -32,6 +32,8 @@
#include "util.h"
#include "transaction.h"
+#include "private/svn_packed_data.h"
+#include "private/svn_sorts_private.h"
#include "private/svn_subr_private.h"
#include "private/svn_string_private.h"
#include "../libsvn_fs/fs-loader.h"
@@ -339,6 +341,18 @@ end_revprop_change(svn_fs_t *fs,
return SVN_NO_ERROR;
}
+/* Represents an entry in the packed revprop manifest.
+ * There is one such entry per pack file. */
+typedef struct manifest_entry_t
+{
+ /* First revision in the pack file. */
+ svn_revnum_t start_rev;
+
+ /* Tag (a counter) appended to the file name to distinguish it from
+ outdated ones. */
+ apr_uint64_t tag;
+} manifest_entry_t;
+
/* Container for all data required to access the packed revprop file
* for a given REVISION. This structure will be filled incrementally
* by read_pack_revprops() its sub-routines.
@@ -356,8 +370,8 @@ typedef struct packed_revprops_t
apr_size_t serialized_size;
- /* name of the pack file (without folder path) */
- const char *filename;
+ /* manifest entry describing the pack file */
+ manifest_entry_t entry;
/* packed shard folder path */
const char *folder;
@@ -365,9 +379,6 @@ typedef struct packed_revprops_t
/* sum of values in SIZES */
apr_size_t total_size;
- /* first revision in the pack (>= MANIFEST_START) */
- svn_revnum_t start_revision;
-
/* size of the revprops in PACKED_REVPROPS */
apr_array_header_t *sizes;
@@ -379,12 +390,8 @@ typedef struct packed_revprops_t
* in the pack, i.e. the pack content without header and compression */
svn_stringbuf_t *packed_revprops;
- /* First revision covered by MANIFEST.
- * Will equal the shard start revision or 1, for the 1st shard. */
- svn_revnum_t manifest_start;
-
/* content of the manifest.
- * Maps long(rev - MANIFEST_START) to const char* pack file name */
+ * Sorted list of manifest_entry_t. */
apr_array_header_t *manifest;
} packed_revprops_t;
@@ -469,17 +476,159 @@ read_non_packed_revprop(apr_hash_t **pro
return SVN_NO_ERROR;
}
-/* Return the minimum length of any packed revprop file name in REVPROPS. */
-static apr_size_t
-get_min_filename_len(packed_revprops_t *revprops)
-{
- char number_buffer[SVN_INT64_BUFFER_SIZE];
-
- /* The revprop filenames have the format <REV>.<COUNT> - with <REV> being
- * at least the first rev in the shard and <COUNT> having at least one
- * digit. Thus, the minimum is 2 + #decimal places in the start rev.
- */
- return svn__i64toa(number_buffer, revprops->manifest_start) + 2;
+/* Serialize the packed revprops MANIFEST into FILE.
+ * Use SCRATCH_POOL for temporary allocations.
+ */
+static svn_error_t *
+write_manifest(apr_file_t *file,
+ const apr_array_header_t *manifest,
+ apr_pool_t *scratch_pool)
+{
+ int i;
+ svn_checksum_t *checksum;
+ svn_stream_t *stream;
+ svn_packed__data_root_t *root = svn_packed__data_create_root(scratch_pool);
+
+ /* one top-level stream per struct element */
+ svn_packed__int_stream_t *start_rev_stream
+ = svn_packed__create_int_stream(root, TRUE, FALSE);
+ svn_packed__int_stream_t *tag_stream
+ = svn_packed__create_int_stream(root, FALSE, FALSE);
+
+ /* serialize ENTRIES */
+ for (i = 0; i < manifest->nelts; ++i)
+ {
+ manifest_entry_t *entry = &APR_ARRAY_IDX(manifest, i, manifest_entry_t);
+ svn_packed__add_uint(start_rev_stream, entry->start_rev);
+ svn_packed__add_uint(tag_stream, entry->tag);
+ }
+
+ /* Write to file and calculate the checksum. */
+ stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
+ stream = svn_checksum__wrap_write_stream(&checksum, stream,
+ svn_checksum_fnv1a_32x4,
+ scratch_pool);
+ SVN_ERR(svn_packed__data_write(stream, root, scratch_pool));
+ SVN_ERR(svn_stream_close(stream));
+
+ /* Append the checksum */
+ SVN_ERR(svn_io_file_write_full(file, checksum->digest,
+ svn_checksum_size(checksum), NULL,
+ scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+/* Read the packed revprops manifest from the CONTENT buffer and return it
+ * in *MANIFEST, allocated in RESULT_POOL. REVISION is the revision number
+ * to put into error messages. Use SCRATCH_POOL for temporary allocations.
+ */
+static svn_error_t *
+read_manifest(apr_array_header_t **manifest,
+ svn_stringbuf_t *content,
+ svn_revnum_t revision,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ apr_size_t data_len;
+ apr_size_t i;
+ apr_size_t count;
+
+ svn_stream_t *stream;
+ svn_packed__data_root_t *root;
+ svn_packed__int_stream_t *start_rev_stream;
+ svn_packed__int_stream_t *tag_stream;
+ const apr_byte_t *digest;
+ svn_checksum_t *actual, *expected;
+
+ /* Verify the checksum. */
+ if (content->len < sizeof(apr_uint32_t))
+ return svn_error_createf(SVN_ERR_FS_CORRUPT_REVPROP_MANIFEST, NULL,
+ "Revprop manifest too short for revision r%ld",
+ revision);
+
+ data_len = content->len - sizeof(apr_uint32_t);
+ digest = (apr_byte_t *)content->data + data_len;
+
+ expected = svn_checksum__from_digest_fnv1a_32x4(digest, scratch_pool);
+ SVN_ERR(svn_checksum(&actual, svn_checksum_fnv1a_32x4, content->data,
+ data_len, scratch_pool));
+
+ if (!svn_checksum_match(actual, expected))
+ SVN_ERR(svn_checksum_mismatch_err(expected, actual, scratch_pool,
+ _("checksum mismatch in revprop "
+ "manifest for revision r%ld"),
+ revision));
+
+ /* read everything from the buffer */
+ stream = svn_stream_from_stringbuf(content, scratch_pool);
+ SVN_ERR(svn_packed__data_read(&root, stream, result_pool, scratch_pool));
+
+ /* get streams */
+ start_rev_stream = svn_packed__first_int_stream(root);
+ tag_stream = svn_packed__next_int_stream(start_rev_stream);
+
+ /* read ids array */
+ count = svn_packed__int_count(start_rev_stream);
+ *manifest = apr_array_make(result_pool, (int)count,
+ sizeof(manifest_entry_t));
+
+ for (i = 0; i < count; ++i)
+ {
+ manifest_entry_t *entry = apr_array_push(*manifest);
+ entry->start_rev = (svn_revnum_t)svn_packed__get_int(start_rev_stream);
+ entry->tag = svn_packed__get_uint(tag_stream);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Implements the standard comparison function signature comparing the
+ * manifest_entry_t(lhs).start_rev to svn_revnum_t(rhs). */
+static int
+compare_entry_revision(const void *lhs,
+ const void *rhs)
+{
+ const manifest_entry_t *entry = lhs;
+ const svn_revnum_t *revision = rhs;
+
+ if (entry->start_rev < *revision)
+ return -1;
+
+ return entry->start_rev == *revision ? 0 : 1;
+}
+
+/* Return the index in MANIFEST that has the info for the pack file
+ * containing REVISION. */
+static int
+get_entry(apr_array_header_t *manifest,
+ svn_revnum_t revision)
+{
+ manifest_entry_t *entry;
+ int idx = svn_sort__bsearch_lower_bound(manifest, &revision,
+ compare_entry_revision);
+
+ assert(manifest->nelts > 0);
+ if (idx >= manifest->nelts)
+ return idx - 1;
+
+ entry = &APR_ARRAY_IDX(manifest, idx, manifest_entry_t);
+ if (entry->start_rev > revision && idx > 0)
+ return idx - 1;
+
+ return idx;
+}
+
+/* Return the full path of the revprop pack file given by ENTRY within
+ * REVPROPS. Allocate the result in RESULT_POOL. */
+static const char *
+get_revprop_pack_filepath(packed_revprops_t *revprops,
+ manifest_entry_t *entry,
+ apr_pool_t *result_pool)
+{
+ const char *filename = apr_psprintf(result_pool, "%ld.%" APR_UINT64_T_FMT,
+ entry->start_rev, entry->tag);
+ return svn_dirent_join(revprops->folder, filename, result_pool);
}
/* Given FS and REVPROPS->REVISION, fill the FILENAME, FOLDER and MANIFEST
@@ -495,98 +644,59 @@ get_revprop_packname(svn_fs_t *fs,
svn_fs_x__data_t *ffd = fs->fsap_data;
svn_stringbuf_t *content = NULL;
const char *manifest_file_path;
- int idx, rev_count;
- char *buffer, *buffer_end;
- const char **filenames, **filenames_end;
- apr_size_t min_filename_len;
+ int idx;
+ svn_revnum_t previous_start_rev;
+ int i;
/* Determine the dimensions. Rev 0 is excluded from the first shard. */
- rev_count = ffd->max_files_per_dir;
- revprops->manifest_start
+ int rev_count = ffd->max_files_per_dir;
+ svn_revnum_t manifest_start
= revprops->revision - (revprops->revision % rev_count);
- if (revprops->manifest_start == 0)
+ if (manifest_start == 0)
{
- ++revprops->manifest_start;
+ ++manifest_start;
--rev_count;
}
- revprops->manifest = apr_array_make(result_pool, rev_count,
- sizeof(const char*));
-
- /* No line in the file can be less than this number of chars long. */
- min_filename_len = get_min_filename_len(revprops);
-
/* Read the content of the manifest file */
revprops->folder = svn_fs_x__path_pack_shard(fs, revprops->revision,
result_pool);
manifest_file_path = svn_dirent_join(revprops->folder, PATH_MANIFEST,
result_pool);
-
SVN_ERR(svn_fs_x__read_content(&content, manifest_file_path, result_pool));
+ SVN_ERR(read_manifest(&revprops->manifest, content, revprops->revision,
+ result_pool, scratch_pool));
- /* There CONTENT must have a certain minimal size and there no
- * unterminated lines at the end of the file. Both guarantees also
- * simplify the parser loop below.
- */
- if ( content->len < rev_count * (min_filename_len + 1)
- || content->data[content->len - 1] != '\n')
- return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
- _("Packed revprop manifest for r%ld not "
- "properly terminated"), revprops->revision);
-
- /* Chop (parse) the manifest CONTENT into filenames, one per line.
- * We only have to replace all newlines with NUL and add all line
- * starts to REVPROPS->MANIFEST.
- *
- * There must be exactly REV_COUNT lines and that is the number of
- * lines we parse from BUFFER to FILENAMES. Set the end pointer for
- * the source BUFFER such that BUFFER+MIN_FILENAME_LEN is still valid
- * BUFFER_END is always valid due to CONTENT->LEN > MIN_FILENAME_LEN.
- *
- * Please note that this loop is performance critical for e.g. 'svn log'.
- * It is run 1000x per revprop access, i.e. per revision and about
- * 50 million times per sec (and CPU core).
- */
- for (filenames = (const char **)revprops->manifest->elts,
- filenames_end = filenames + rev_count,
- buffer = content->data,
- buffer_end = buffer + content->len - min_filename_len;
- (filenames < filenames_end) && (buffer < buffer_end);
- ++filenames)
- {
- /* BUFFER always points to the start of the next line / filename. */
- *filenames = buffer;
-
- /* Find the next EOL. This is guaranteed to stay within the CONTENT
- * buffer because we left enough room after BUFFER_END and we know
- * we will always see a newline as the last non-NUL char. */
- buffer += min_filename_len;
- while (*buffer != '\n')
- ++buffer;
-
- /* Found EOL. Turn it into the filename terminator and move BUFFER
- * to the start of the next line or CONTENT buffer end. */
- *buffer = '\0';
- ++buffer;
- }
-
- /* We must have reached the end of both buffers. */
- if (buffer < content->data + content->len)
- return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
- _("Packed revprop manifest for r%ld "
- "has too many entries"), revprops->revision);
-
- if (filenames < filenames_end)
- return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
- _("Packed revprop manifest for r%ld "
- "has too few entries"), revprops->revision);
-
- /* The target array has now exactly one entry per revision. */
- revprops->manifest->nelts = rev_count;
-
- /* Now get the file name */
- idx = (int)(revprops->revision - revprops->manifest_start);
- revprops->filename = APR_ARRAY_IDX(revprops->manifest, idx, const char*);
+ /* Verify the manifest data. */
+ if (revprops->manifest->nelts == 0)
+ return svn_error_createf(SVN_ERR_FS_CORRUPT_REVPROP_MANIFEST, NULL,
+ "Revprop manifest for r%ld is empty",
+ revprops->revision);
+
+ previous_start_rev = 0;
+ for (i = 0; i < revprops->manifest->nelts; ++i)
+ {
+ svn_revnum_t start_rev = APR_ARRAY_IDX(revprops->manifest, i,
+ manifest_entry_t).start_rev;
+ if ( start_rev < manifest_start
+ || start_rev >= manifest_start + rev_count)
+ return svn_error_createf(SVN_ERR_FS_CORRUPT_REVPROP_MANIFEST, NULL,
+ "Revprop manifest for r%ld contains "
+ "out-of-range revision r%ld",
+ revprops->revision, start_rev);
+
+ if (start_rev < previous_start_rev)
+ return svn_error_createf(SVN_ERR_FS_CORRUPT_REVPROP_MANIFEST, NULL,
+ "Entries in revprop manifest for r%ld "
+ "are not ordered", revprops->revision);
+
+ previous_start_rev = start_rev;
+ }
+
+ /* Now get the pack file description */
+ idx = get_entry(revprops->manifest, revprops->revision);
+ revprops->entry = APR_ARRAY_IDX(revprops->manifest, idx,
+ manifest_entry_t);
return SVN_NO_ERROR;
}
@@ -602,10 +712,9 @@ same_shard(svn_fs_t *fs,
return (r1 / ffd->max_files_per_dir) == (r2 / ffd->max_files_per_dir);
}
-/* Given FS and the full packed file content in REVPROPS->PACKED_REVPROPS,
- * fill the START_REVISION member, and make PACKED_REVPROPS point to the
- * first serialized revprop. If READ_ALL is set, initialize the SIZES
- * and OFFSETS members as well.
+/* Given FS and the full packed file content in REVPROPS->PACKED_REVPROPS
+ * and make PACKED_REVPROPS point to the first serialized revprop. If
+ * READ_ALL is set, initialize the SIZES and OFFSETS members as well.
*
* Parse the revprops for REVPROPS->REVISION and set the PROPERTIES as
* well as the SERIALIZED_SIZE member. If revprop caching has been
@@ -673,7 +782,7 @@ parse_packed_revprops(svn_fs_t *fs,
revprops->packed_revprops->blocksize = (apr_size_t)(uncompressed->blocksize - offset);
/* STREAM still points to the first entry in the sizes list. */
- revprops->start_revision = (svn_revnum_t)first_rev;
+ SVN_ERR_ASSERT(revprops->entry.start_rev = (svn_revnum_t)first_rev);
if (read_all)
{
/* Init / construct REVPROPS members. */
@@ -782,9 +891,8 @@ read_pack_revprop(packed_revprops_t **re
* Re-read the manifest and the pack file.
*/
SVN_ERR(get_revprop_packname(fs, result, result_pool, iterpool));
- file_path = svn_dirent_join(result->folder,
- result->filename,
- iterpool);
+ file_path = get_revprop_pack_filepath(result, &result->entry,
+ iterpool);
SVN_ERR(svn_fs_x__try_stringbuf_from_file(&result->packed_revprops,
&missing,
file_path,
@@ -1052,7 +1160,8 @@ repack_revprops(svn_fs_t *fs,
stream = svn_stream_from_stringbuf(uncompressed, scratch_pool);
/* write the header*/
- SVN_ERR(serialize_revprops_header(stream, revprops->start_revision + start,
+ SVN_ERR(serialize_revprops_header(stream,
+ revprops->entry.start_rev + start,
revprops->sizes, start, end,
scratch_pool));
@@ -1093,9 +1202,8 @@ repack_revprops(svn_fs_t *fs,
return SVN_NO_ERROR;
}
-/* Allocate a new pack file name for revisions
- * [REVPROPS->START_REVISION + START, REVPROPS->START_REVISION + END - 1]
- * of REVPROPS->MANIFEST. Add the name of old file to FILES_TO_DELETE,
+/* Allocate a new pack file name for revisions starting at START_REV in
+ * REVPROPS->MANIFEST. Add the name of old file to FILES_TO_DELETE,
* auto-create that array if necessary. Return an open file *FILE that is
* allocated in RESULT_POOL. Allocate the paths in *FILES_TO_DELETE from
* the same pool that contains the array itself. Schedule necessary fsync
@@ -1107,55 +1215,43 @@ static svn_error_t *
repack_file_open(apr_file_t **file,
svn_fs_t *fs,
packed_revprops_t *revprops,
- int start,
- int end,
+ svn_revnum_t start_rev,
apr_array_header_t **files_to_delete,
svn_fs_x__batch_fsync_t *batch,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- apr_int64_t tag;
- const char *tag_string;
- svn_string_t *new_filename;
- int i;
- int manifest_offset
- = (int)(revprops->start_revision - revprops->manifest_start);
-
- /* get the old (= current) file name and enlist it for later deletion */
- const char *old_filename = APR_ARRAY_IDX(revprops->manifest,
- start + manifest_offset,
- const char*);
+ manifest_entry_t new_entry;
+ const char *new_path;
+ int idx;
+
+ /* We always replace whole pack files - possibly by more than one new file.
+ * When we create the file for the first part of the pack, enlist the old
+ * one for later deletion */
+ SVN_ERR_ASSERT(start_rev >= revprops->entry.start_rev);
if (*files_to_delete == NULL)
*files_to_delete = apr_array_make(result_pool, 3, sizeof(const char*));
- APR_ARRAY_PUSH(*files_to_delete, const char*)
- = svn_dirent_join(revprops->folder, old_filename,
- (*files_to_delete)->pool);
-
- /* increase the tag part, i.e. the counter after the dot */
- tag_string = strchr(old_filename, '.');
- if (tag_string == NULL)
- return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
- _("Packed file '%s' misses a tag"),
- old_filename);
-
- SVN_ERR(svn_cstring_atoi64(&tag, tag_string + 1));
- new_filename = svn_string_createf((*files_to_delete)->pool,
- "%ld.%" APR_INT64_T_FMT,
- revprops->start_revision + start,
- ++tag);
+ if (revprops->entry.start_rev == start_rev)
+ APR_ARRAY_PUSH(*files_to_delete, const char*)
+ = get_revprop_pack_filepath(revprops, &revprops->entry,
+ (*files_to_delete)->pool);
+
+ /* Initialize the new manifest entry. Bump the tag part. */
+ new_entry.start_rev = start_rev;
+ new_entry.tag = revprops->entry.tag + 1;
/* update the manifest to point to the new file */
- for (i = start; i < end; ++i)
- APR_ARRAY_IDX(revprops->manifest, i + manifest_offset, const char*)
- = new_filename->data;
+ idx = get_entry(revprops->manifest, start_rev);
+ if (revprops->entry.start_rev == start_rev)
+ APR_ARRAY_IDX(revprops->manifest, idx, manifest_entry_t) = new_entry;
+ else
+ svn_sort__array_insert(revprops->manifest, &new_path, idx + 1);
/* open the file */
- SVN_ERR(svn_fs_x__batch_fsync_open_file(file, batch,
- svn_dirent_join(revprops->folder,
- new_filename->data,
- scratch_pool),
+ new_path = get_revprop_pack_filepath(revprops, &new_entry, scratch_pool);
+ SVN_ERR(svn_fs_x__batch_fsync_open_file(file, batch, new_path,
scratch_pool));
return SVN_NO_ERROR;
@@ -1205,7 +1301,7 @@ write_packed_revprop(const char **final_
SVN_ERR(svn_stream_close(stream));
/* calculate the size of the new data */
- changed_index = (int)(rev - revprops->start_revision);
+ changed_index = (int)(rev - revprops->entry.start_rev);
new_total_size = revprops->total_size - revprops->serialized_size
+ serialized->len
+ (revprops->offsets->nelts + 2) * SVN_INT64_BUFFER_SIZE;
@@ -1219,8 +1315,8 @@ write_packed_revprop(const char **final_
/* simply replace the old pack file with new content as we do it
* in the non-packed case */
- *final_path = svn_dirent_join(revprops->folder, revprops->filename,
- result_pool);
+ *final_path = get_revprop_pack_filepath(revprops, &revprops->entry,
+ result_pool);
*tmp_path = apr_pstrcat(result_pool, *final_path, ".tmp", SVN_VA_NULL);
SVN_ERR(svn_fs_x__batch_fsync_open_file(&file, batch, *tmp_path,
scratch_pool));
@@ -1231,7 +1327,7 @@ write_packed_revprop(const char **final_
else
{
/* split the pack file into two of roughly equal size */
- int right_count, left_count, i;
+ int right_count, left_count;
int left = 0;
int right = revprops->sizes->nelts - 1;
@@ -1278,8 +1374,9 @@ write_packed_revprop(const char **final_
/* write the new, split files */
if (left_count)
{
- SVN_ERR(repack_file_open(&file, fs, revprops, 0,
- left_count, files_to_delete, batch,
+ SVN_ERR(repack_file_open(&file, fs, revprops,
+ revprops->entry.start_rev,
+ files_to_delete, batch,
scratch_pool, scratch_pool));
SVN_ERR(repack_revprops(fs, revprops, 0, left_count,
changed_index, serialized, new_total_size,
@@ -1288,9 +1385,9 @@ write_packed_revprop(const char **final_
if (left_count + right_count < revprops->sizes->nelts)
{
- SVN_ERR(repack_file_open(&file, fs, revprops, changed_index,
- changed_index + 1, files_to_delete,
- batch, scratch_pool, scratch_pool));
+ SVN_ERR(repack_file_open(&file, fs, revprops, rev,
+ files_to_delete, batch,
+ scratch_pool, scratch_pool));
SVN_ERR(repack_revprops(fs, revprops, changed_index,
changed_index + 1,
changed_index, serialized, new_total_size,
@@ -1299,9 +1396,7 @@ write_packed_revprop(const char **final_
if (right_count)
{
- SVN_ERR(repack_file_open(&file, fs, revprops,
- revprops->sizes->nelts - right_count,
- revprops->sizes->nelts,
+ SVN_ERR(repack_file_open(&file, fs, revprops, rev + 1,
files_to_delete, batch,
scratch_pool, scratch_pool));
SVN_ERR(repack_revprops(fs, revprops,
@@ -1317,15 +1412,7 @@ write_packed_revprop(const char **final_
*tmp_path = apr_pstrcat(result_pool, *final_path, ".tmp", SVN_VA_NULL);
SVN_ERR(svn_fs_x__batch_fsync_open_file(&file, batch, *tmp_path,
scratch_pool));
-
- stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
- for (i = 0; i < revprops->manifest->nelts; ++i)
- {
- const char *filename = APR_ARRAY_IDX(revprops->manifest, i,
- const char*);
- SVN_ERR(svn_stream_printf(stream, scratch_pool, "%s\n", filename));
- }
- SVN_ERR(svn_stream_close(stream));
+ SVN_ERR(write_manifest(file, revprops->manifest, scratch_pool));
}
return SVN_NO_ERROR;
@@ -1406,19 +1493,14 @@ svn_fs_x__packed_revprop_available(svn_b
svn_revnum_t revision,
apr_pool_t *scratch_pool)
{
- svn_fs_x__data_t *ffd = fs->fsap_data;
- svn_stringbuf_t *content = NULL;
+ svn_node_kind_t kind;
+ packed_revprops_t *revprops;
+ svn_error_t *err;
/* try to read the manifest file */
- const char *folder = svn_fs_x__path_pack_shard(fs, revision, scratch_pool);
- const char *manifest_path = svn_dirent_join(folder, PATH_MANIFEST,
- scratch_pool);
-
- svn_error_t *err = svn_fs_x__try_stringbuf_from_file(&content,
- missing,
- manifest_path,
- FALSE,
- scratch_pool);
+ revprops = apr_pcalloc(scratch_pool, sizeof(*revprops));
+ revprops->revision = revision;
+ err = get_revprop_packname(fs, revprops, scratch_pool, scratch_pool);
/* if the manifest cannot be read, consider the pack files inaccessible
* even if the file itself exists. */
@@ -1428,44 +1510,19 @@ svn_fs_x__packed_revprop_available(svn_b
return FALSE;
}
- if (*missing)
- return FALSE;
-
- /* parse manifest content until we find the entry for REVISION.
- * Revision 0 is never packed. */
- revision = revision < ffd->max_files_per_dir
- ? revision - 1
- : revision % ffd->max_files_per_dir;
- while (content->data)
+ /* the respective pack file must exist (and be a file) */
+ err = svn_io_check_path(get_revprop_pack_filepath(revprops,
+ &revprops->entry,
+ scratch_pool),
+ &kind, scratch_pool);
+ if (err)
{
- char *next = strchr(content->data, '\n');
- if (next)
- {
- *next = 0;
- ++next;
- }
-
- if (revision-- == 0)
- {
- /* the respective pack file must exist (and be a file) */
- svn_node_kind_t kind;
- err = svn_io_check_path(svn_dirent_join(folder, content->data,
- scratch_pool),
- &kind, scratch_pool);
- if (err)
- {
- svn_error_clear(err);
- return FALSE;
- }
-
- *missing = kind == svn_node_none;
- return kind == svn_node_file;
- }
-
- content->data = next;
+ svn_error_clear(err);
+ return FALSE;
}
- return FALSE;
+ *missing = kind == svn_node_none;
+ return kind == svn_node_file;
}
@@ -1573,21 +1630,19 @@ svn_fs_x__pack_revprops_shard(svn_fs_t *
{
const char *manifest_file_path, *pack_filename = NULL;
apr_file_t *manifest_file;
- svn_stream_t *manifest_stream;
svn_revnum_t start_rev, end_rev, rev;
apr_off_t total_size;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
apr_array_header_t *sizes;
+ apr_array_header_t *manifest;
/* Some useful paths. */
manifest_file_path = svn_dirent_join(pack_file_dir, PATH_MANIFEST,
scratch_pool);
- /* Create the manifest file stream. */
+ /* Create the manifest file. */
SVN_ERR(svn_fs_x__batch_fsync_open_file(&manifest_file, batch,
manifest_file_path, scratch_pool));
- manifest_stream = svn_stream_from_aprfile2(manifest_file, TRUE,
- scratch_pool);
/* revisions to handle. Special case: revision 0 */
start_rev = (svn_revnum_t) (shard * max_files_per_dir);
@@ -1611,6 +1666,8 @@ svn_fs_x__pack_revprops_shard(svn_fs_t *
sizes = apr_array_make(scratch_pool, max_files_per_dir, sizeof(apr_off_t));
total_size = 2 * SVN_INT64_BUFFER_SIZE;
+ manifest = apr_array_make(scratch_pool, 4, sizeof(manifest_entry_t));
+
/* Iterate over the revisions in this shard, determine their size and
* squashing them together into pack files. */
for (rev = start_rev; rev <= end_rev; rev++)
@@ -1644,10 +1701,13 @@ svn_fs_x__pack_revprops_shard(svn_fs_t *
/* Update the manifest. Allocate a file name for the current pack
* file if it is a new one */
if (sizes->nelts == 0)
- pack_filename = apr_psprintf(scratch_pool, "%ld.0", rev);
+ {
+ manifest_entry_t *entry = apr_array_push(manifest);
+ entry->start_rev = rev;
+ entry->tag = 0;
- SVN_ERR(svn_stream_printf(manifest_stream, iterpool, "%s\n",
- pack_filename));
+ pack_filename = apr_psprintf(scratch_pool, "%ld.0", rev);
+ }
/* add to list of files to put into the current pack file */
APR_ARRAY_PUSH(sizes, apr_off_t) = finfo.size;
@@ -1661,8 +1721,9 @@ svn_fs_x__pack_revprops_shard(svn_fs_t *
(apr_size_t)total_size, compression_level,
batch, cancel_func, cancel_baton, iterpool));
+ SVN_ERR(write_manifest(manifest_file, manifest, iterpool));
+
/* flush all data to disk and update permissions */
- SVN_ERR(svn_stream_close(manifest_stream));
SVN_ERR(svn_io_copy_perms(shard_path, pack_file_dir, iterpool));
svn_pool_destroy(iterpool);
Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_x/transaction.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_x/transaction.c?rev=1713386&r1=1713385&r2=1713386&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_x/transaction.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_x/transaction.c Mon Nov 9 11:06:42 2015
@@ -877,61 +877,33 @@ unparse_dir_entry(svn_fs_x__dirent_t *di
apr_pool_t *scratch_pool)
{
apr_size_t to_write;
- svn_string_t *id_str = svn_fs_x__id_unparse(&dirent->id, scratch_pool);
apr_size_t name_len = strlen(dirent->name);
- /* Note that sizeof == len + 1, i.e. accounts for the space between
- * type and ID. */
- apr_size_t type_len = (dirent->kind == svn_node_file)
- ? sizeof(SVN_FS_X__KIND_FILE)
- : sizeof(SVN_FS_X__KIND_DIR);
- apr_size_t value_len = type_len + id_str->len;
-
/* A buffer with sufficient space for
- * - both string lines
- * - 4 newlines
- * - 2 lines K/V lines containing a number each
+ * - entry name + 1 terminating NUL
+ * - 1 byte for the node kind
+ * - 2 numbers in 7b/8b encoding for the noderev-id
*/
- char *buffer = apr_palloc(scratch_pool, name_len + value_len
- + 4
- + 2 * (2 + SVN_INT64_BUFFER_SIZE));
+ apr_byte_t *buffer = apr_palloc(scratch_pool,
+ name_len + 2 + 2 * SVN__MAX_ENCODED_UINT_LEN);
/* Now construct the value. */
- char *p = buffer;
-
- /* The "K length(name)\n" line. */
- p[0] = 'K';
- p[1] = ' ';
- p += 2;
- p += svn__i64toa(p, name_len);
- *(p++) = '\n';
+ apr_byte_t *p = buffer;
- /* The line with the key, i.e. dir entry name. */
- memcpy(p, dirent->name, name_len);
- p += name_len;
- *(p++) = '\n';
-
- /* The "V length(type+id)\n" line. */
- p[0] = 'V';
- p[1] = ' ';
- p += 2;
- p += svn__i64toa(p, value_len);
- *(p++) = '\n';
-
- /* The line with the type and ID. */
- memcpy(p,
- (dirent->kind == svn_node_file) ? SVN_FS_X__KIND_FILE
- : SVN_FS_X__KIND_DIR,
- type_len - 1);
- p += type_len - 1;
- *(p++) = ' ';
- memcpy(p, id_str->data, id_str->len);
- p+=id_str->len;
- *(p++) = '\n';
+ /* The entry name, terminated by NUL. */
+ memcpy(p, dirent->name, name_len + 1);
+ p += name_len + 1;
+
+ /* The entry type. */
+ p = svn__encode_uint(p, dirent->kind);
+
+ /* The ID. */
+ p = svn__encode_int(p, dirent->id.change_set);
+ p = svn__encode_uint(p, dirent->id.number);
/* Add the entry to the output stream. */
to_write = p - buffer;
- SVN_ERR(svn_stream_write(stream, buffer, &to_write));
+ SVN_ERR(svn_stream_write(stream, (const char *)buffer, &to_write));
return SVN_NO_ERROR;
}
@@ -943,8 +915,15 @@ unparse_dir_entries(apr_array_header_t *
svn_stream_t *stream,
apr_pool_t *scratch_pool)
{
+ apr_byte_t buffer[SVN__MAX_ENCODED_UINT_LEN];
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
int i;
+
+ /* Write the number of entries. */
+ apr_size_t to_write = svn__encode_uint(buffer, entries->nelts) - buffer;
+ SVN_ERR(svn_stream_write(stream, (const char *)buffer, &to_write));
+
+ /* Write all entries */
for (i = 0; i < entries->nelts; ++i)
{
svn_fs_x__dirent_t *dirent;
@@ -954,9 +933,6 @@ unparse_dir_entries(apr_array_header_t *
SVN_ERR(unparse_dir_entry(dirent, stream, iterpool));
}
- SVN_ERR(svn_stream_printf(stream, scratch_pool, "%s\n",
- SVN_HASH_TERMINATOR));
-
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
@@ -1240,60 +1216,6 @@ create_new_txn_noderev_from_rev(svn_fs_t
return svn_fs_x__put_node_revision(fs, noderev, scratch_pool);
}
-/* Read 'txn-current', return it in *TXN_NUMBER and write the next value
- into 'txn-next' for FS. Schedule fsyncs in BATCH. Use SCRATCH_POOL
- for temporaries. */
-static svn_error_t *
-get_and_txn_key(apr_uint64_t *txn_number,
- svn_fs_t *fs,
- svn_fs_x__batch_fsync_t *batch,
- apr_pool_t *scratch_pool)
-{
- const char *txn_current_path = svn_fs_x__path_txn_current(fs, scratch_pool);
- const char *txn_next_path = svn_fs_x__path_txn_next(fs, scratch_pool);
-
- apr_file_t *file;
- char new_id_str[SVN_INT64_BUFFER_SIZE];
-
- svn_stringbuf_t *buf;
- SVN_ERR(svn_fs_x__read_content(&buf, txn_current_path, scratch_pool));
-
- /* remove trailing newlines */
- *txn_number = svn__base36toui64(NULL, buf->data);
- if (*txn_number == 0)
- ++(*txn_number);
-
- /* Increment the key and add a trailing \n to the string so the
- txn-current file has a newline in it. */
- SVN_ERR(svn_fs_x__batch_fsync_open_file(&file, batch, txn_next_path,
- scratch_pool));
- SVN_ERR(svn_io_file_write_full(file, new_id_str,
- svn__ui64tobase36(new_id_str, *txn_number+1),
- NULL, scratch_pool));
- SVN_ERR(svn_io_copy_perms(txn_current_path, txn_next_path, scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
-/* Move 'txn-next' into place as 'txn-current' for FS. Schedule fsyncs
- in BATCH. Use SCRATCH_POOL for temporaries. */
-static svn_error_t *
-bump_txn_key(svn_fs_t *fs,
- svn_fs_x__batch_fsync_t *batch,
- apr_pool_t *scratch_pool)
-{
- const char *txn_current_path = svn_fs_x__path_txn_current(fs, scratch_pool);
- const char *txn_next_path = svn_fs_x__path_txn_next(fs, scratch_pool);
-
- /* Increment the key and add a trailing \n to the string so the
- txn-current file has a newline in it. */
- SVN_ERR(svn_fs_x__move_into_place(txn_next_path, txn_current_path,
- txn_current_path, batch,
- scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
/* A structure used by get_and_increment_txn_key_body(). */
typedef struct get_and_increment_txn_key_baton_t
{
@@ -1309,14 +1231,57 @@ get_and_increment_txn_key_body(void *bat
apr_pool_t *scratch_pool)
{
get_and_increment_txn_key_baton_t *cb = baton;
- svn_fs_x__batch_fsync_t *batch;
+ svn_fs_t *fs = cb->fs;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ const char *txn_current_path = svn_fs_x__path_txn_current(fs, scratch_pool);
+ char new_id_str[SVN_INT64_BUFFER_SIZE];
- SVN_ERR(svn_fs_x__batch_fsync_create(&batch, scratch_pool));
- SVN_ERR(get_and_txn_key(&cb->txn_number, cb->fs, batch, scratch_pool));
- SVN_ERR(svn_fs_x__batch_fsync_run(batch, scratch_pool));
+ svn_stringbuf_t *buf;
+ SVN_ERR(svn_fs_x__read_content(&buf, txn_current_path, scratch_pool));
- SVN_ERR(bump_txn_key(cb->fs, batch, scratch_pool));
- SVN_ERR(svn_fs_x__batch_fsync_run(batch, scratch_pool));
+ /* Parse the txn number, stopping at the next non-digit.
+ *
+ * Note that an empty string is being interpreted as "0".
+ * This gives us implicit recovery if the file contents should be lost
+ * due to e.g. power failure.
+ */
+ cb->txn_number = svn__base36toui64(NULL, buf->data);
+ if (cb->txn_number == 0)
+ ++cb->txn_number;
+
+ /* Check for conflicts. Those might happen if the server crashed and we
+ * had 'svnadmin recover' reset the txn counter.
+ *
+ * Once we found an unused txn id, claim it by creating the respective
+ * txn directory.
+ *
+ * Note that this is not racy because we hold the txn-current-lock.
+ */
+ while (TRUE)
+ {
+ const char *txn_dir;
+ svn_node_kind_t kind;
+ svn_pool_clear(iterpool);
+
+ txn_dir = svn_fs_x__path_txn_dir(fs, cb->txn_number, iterpool);
+ SVN_ERR(svn_io_check_path(txn_dir, &kind, iterpool));
+ if (kind == svn_node_none)
+ {
+ svn_io_dir_make(txn_dir, APR_OS_DEFAULT, iterpool);
+ break;
+ }
+
+ ++cb->txn_number;
+ }
+
+ /* Increment the key and add a trailing \n to the string so the
+ txn-current file has a newline in it. */
+ SVN_ERR(svn_io_write_atomic2(txn_current_path, new_id_str,
+ svn__ui64tobase36(new_id_str,
+ cb->txn_number + 1),
+ txn_current_path, FALSE, scratch_pool));
+
+ svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
@@ -1332,38 +1297,21 @@ create_txn_dir(const char **id_p,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- const char *txn_dir;
- svn_fs_x__data_t *ffd = fs->fsap_data;
-
- /* If we recently committed a revision through FS, we will have a
- pre-allocated txn-ID that we can just use. */
- if (ffd->next_txn_id)
- {
- *txn_id = ffd->next_txn_id;
-
- /* Not pre-allocated anymore. */
- ffd->next_txn_id = 0;
- }
- else
- {
- get_and_increment_txn_key_baton_t cb;
-
- /* Get the current transaction sequence value, which is a base-36
- number, from the txn-current file, and write an
- incremented value back out to the file. Place the revision
- number the transaction is based off into the transaction id. */
- cb.fs = fs;
- SVN_ERR(svn_fs_x__with_txn_current_lock(fs,
- get_and_increment_txn_key_body,
- &cb,
- scratch_pool));
- *txn_id = cb.txn_number;
- }
+ get_and_increment_txn_key_baton_t cb;
+ /* Get the current transaction sequence value, which is a base-36
+ number, from the txn-current file, and write an
+ incremented value back out to the file. Place the revision
+ number the transaction is based off into the transaction id. */
+ cb.fs = fs;
+ SVN_ERR(svn_fs_x__with_txn_current_lock(fs,
+ get_and_increment_txn_key_body,
+ &cb,
+ scratch_pool));
+ *txn_id = cb.txn_number;
*id_p = svn_fs_x__txn_name(*txn_id, result_pool);
- txn_dir = svn_fs_x__path_txn_dir(fs, *txn_id, scratch_pool);
- return svn_io_dir_make(txn_dir, APR_OS_DEFAULT, scratch_pool);
+ return SVN_NO_ERROR;
}
/* Create a new transaction in filesystem FS, based on revision REV,
@@ -1860,6 +1808,7 @@ svn_fs_x__set_entry(svn_fs_t *fs,
svn_fs_x__data_t *ffd = fs->fsap_data;
apr_pool_t *subpool = svn_pool_create(scratch_pool);
const svn_fs_x__id_t *key = &(parent_noderev->noderev_id);
+ svn_fs_x__dirent_t entry;
if (!rep || !svn_fs_x__is_txn(rep->id.change_set))
{
@@ -1940,21 +1889,17 @@ svn_fs_x__set_entry(svn_fs_t *fs,
}
}
- /* Append an incremental hash entry for the entry change. */
+ /* Append an incremental hash entry for the entry change.
+ A deletion is represented by an "unused" noderev-id. */
if (id)
- {
- svn_fs_x__dirent_t entry;
- entry.name = name;
- entry.id = *id;
- entry.kind = kind;
-
- SVN_ERR(unparse_dir_entry(&entry, out, subpool));
- }
+ entry.id = *id;
else
- {
- SVN_ERR(svn_stream_printf(out, subpool, "D %" APR_SIZE_T_FMT "\n%s\n",
- strlen(name), name));
- }
+ svn_fs_x__id_reset(&entry.id);
+
+ entry.name = name;
+ entry.kind = kind;
+
+ SVN_ERR(unparse_dir_entry(&entry, out, subpool));
/* Flush APR buffers. */
SVN_ERR(svn_io_file_flush(file, subpool));
@@ -3068,6 +3013,10 @@ get_final_id(svn_fs_x__id_t *part,
node-revision. It is only controls additional sanity checking
logic.
+ CHANGED_PATHS is the changed paths hash for the new revision.
+ The noderev-ids in it will be updated as soon as the respective
+ nodesrevs got their final IDs assigned.
+
Temporary allocations are also from SCRATCH_POOL. */
static svn_error_t *
write_final_rev(svn_fs_x__id_t *new_id_p,
@@ -3081,6 +3030,7 @@ write_final_rev(svn_fs_x__id_t *new_id_p
apr_hash_t *reps_hash,
apr_pool_t *reps_pool,
svn_boolean_t at_root,
+ apr_hash_t *changed_paths,
apr_pool_t *scratch_pool)
{
svn_fs_x__noderev_t *noderev;
@@ -3093,6 +3043,7 @@ write_final_rev(svn_fs_x__id_t *new_id_p
svn_fs_x__change_set_t change_set = svn_fs_x__change_set_by_rev(rev);
svn_stream_t *file_stream;
apr_pool_t *subpool;
+ svn_fs_x__change_t *change;
/* Check to see if this is a transaction node. */
if (txn_id == SVN_FS_X__INVALID_TXN_ID)
@@ -3123,9 +3074,8 @@ write_final_rev(svn_fs_x__id_t *new_id_p
SVN_ERR(write_final_rev(&new_id, file, rev, fs, &dirent->id,
initial_offset, directory_ids,
reps_to_cache, reps_hash,
- reps_pool, FALSE, subpool));
- if ( svn_fs_x__id_used(&new_id)
- && (svn_fs_x__get_revnum(new_id.change_set) == rev))
+ reps_pool, FALSE, changed_paths, subpool));
+ if (new_id.change_set == change_set)
dirent->id = new_id;
}
@@ -3271,12 +3221,38 @@ write_final_rev(svn_fs_x__id_t *new_id_p
SVN_ERR(store_p2l_index_entry(fs, txn_id, &entry, scratch_pool));
+ /* Update the ID within the changed paths list. */
+ change = svn_hash_gets(changed_paths, noderev->created_path);
+ if (change)
+ change->noderev_id = noderev->noderev_id;
+
/* Return our ID that references the revision file. */
*new_id_p = new_id;
return SVN_NO_ERROR;
}
+/* Reset all in-transaction noderev-IDs in CHANGED_PATHS. They should
+ belong to deleted nodes only. At any rate, these IDs become invalid
+ as soon as transaction got committed.
+ Perform temporary allocations in SCRATCH_POOL. */
+static svn_error_t *
+sanitize_changed_path_info(apr_hash_t *changed_paths,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_index_t *hi;
+ for (hi = apr_hash_first(scratch_pool, changed_paths);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ svn_fs_x__change_t *change = apr_hash_this_val(hi);
+ if (svn_fs_x__is_txn(change->noderev_id.change_set))
+ svn_fs_x__id_reset(&change->noderev_id);
+ }
+
+ return SVN_NO_ERROR;
+}
+
/* Write the changed path info CHANGED_PATHS from transaction TXN_ID to the
permanent rev-file FILE representing NEW_REV in filesystem FS. *OFFSET_P
is set the to offset in the file of the beginning of this information.
@@ -3675,15 +3651,11 @@ bump_ids(void *baton,
apr_pool_t *scratch_pool)
{
bump_ids_baton_t *b = baton;
- svn_fs_x__data_t *ffd = b->fs->fsap_data;
const char *current_filename;
/* Write the 'next' file. */
SVN_ERR(write_next_file(b->fs, b->new_rev, b->batch, scratch_pool));
- /* Allocate a new txn id. */
- SVN_ERR(get_and_txn_key(&ffd->next_txn_id, b->fs, b->batch, scratch_pool));
-
/* Commit all changes to disk. */
SVN_ERR(svn_fs_x__batch_fsync_run(b->batch, scratch_pool));
@@ -3693,9 +3665,6 @@ bump_ids(void *baton,
current_filename, current_filename,
b->batch, scratch_pool));
- /* Bump txn id. */
- SVN_ERR(bump_txn_key(b->fs, b->batch, scratch_pool));
-
/* Make the new revision permanently visible. */
SVN_ERR(svn_fs_x__batch_fsync_run(b->batch, scratch_pool));
@@ -3830,10 +3799,12 @@ commit_body(void *baton,
svn_fs_x__init_txn_root(&root_id, txn_id);
SVN_ERR(write_final_rev(&new_root_id, proto_file, new_rev, cb->fs, &root_id,
initial_offset, directory_ids, cb->reps_to_cache,
- cb->reps_hash, cb->reps_pool, TRUE, subpool));
+ cb->reps_hash, cb->reps_pool, TRUE, changed_paths,
+ subpool));
svn_pool_clear(subpool);
/* Write the changed-path information. */
+ SVN_ERR(sanitize_changed_path_info(changed_paths, subpool));
SVN_ERR(write_final_changed_path_info(&changed_path_offset, proto_file,
cb->fs, txn_id, changed_paths,
new_rev, subpool));
Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_x/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_x/util.c?rev=1713386&r1=1713385&r2=1713386&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_x/util.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_x/util.c Mon Nov 9 11:06:42 2015
@@ -124,13 +124,6 @@ svn_fs_x__path_txn_current(svn_fs_t *fs,
}
const char *
-svn_fs_x__path_txn_next(svn_fs_t *fs,
- apr_pool_t *result_pool)
-{
- return svn_dirent_join(fs->path, PATH_TXN_NEXT, result_pool);
-}
-
-const char *
svn_fs_x__path_txn_current_lock(svn_fs_t *fs,
apr_pool_t *result_pool)
{
Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_x/util.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_x/util.h?rev=1713386&r1=1713385&r2=1713386&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_x/util.h (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_x/util.h Mon Nov 9 11:06:42 2015
@@ -123,13 +123,6 @@ const char *
svn_fs_x__path_txn_current(svn_fs_t *fs,
apr_pool_t *result_pool);
-/* Return the full path of the "txn-next" file in FS.
- * The result will be allocated in RESULT_POOL.
- */
-const char *
-svn_fs_x__path_txn_next(svn_fs_t *fs,
- apr_pool_t *result_pool);
-
/* Return the full path of the "txn-current-lock" file in FS.
* The result will be allocated in RESULT_POOL.
*/
Modified: subversion/branches/move-tracking-2/subversion/libsvn_subr/compress.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_subr/compress.c?rev=1713386&r1=1713385&r2=1713386&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_subr/compress.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_subr/compress.c Mon Nov 9 11:06:42 2015
@@ -82,6 +82,17 @@ svn__encode_uint(unsigned char *p, apr_u
return p;
}
+unsigned char *
+svn__encode_int(unsigned char *p, apr_int64_t val)
+{
+ apr_uint64_t value = val;
+ value = value & APR_UINT64_C(0x8000000000000000)
+ ? APR_UINT64_MAX - (2 * value)
+ : 2 * value;
+
+ return svn__encode_uint(p, value);
+}
+
const unsigned char *
svn__decode_uint(apr_uint64_t *val,
const unsigned char *p,
@@ -111,6 +122,22 @@ svn__decode_uint(apr_uint64_t *val,
return NULL;
}
+const unsigned char *
+svn__decode_int(apr_int64_t *val,
+ const unsigned char *p,
+ const unsigned char *end)
+{
+ apr_uint64_t value;
+ const unsigned char *result = svn__decode_uint(&value, p, end);
+
+ value = value & 1
+ ? (APR_UINT64_MAX - value / 2)
+ : value / 2;
+ *val = (apr_int64_t)value;
+
+ return result;
+}
+
/* If IN is a string that is >= MIN_COMPRESS_SIZE and the COMPRESSION_LEVEL
is not SVN_DELTA_COMPRESSION_LEVEL_NONE, zlib compress it and places the
result in OUT, with an integer prepended specifying the original size.
Modified: subversion/branches/move-tracking-2/subversion/libsvn_subr/packed_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_subr/packed_data.c?rev=1713386&r1=1713385&r2=1713386&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_subr/packed_data.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_subr/packed_data.c Mon Nov 9 11:06:42 2015
@@ -308,7 +308,7 @@ unmap_uint(apr_uint64_t value)
* are no sub-streams).
*/
static void
-svn_packed__data_flush_buffer(svn_packed__int_stream_t *stream)
+data_flush_buffer(svn_packed__int_stream_t *stream)
{
packed_int_private_t *private_data = stream->private_data;
apr_size_t i;
@@ -382,7 +382,7 @@ svn_packed__add_uint(svn_packed__int_str
{
stream->buffer[stream->buffer_used] = value;
if (++stream->buffer_used == SVN__PACKED_DATA_BUFFER_SIZE)
- svn_packed__data_flush_buffer(stream);
+ data_flush_buffer(stream);
}
void
@@ -435,7 +435,7 @@ write_int_stream_structure(svn_stringbuf
+ (private_data->is_signed ? 2 : 0));
/* store item count and length their of packed representation */
- svn_packed__data_flush_buffer(stream);
+ data_flush_buffer(stream);
write_packed_uint(tree_struct, private_data->item_count);
write_packed_uint(tree_struct, private_data->packed
Modified: subversion/branches/move-tracking-2/subversion/mod_dav_svn/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/mod_dav_svn/util.c?rev=1713386&r1=1713385&r2=1713386&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/mod_dav_svn/util.c (original)
+++ subversion/branches/move-tracking-2/subversion/mod_dav_svn/util.c Mon Nov 9 11:06:42 2015
@@ -620,7 +620,7 @@ dav_svn__make_base64_output_stream(apr_b
wb->output = output;
svn_stream_set_write(stream, brigade_write_fn);
- return svn_base64_encode2(stream, TRUE, pool);
+ return svn_base64_encode2(stream, FALSE, pool);
}
void