It's become clear trying to fix the Xapian locking mess that we
actually want two locks, like we have for mailboxes.  A namelock that
is long lasting and doesn't block regular indexing or searching, but
guarantees that things won't be deleted out underneath, and the
existing short term locks on xapianactive that are used to guarantee
clean reads and safe indexing.
Xapian Locking:
---

* Xapian per-user NAMELOCK (shared or exclusive)
* xapianactive file lock (shared or exclusive)

Shared namelock holds the following invariants:
* xapianactive file contents are not changed
* directories mentioned in xapianactive are not cleaned up

Xapianactive exclusive lock holds the following invariants:
* owner may write to first database mentioned in xapianactive

Xapianactive shared lock holds:
* all databases in xapianactive are readable and a consistent
  read can be made across all of them, even with multiple requests
  while the lock is held.


Locking orders:

SHARED case:
* user conversations db <=== possibly reversible with SHARED
  xapian namelock* SHARED xapian namelock
* xapianactive lock (shared to search, exclusive to write)
* cyrus.index may be locked either side of the xapianactive lock,
  because the  conversationsdb lock protects it from races.

EXCLUSIVE case:
* EXCLUSIVE xapian namelock
  -> that's it.  While you've got this, you can add or delete items from     
the xapianactive file, and delete paths on disk for
     directories that     you have removed (either during or after locking).  
No other locks
     are     permitted.

If you hold a SHARED xapian namelock, you may write to a .NEW
folder for axapianactive entry that you created without taking any additional 
locks,because nothing can clean it under you, and nothing else can read it.
Thisis how the repack case works.

---------------------------------

Places that will need to be changed:

begin_search: needs to take a SHARED namelock before taking a SHARED 
xapianactive lock.
end_search: needs to release the namelock after unlocking the activefile.
begin_mailbox_update: needs to take a SHARED namelock before taking an 
EXCLUSIVE xapianactive lock.
end_mailbox_update: needs to release the namelock.

list_files: needs to take a SHARED namelock and release it again.

delete_user: needs to take an EXCLUSIVE namelock as well as the existing 
EXCLUSIVE xapianactive lock.
compact_dbs: this is the complex one!

1) take an EXCLUSIVE namelock while doing the following:
   -> add a new first target tier:number to the xapianactive file
   (always temp)   -> add a new tier:number target to the tail of the 
xapianactive file
   (squatter -z option)2) release the EXCLUSIVE namelock
3) take a SHARED namelock and SHARED xapianactive lock to read
   the contents of the xapianactive file and make sure we didn't
   lose a race.4) release the SHARED xapianactive lock.
5) compact or reindex into target:number xapian.<number>.NEW directory
   (see above, this is safe without locks)6) release the SHARED namelock
7) take an EXCLUSIVE namelock and check again that we have the same
   xapianactive contents, if we lost the race here, we still need to
   delete all the xapian.<number>.NEW and abort.8)  rename xapian.<number>.NEW 
to xapian.<number>
9) remove the source tier:number entries from xapianactive
10) release the EXCLUSIVE namelock.
11) take a SHARED namelock
12) It's now safe to delete all the directories which were source
    tier:number, as well as any other directory not mentioned in
    xapianactive any more.13) release everything, you're done :)


--
  Bron Gondwana, CEO, FastMail Pty Ltd
  br...@fastmailteam.com


Reply via email to