[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

trivial yet very serious bug, suggestions welcome

From: Karl Fogel <kfogel_at_newton.ch.collab.net>
Date: 2001-10-26 23:22:48 CEST

Heh, found this one while writing a script to test "svn log"...

We have a timestamp issue, at least on my Linux 2.2.16 system. If you
modify a file too quickly after it's checked out or updated (i.e.,
after its entry timestamp got set), then the file's on-disk timestamp
will not be different from the entry's, and therefore Subversion will
not detect your local mods unless those mods also changed the file's
size.

A human probably can't modify a file that fast, but a script sure
can (I've included one such at the end of this mail).

So, here's the dilemna:

   - If we no longer compare timestamps, we can guarantee correctness,
     but at the expense of speed. A very drastic expense -- any
     command that crawls the working copy looking for local mods will
     now have to do a byte-for-byte comparison on most files (because
     most files are not modified at any given time, and therefore the
     filesize check will be inconclusive for them). We can expect
     "svn status" and "svn commit" to become rather painful.

   - But if we keep the current timestamp code, then depending on your
     system granularity, there may occasionally be times when a local
     mod is not detected. If you happen to *know* about the mod, you
     can easily solve the problem by `touch'ing the file or doing
     whatever to change its timestamp. But if you were depending on
     Subversion to reliably tell you what's modified, you'll be
     hosed.

(Hm, does CVS have this problem too? It has *only* timestamps to go
on, no text-base. I don't recall ever running into this, though.)

Anyway, the only solution I can think of is kind of weird:

Normally, after we've written out a working file as part of checkout
or update, we then store an entry timestamp according to the new
working file's on-disk timestamp. We make the entry timestamp be
precisely the same as the on-disk timestamp. See this line

   entry->text_time = text_time;

in libsvn_wc/log.c:log_do_modify_entry().

If we instead write a timestamp slightly in the future w.r.t. the
working file -- where "slightly" means "by an amount greater than the
greatest system granularity you ever heard of" -- then if we ever saw
a working file whose on-disk timestamp were closer to the entry stamp
than that amount, we'd know it had been modified. Uh, right? :-)

Anyone got any other thoughts?

Repro script follows:

--------------------8-<-------cut-here---------8-<-----------------------
#!/bin/sh

# With no arguments, demonstrate a bug whereby very fast working copy
# modifications can result in a wc that contains local mods
# undetectable by Subversion (due to timestamp badness).
#
# With an argument, sleep for a second between each commit, so the
# timestamp problem is avoided, and see all the commits succeed,
# ending with revision 6. Frightening, eh?
#
# Use this script like so:
#
# $ cd top-level-of-subversion-wc/
# $ make
# $ make check
# $ cd subversion/tests/clients/cmdline
# $ ...put this script here as `repro.sh'...
# $ ...edit repro.sh so the $WD and $SVN vars are correct for you...
# $ chmod a+x repro.sh
# $ ./repro.sh
# $ ./repro.sh blah /* blah can be literally "blah" */

### YOU SHOULD ONLY NEED TO MODIFY THESE TWO VARIABLES ###
WD=${HOME}/src/subversion/subversion/tests/clients/cmdline
SVN=${HOME}/src/subversion/subversion/clients/cmdline/svn

cd ${WD}

rm -rf safe-repo safe-wc repo wc

cp -a repositories/basic_tests-1 ./safe-repo
cp -a safe-repo repo
${SVN} co file://${WD}/repo -d safe-wc

${SVN} co file://${WD}/repo -d wc
cd wc

echo "This is rev 2" > iota; ${SVN} ci -m "Log msg for rev two."
echo "Committed revision 2";
if [ "${1-X}" != "X" ]; then sleep 1; fi

echo "This is rev 3" > iota; ${SVN} ci -m "Log msg for rev three."
echo "Committed revision 3";
if [ "${1-X}" != "X" ]; then sleep 1; fi

echo "This is rev 4" > iota; ${SVN} ci -m "Log msg for rev four."
echo "Committed revision 4";
if [ "${1-X}" != "X" ]; then sleep 1; fi

echo "This is rev 5" > iota; ${SVN} ci -m "Log msg for rev five."
echo "Committed revision 5";
if [ "${1-X}" != "X" ]; then sleep 1; fi

echo "This is rev 6" > iota; ${SVN} ci -m "Log msg for rev six."
echo "Committed revision 6";
if [ "${1-X}" != "X" ]; then sleep 1; fi

${SVN} up
${SVN} st -uv

echo ""
echo "NOTE:"
echo "If the status output above does not show everything at revision 6,"
echo "including a head revision of 6, then you have reproduced the bug."
echo "Congratulations."

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Sat Oct 21 14:36:46 2006

This is an archived mail posted to the Subversion Dev mailing list.