[Cyrus-CVS] src/cyrus/lib by murch

murch at andrew.cmu.edu murch at andrew.cmu.edu
Fri Nov 16 07:15:58 EST 2007


Update of /afs/andrew/system/cvs/src/cyrus/lib
In directory unix33.andrew.cmu.edu:/var/tmp/cvs-serv8934

Modified Files:
	cyrusdb_skiplist.c 
Log Message:
SKIPLIST bugfixes (Bron Gondwana <brong at fastmail.fm>)

In the past we have had issues with bugs in skiplist on seen
files, and we truncated files at the offset with the issue
since they were only seen data.

Lately, we have had more tools updating mailboxes.db more
often, and have lost multiple mailboxes.db files.

There are two detectable issues:

1) incorrect header "logstart" values causing recovery to
   fail with either unexpected ADD/DELETE records or
   unexpected INORDER records depending which side of the
   correct location the logstart value is wrong.
2) a bunch of zero bytes between transactions in the log
   section.

The attached patch fixes the following issues:

a) recovery failed to update db->map_base if it truncated
   a partial transaction.  This reliably recreated the
   zero bytes issues above by having the next store command
   lseek to a location past the new end of the file, and
   hence fill the remainder with blanks.

b) the logic in the "delete" handler for detecting "no
   record exists" (ptr == db->map_base) was backwards,
   meaning that a delete on a record which didn't exist
   caused reads of PTR(db->map_base, i), which is bogus
   and nasty.  This is the suspect for logstart breakage
   though I haven't proven this yet.

c) unsure if this is a real risk, but added a ftruncate
   to checkpoint to ensure new file really is empty,
   since we don't open it with O_EXCL.

d.1) when abort is called it needs to update_lock() to
     ensure that the records it's about to rollback are
     actually locked.  This fix stopped segfaults in
     my testing.

d.2) delete didn't check retry_write for success, and
     also suffered from the same problem as:

d.3) if retry_writev in store failed, then it called
     abort, but without the records actually written,
     abort had no way of knowing which offsets needed
     to be switched back, meaning bogus pointers could
     be left in the file until the next recovery().
     Changed it to write the records first, then only
     once that succeeded update the pointers.  This way
     abort will do the right thing regardless.



--- links to diffs follow ---
http://bugzilla.andrew.cmu.edu/cgi-bin/cvsweb.cgi/src/cyrus/lib/cyrusdb_skiplist.c.diff?r1=1.53&r2=1.54


More information about the Cyrus-cvs mailing list