For reference, TimeLimitedCollector was added in
LUCENE-997, where TimerThread's functionality is discussed.
When we resolve this one, I think
SOLR-1735 can be resolved as well.
TimerThread provides a pseudo-clock service to all searching threads, so that they can count elapsed time with less overhead than repeatedly calling System.currentTimeMillis. A single thread should be created to be used for all searches.
The opinions about the effectiveness of TimerThread went both ways. For example, in LUCENE-1720, the timeout mechanism works differently, and I wonder if we can apply the same logic here, or something very similar.
Instead of having a static TimerThread, we can have start()/finish() API on TimeLimitingCollector(). start() will start a Thread that will sleep in nanosecs granularity until timeout exceeds. When it exceeds, it raises a flag. In collect() (and in setNextReader/Scorer too, to increase accuracy) all we do is check the flag and if it's on, we fail, just like collect() is impled today. App can call finish() that will signal the thread to stop.
I think it's simple and shouldn't reduce accuracy of current impl (maybe only improve it). Assuming apps don't set timeout to 20 msec, Thread.sleep w/ nanosec granularity should be very accurate. Also, today timeout is counted from the moment you create TLC, but the app may do few more things before IndexSearcher.search() is actually called. start/finish will allow the app to time the search() method (or whatever it wants).
Also, TimerThread was intended to serve all search requests, hence why it is static, but TLC itself cannot be shared across searches at all ...
This will solve this issue, as well as simplify TLC IMO.