Re: FSFS locks questions and a concern

2010-11-13 Thread Daniel Shahaf
C. Michael Pilato wrote on Fri, Nov 12, 2010 at 09:40:49 -0500:
 On 11/11/2010 04:25 PM, Daniel Shahaf wrote:
  Philip observed today that, since 'hotcopy' copies the $REPOS/db/locks/???/*
  files using a simple svn_io_copy_dir_recursively(), the correctness of
  the copy is not guaranteed if locks are being added/removed while the
  hotcopy is ongoing: the hotcopy might contain only an arbitrary subset
  of the path-prefix-digest-files.  (It might contain any subset of the
  three digest files md5(/), md5(/trunk/iota), md5(/trunk).  The
  lock removal removes/updates those files in depth-first order.)
  
  So, a few questions:
 
 Maybe, just maybe, you can find some of the information you seek in the
 history of http://subversion.tigris.org/issues/show_bug.cgi?id=3660.  I had
 to study the FSFS lock storage and usage algorithms some time ago to fix a
 bug.  (Though, don't expect to find hotcopy strategies there.)

Indeed, I don't find hotcopy strategies there, but I do find there
discussion on whether the FSFS locks directory should, in each
non-immediate ancestor of a locked file, a pointer to that file's digest
file or a pointer to the next-ancestor-in-the-chain (i.e., /trunk to
/trunk/A)'s digest file.

I guess this answers my original point (2) by It has always been this
way.  Following if it ain't broken, don't fix it, I'll leave this bit
untouched until somebody complains (that 'svn lock' takes too long).

Thanks for the pointer,

Daniel


Re: FSFS locks questions and a concern

2010-11-13 Thread Daniel Shahaf
Philip Martin wrote on Fri, Nov 12, 2010 at 11:02:14 +:
 Daniel Shahaf d...@daniel.shahaf.name writes:
 
  3. What's a reasonable strategy to hotcopy the locks?
 
 I've started on a patch that uses walk_digest_files() (I modified
 that function today), but currently that patch simply does a walk
 starting at the digest file md5(/), and consequently it misses
 copying the unreferenced digest file md5(/trunk).
 
 It appears you have to read/copy md5(/) and get a list of locks, then
 read/copy each lock file that still exists, then reconstruct the
 intermediate files for the locks that were copied.
 

So, for example:

- read md5(/)
  * read md5(/trunk/A/mu)
+ compute md5(/trunk/A)
+ compute md5(/trunk)
  * read md5(/trunk/iota)
+ compute md5(/trunk)

where the 'compute()' steps follow those of normal lock creation: read
the digest file, update list of children, write it back.

 -- 
 Philip


Re: issue 3486 should be reopened?

2010-11-13 Thread Daniel Shahaf
Peter Parker wrote on Sat, Nov 13, 2010 at 05:55:06 +0100:
 Hello,
 I still have still issues with fixed issue:
 #3486 (svn: Attempt to add tree conflict that already exists)
 
 See attached script for provoking this error.
 

With trunk, I get:

[[[
+ /home/daniel/src/svn/trunk/subversion/svn/svn merge '^/Source/branches/3.0' 
-r5:9
subversion/libsvn_client/merge.c:8923: (apr_err=195016)
svn: Cannot merge into mixed-revision working copy [7:8]; try updating first
]]]

and when I add an '$svn up' before the '$svn merge', I get:

[[[
+ /home/daniel/src/svn/trunk/subversion/svn/svn merge '^/Source/branches/3.0' 
-r5:9
--- Merging r6 into '.':
   C dir/foo.c
Summary of conflicts:
  Tree conflicts: 1
subversion/libsvn_wc/tree_conflicts.c:403: (apr_err=155016)
svn: Attempt to add tree conflict that already exists at 
'/tmp/sandbox-scripts/wc/Source/trunk/dir/foo.c'
]]]

Attached the non-windows version of your script I used for testing.

Daniel


 Same results with webdav except you get additional error:
 svn: Attempt to add tree conflict that already exists at 'dir\foo.c'
 svn: Error reading spooled REPORT request response
 
 I used subversion 1.6.13 on windows (script should be easily adapted to
 unix(change line 2 and 8))
 
 Biggest problem is the bail out on merge leaving all other merges
 unprocessed.
 
 Best regards,
 Peter
 
 



Re: FSFS locks questions and a concern

2010-11-13 Thread Daniel Shahaf
Daniel Shahaf wrote on Sat, Nov 13, 2010 at 14:08:12 +0200:
 Philip Martin wrote on Fri, Nov 12, 2010 at 11:02:14 +:
  Daniel Shahaf d...@daniel.shahaf.name writes:
   3. What's a reasonable strategy to hotcopy the locks?
  
  I've started on a patch that uses walk_digest_files() (I modified
  that function today), but currently that patch simply does a walk
  starting at the digest file md5(/), and consequently it misses
  copying the unreferenced digest file md5(/trunk).
  
  It appears you have to read/copy md5(/) and get a list of locks, then
  read/copy each lock file that still exists, then reconstruct the
  intermediate files for the locks that were copied.
  
 
 So, for example:
 
 - read md5(/)
   * read md5(/trunk/A/mu)
 + compute md5(/trunk/A)
 + compute md5(/trunk)
   * read md5(/trunk/iota)
 + compute md5(/trunk)
 
 where the 'compute()' steps follow those of normal lock creation: read
 the digest file, update list of children, write it back.

Attached patch implements this.  Comments?

http://people.apache.org/~danielsh/hot.logmsg
http://people.apache.org/~danielsh/hot.diff

[[[
FSFS: teach 'hotcopy' the semantics of the locks/ directory.

Found by: philip

* notes/fsfs:
Document another limitation of rsync-style backup, which 'hotcopy' lacks.

* subversion/libsvn_fs_fs/fs_fs.c
  (svn_fs_fs__hotcopy):
Use svn_fs_fs__hotcopy_locks() instead of svn_io_copy_dir_recursively().

* subversion/libsvn_fs_fs/lock.c
  (svn_fs_fs__hotcopy_locks):  New declaration.

* subversion/libsvn_fs_fs/lock.c
  (digest_dir_path_from_digest):
New, like svn_dirent_dirname(digest_path_from_digest()).
  (hotcopy_walker):  New callback.
  (svn_fs_fs__hotcopy_locks):  New definition.
]]]

[[[
Index: notes/fsfs
===
--- notes/fsfs  (revision 1034745)
+++ notes/fsfs  (working copy)
@@ -248,6 +248,11 @@ manually removed.  svnadmin hotcopy does not cop
 transactions from an FSFS repository, although that might need to
 change if Subversion starts making use of long-lived transactions.
 
+Naively copying an FSFS repository might also copy an inconsistent view
+of the locks directory, if locks are being added or removed as the copy
+operation is running.  svnadmin hotcopy copies and generates the locks
+digest files properly.
+
 So, if you are using standard backup tools to make backups of a FSFS
 repository, configure the software to copy the current file before
 the numbered revision files, if possible, and configure it not to copy
Index: subversion/libsvn_fs_fs/fs_fs.c
===
--- subversion/libsvn_fs_fs/fs_fs.c (revision 1034745)
+++ subversion/libsvn_fs_fs/fs_fs.c (working copy)
@@ -1767,9 +1767,7 @@ svn_fs_fs__hotcopy(const char *src_path,
   src_subdir = svn_dirent_join(src_path, PATH_LOCKS_DIR, pool);
   SVN_ERR(svn_io_check_path(src_subdir, kind, pool));
   if (kind == svn_node_dir)
-SVN_ERR(svn_io_copy_dir_recursively(src_subdir, dst_path,
-PATH_LOCKS_DIR, TRUE, NULL,
-NULL, pool));
+SVN_ERR(svn_fs_fs__hotcopy_locks(src_path, dst_path, pool));
 
   /* Now copy the node-origins cache tree. */
   src_subdir = svn_dirent_join(src_path, PATH_NODE_ORIGINS_DIR, pool);
Index: subversion/libsvn_fs_fs/lock.c
===
--- subversion/libsvn_fs_fs/lock.c  (revision 1034756)
+++ subversion/libsvn_fs_fs/lock.c  (working copy)
@@ -121,6 +121,19 @@ err_corrupt_lockfile(const char *fs_path, const ch
 
 /*** Digest file handling functions. ***/
 
+/* Return the path of the lock/entries directory for which DIGEST is the
+   hashed repository relative path. */
+static const char *
+digest_dir_path_from_digest(const char *fs_path,
+const char *digest,
+apr_pool_t *pool)
+{
+  return svn_dirent_join_many(pool, fs_path, PATH_LOCKS_DIR,
+  apr_pstrmemdup(pool, digest, DIGEST_SUBDIR_LEN),
+  NULL);
+}
+
+
 /* Return the path of the lock/entries file for which DIGEST is the
hashed repository relative path. */
 static const char *
@@ -893,6 +906,65 @@ unlock_body(void *baton, apr_pool_t *pool)
 }
 
 
+/*** Hotcopying locks. ***/
+
+/* Implements walk_digests_callback_t. */
+static svn_error_t *
+hotcopy_walker(void *baton,
+   const char *fs_path,
+   const char *digest_path,
+   apr_hash_t *children /* ignored */,
+   svn_lock_t *lock /* ignored */,
+   svn_boolean_t have_write_lock,
+   apr_pool_t *pool)
+{
+  const char *dst_fs_path = baton;
+  const char *digest;
+  const char *src_digest_dir, *dst_digest_dir;
+  const char *perms_reference = digest_path;
+  
+  digest = svn_dirent_basename(digest_path, 

Re: issue 3486 should be reopened?

2010-11-13 Thread Daniel Shahaf
Daniel Shahaf wrote on Sat, Nov 13, 2010 at 14:35:13 +0200:
 Attached the non-windows version of your script I used for testing.

[[[
#!/bin/sh -ex

rm -rf repo wc
REPO_PATH=$(pwd)/repo

$svnadmin create repo
$svn co file://$REPO_PATH wc
pushd wc

mkdir -p Server/trunk/dir
echo x  Server/trunk/dir/foo.c
echo x  Server/trunk/dir/bar.c
$svn add Server
$svn commit -m 1

$svn move Server Source
$svn commit -m 2

mkdir -p Source/branches
$svn add Source/branches
$svn commit -m 3

$svn copy Source/trunk Source/branches/3.0
$svn commit -m 4

$svn delete Source/trunk/dir/foo.c
$svn commit -m 5


# few checkins
echo xxx  Source/branches/3.0/dir/foo.c
$svn commit -m 6

echo xxx  Source/branches/3.0/dir/bar.c
$svn commit -m 7

# merge down bar.c only
pushd Source/trunk
# wtf - 6:7 is exclusive on the left side? -r 7 or -r 7:7 does nothing
$svn merge ^/Source/branches/3.0 -r 6:7
$svn up
$svn commit -m 8

popd
echo xxx  Source/branches/3.0/dir/foo.c
$svn commit -m 9

pushd Source/trunk
test -n $1  $svn up
$svn merge ^/Source/branches/3.0 -r5:9

popd
popd
]]]


[Proposed] Split very long messages by paragraph for easy translate

2010-11-13 Thread Dongsheng Song
Hi folks,

subversion.pot have some very long translated message, for example:

Apply a patch to a working copy.\n
usage: patch PATCHFILE [WCPATH]\n
\n
 Apply a unidiff patch in PATCHFILE to the working copy WCPATH.\n
 If WCPATH is omitted, '.' is assumed.\n
\n
 A unidiff patch suitable for application to a working copy can be\n
 produced with the 'svn diff' command or third-party diffing tools.\n
 Any non-unidiff content of PATCHFILE is ignored.\n
\n
 Changes listed in the patch will either be applied or rejected.\n
 If a change does not match at its exact line offset, it may be applied\n
 earlier or later in the file if a match is found elsewhere for the\n
 surrounding lines of context provided by the patch.\n
 A change may also be applied with fuzz, which means that one\n
 or more lines of context are ignored when matching the change.\n
 If no matching context can be found for a change, the change conflicts\n
 and will be written to a reject file with the extension .svnpatch.rej.\n
\n
 For each patched file a line will be printed with characters reporting\n
 the action taken. These characters have the following meaning:\n
\n
   A  Added\n
   D  Deleted\n
   U  Updated\n
   C  Conflict\n
   G  Merged (with local uncommitted changes)\n
\n
 Changes applied with an offset or fuzz are reported on lines starting\n
 with the '' symbol. You should review such changes carefully.\n
\n
 If the patch removes all content from a file, that file is scheduled\n
 for deletion. If the patch creates a new file, that file is scheduled\n
 for addition. Use 'svn revert' to undo deletions and additions you\n
 do not agree with.\n

From the translator's point of view, this very hard for translate and maintain.
So I proposed we should split these long message like mercurial.

--
Dongsheng


Re: [Proposed] Split very long messages by paragraph for easy translate

2010-11-13 Thread Daniel Shahaf
Sounds reasonable.

What changes to the source code would be required?

Do we just change
N_(three\n\nparagraphs\n\nhere\n)
to
N_(three\n) N_(paragraphs\n) N_(here\n)
?

Dongsheng Song wrote on Sat, Nov 13, 2010 at 23:18:08 +0800:
 Hi folks,
 
 subversion.pot have some very long translated message, for example:
 
 Apply a patch to a working copy.\n
 usage: patch PATCHFILE [WCPATH]\n
 \n
  Apply a unidiff patch in PATCHFILE to the working copy WCPATH.\n
  If WCPATH is omitted, '.' is assumed.\n
 \n
  A unidiff patch suitable for application to a working copy can be\n
  produced with the 'svn diff' command or third-party diffing tools.\n
  Any non-unidiff content of PATCHFILE is ignored.\n
 \n
  Changes listed in the patch will either be applied or rejected.\n
  If a change does not match at its exact line offset, it may be applied\n
  earlier or later in the file if a match is found elsewhere for the\n
  surrounding lines of context provided by the patch.\n
  A change may also be applied with fuzz, which means that one\n
  or more lines of context are ignored when matching the change.\n
  If no matching context can be found for a change, the change conflicts\n
  and will be written to a reject file with the extension .svnpatch.rej.\n
 \n
  For each patched file a line will be printed with characters reporting\n
  the action taken. These characters have the following meaning:\n
 \n
    A  Added\n
    D  Deleted\n
    U  Updated\n
    C  Conflict\n
    G  Merged (with local uncommitted changes)\n
 \n
  Changes applied with an offset or fuzz are reported on lines starting\n
  with the '' symbol. You should review such changes carefully.\n
 \n
  If the patch removes all content from a file, that file is scheduled\n
  for deletion. If the patch creates a new file, that file is scheduled\n
  for addition. Use 'svn revert' to undo deletions and additions you\n
  do not agree with.\n
 
 From the translator's point of view, this very hard for translate and 
 maintain.
 So I proposed we should split these long message like mercurial.
 
 --
 Dongsheng


Re: [Proposed] Split very long messages by paragraph for easy translate

2010-11-13 Thread Greg Hudson
On Sat, 2010-11-13 at 10:31 -0500, Daniel Shahaf wrote:
 Sounds reasonable.
 
 What changes to the source code would be required?
 
 Do we just change
   N_(three\n\nparagraphs\n\nhere\n)
 to
   N_(three\n) N_(paragraphs\n) N_(here\n)

No, that would just result in evaluating gettext on the combined string,
same as before.  I can see two options for help strings in particular:

1. Rev svn_opt_subcommand_desc2_t to include an array of help strings
which are translated and displayed in sequence.

2. Change print_command_info2 to look at the help string and break it up
at certain boundaries (such as blank lines or numbered list entries)
before translating it.

(Mercurial is written in Python, so it has different constraints.)




Re: [PATCH] extend svn_subst_translate_string() to record whether re-encoding and/or line ending translation were performed (v. 3)

2010-11-13 Thread Daniel Trebbien
 The only difference between translate_newline() and translate_newline_alt()
 is the lines of code from here to the end of the function.  I think you
 could keep translate_newline() as is, and just move these checks elsewhere
 (to a new function or to the caller; I haven't thought about this in
 detail).

 In any case, please avoid the code duplication if possible.  (Function
 pointers are nice, but sometimes just a way to shoot yourself in the
 foot.)  If you're unsure what approach to take, do brainstorm on-list
 before sending a new iteration of the patch.  (That saves time to you
 and to us)

After thinking about this problem some more, I thought about using a
macro solution.  I define a macro that is able to output the
definitions of the two variants of translate_newline():
translate_newline() and translate_newline_alt().  This way, duplicate
code is avoided, but it is like having duplicate code where each copy
is slightly different.

Do you like this idea?  I have attached C code that I have tested.  In
this sample, the macro that outputs the definitions of
translate_newline() and translate_newline_alt() is called
DEFINE_TRANSLATE_NEWLINE_FN.
/* A boolean expression that evaluates to true if the string STR, having length
   STR_LEN, is one of the end-of-line strings LF, CR, or CRLF;  to false
   otherwise.  */
#define STRING_IS_EOL(str, str_len) (((str_len) == 2 \
  (str)[0] == '\r'   \
  (str)[1] == '\n') || \
 ((str_len) == 1 \
  ((str)[0] == '\n' || (str)[0] == '\r')))

/* A boolean expression that evaluates to true if the end-of-line string EOL1,
   having length EOL1_LEN, and the end-of-line string EOL2, having length
   EOL2_LEN, are different, assuming that EOL1 and EOL2 are both from the
   set {\n, \r, \r\n};  to false otherwise.
   
   Given that EOL1 and EOL2 are either \n, \r, or \r\n, then if
   EOL1_LEN is not the same as EOL2_LEN, then EOL1 and EOL2 are of course
   different. If EOL1_LEN and EOL2_LEN are both 2 then EOL1 and EOL2 are both
   \r\n. Otherwise, EOL1_LEN and EOL2_LEN are both 1. We need only check the
   one character for equality to determine whether EOL1 and  EOL2 are the same
   in that case. */
#define DIFFERENT_EOL_STRINGS(eol1, eol1_len, eol2, eol2_len) \
  (((eol1_len) != (eol2_len)) || (*(eol1) != *(eol2)))

static svn_error_t *
translate_newline_alt(const char *eol_str,
  apr_size_t eol_str_len,
  char *src_format,
  apr_size_t *src_format_len,
  const char *newline_buf,
  apr_size_t newline_len,
  svn_stream_t *dst,
  struct translation_baton *b);

#define DEFINE_TRANSLATE_NEWLINE_FN(fn, is_alt)\
static svn_error_t *   \
fn(const char *eol_str,\
   apr_size_t eol_str_len, \
   char *src_format,   \
   apr_size_t *src_format_len, \
   const char *newline_buf,\
   apr_size_t newline_len, \
   svn_stream_t *dst,  \
   struct translation_baton *b)\
{  \
  SVN_ERR_ASSERT(STRING_IS_EOL(eol_str, eol_str_len)); \
  SVN_ERR_ASSERT(STRING_IS_EOL(newline_buf, newline_len)); \
   \
  /* If we've seen a newline before, compare it with our cache to  \
 check for consistency, else cache it for future comparisons. */   \
  if (*src_format_len) \
{  \
  /* Comparing with cache.  If we are inconsistent and \
 we are NOT repairing the file, generate an error! */  \
  if ((! b-repair)  \
  ((*src_format_len != newline_len) || \
   (strncmp(src_format, newline_buf, newline_len   \
return svn_error_create(SVN_ERR_IO_INCONSISTENT_EOL, NULL, NULL);  \
}  \
  else