==================================== Concurrency, locking, and versioning ==================================== Concurrency =========== The ``FileIndex`` object is "stateless" and should be share-able between threads. A ``Reader`` object (which underlies the ``Searcher`` object) wraps open files and often individual methods rely on consistent file cursor positions (e.g. they do two ``file.read()``\ s in a row, so if another thread moves the cursor between the two read calls Bad Things would happen). You should use one Reader/Searcher per thread in your code. Readers/Searchers tend to cache information (such as field caches for sorting), so if you can share one across multiple search requests, it's a big performance win. Locking ======= Only one thread/process can write to an index at a time. When you open a writer, it locks the index. If you try to open a writer on the same index in another thread/process, it will raise ``whoosh.store.LockError``. In a multi-threaded or multi-process environment your code needs to be aware that opening a writer may raise this exception if a writer is already open. Whoosh includes a couple of example implementations (:class:`whoosh.writing.AsyncWriter` and :class:`whoosh.writing.BufferedWriter`) of ways to work around the write lock. While the writer is open and during the commit, **the index is still available for reading**. Existing readers are unaffected and new readers can open the current index normally. Lock files ---------- Locking the index is accomplished by acquiring an exclusive file lock on the ``_WRITELOCK`` file in the index directory. The file is not deleted after the file lock is released, so the fact that the file exists **does not** mean the index is locked. Versioning ========== When you open a reader/searcher, the reader represents a view of the **current version** of the index. If someone writes changes to the index, any readers that are already open **will not** pick up the changes automatically. A reader always sees the index as it existed when the reader was opened. If you are re-using a Searcher across multiple search requests, you can check whether the Searcher is a view of the latest version of the index using :meth:`whoosh.searching.Searcher.up_to_date`. If the searcher is not up to date, you can get an up-to-date copy of the searcher using :meth:`whoosh.searching.Searcher.refresh`:: # If 'searcher' is not up-to-date, replace it searcher = searcher.refresh() (If the searcher has the latest version of the index, ``refresh()`` simply returns it.) Calling ``Searcher.refresh()`` is more efficient that closing the searcher and opening a new one, since it will re-use any underlying readers and caches that haven't changed.