[Xapian-discuss] Threaded test (in C++) to reproduce our database
problems
Richard Boulton
richard@lemurconsulting.com
Thu, 17 Jun 2004 14:25:37 +0100
This is a multi-part message in MIME format.
--------------030706000907010606080908
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit
For the record, running a test with helgrind (a skin for valgrind to
detect race conditions) throws up a large number of race conditions,
mainly involving strings. Since the tests don't obviously share any
string data, I assume this is either something happening behind the
scenes in the string class, or a false report from helgrind (which occur
a lot). If you still have problems, it would certainly be worth looking
into these reports further.
My amended test case which I've been running with helgrind is attached
(I put a mutex round the output lines to remove a large number of
obvious false positives).
Eric Ridge wrote:
> As an aside, is it necessary to compile Xapian with -pthread or
> -lpthread or -D_REENTRANT or -D_THREAD_SAFE or something? My
> thinking is no, but I'm just a novice when it comes to pthreads.
It depends on your system really, but I would say that it would be a
good idea to define both _REENTRANT and _THREAD_SAFE if compiling for
use in a multithreaded environment. I doubt that doing so will cause
any harm, at least.
Actually, it occurs to me that this could be the reason that Olly saw
"Interrupted system call" errors failing to be caught - if the relevant
file isn't compiled to use thread-local errno values, a race condition
could cause the wrong error condition to be reported.
--
Richard
--------------030706000907010606080908
Content-Type: text/x-c++;
name="xapian_threads1.cpp"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="xapian_threads1.cpp"
#include <xapian.h>
#include <pthread.h>
#include <unistd.h>
#define DATABASE "/tmp/xapian_threads.db"
#define MAX_THREADS 3
using namespace std;
pthread_t _writer;
pthread_t _readers[MAX_THREADS];
pthread_mutex_t output_mutex;
void msg(const char * msg) {
pthread_mutex_lock(&output_mutex);
fprintf(stderr, "%s\n", msg);
pthread_mutex_unlock(&output_mutex);
}
void* do_writes(void *) {
unlink(DATABASE"/db_lock");
Xapian::WritableDatabase db = Xapian::Auto::open(DATABASE, Xapian::DB_CREATE_OR_OVERWRITE);
char *rnd = (char *) malloc(255);
memset(rnd, 0, 255);
long cnt = 0;
try {
// endlessly add a 2000 term document to the database
while (true) {
Xapian::Document doc;
int i=0;
for (; i<1000; i++) {
doc.add_posting("random", i);
sprintf(rnd, "%d", rand());
doc.add_posting(rnd, i);
}
db.add_document(doc);
if (++cnt % 10 == 0) {
// flush every 10 documents
db.flush();
msg("Writer: flush()");
}
}
} catch (Xapian::Error &err) {
msg((string("Writer: ERROR=") + err.get_msg()).c_str());
}
msg("Writer thread unexpectedly exited...");
pthread_exit(NULL);
}
void* do_reads(void *) {
msg("Reader: started");
try {
// create the reader database once
// and continue to query it.
Xapian::Database db = Xapian::Auto::open(DATABASE);
while (true) {
// NOTE: Creating the database here causes the test
// to fail too, but in different and mysterious ways
Xapian::Enquire enq(db);
Xapian::Query query("random");
Xapian::MSet set;
enq.set_query(query);
set = enq.get_mset(0, 2500);
// walk the results to exercize the mset iterator
for (Xapian::MSetIterator i = set.begin(); i != set.end(); ++i);
}
} catch (Xapian::Error &err) {
msg((string("Reader: ERROR=") + err.get_msg()).c_str());
}
pthread_exit(NULL);
}
void setup_writer_thread() {
pthread_create(&_writer, NULL, do_writes, NULL);
}
void setup_reader_threads() {
int i = 0;
for (; i<MAX_THREADS; i++) {
int success = pthread_create(&(_readers[i]), NULL, do_reads, NULL) == 0;
if (!success) {
msg("setup_reader_threads: Could not create thread");
}
}
}
int main(int argv, char **argc) {
int i = 0;
pthread_mutex_init(&output_mutex, NULL);
setup_writer_thread();
// let the writer thread get going before
// we start a bunch of readers
sleep(2);
setup_reader_threads();
msg("Readers started");
// sit and wait for everything to finish
// in a perfect world, they'll never finish
pthread_join(_writer, NULL);
for (; i<MAX_THREADS; i++) {
pthread_join(_readers[i], NULL);
}
pthread_mutex_destroy(&output_mutex);
return 0;
}
--------------030706000907010606080908--