Robert Pollak
2004-Jul-13 12:33 UTC
[Xapian-discuss] Multithread problem: Writing to a db disables reading from another one
Hi to all,
I have Xapian 0.8.1 installed on a single processor RH9 machine with a custom
2.4.20 kernel.
(I used ./configure without parameters.)
I have followed the recent "threaded test" discussion here, and I have
tested the examples:
- Richard Boulton's example with one database, one writer, and three readers
(1)
works fine, I only see the expected DatabaseModifiedError.
- Eric B. Ridge's example with just two writers to separate databases (2)
also shows no errors (I stopped after 162 docs were added).
I then expanded Richard's example by adding a second writer that writes to a
separate database (see attachment).
(I am also reopening the db if necessary.)
Now the queries give empty results!
Commenting out the creation of _writer2 makes the queries return the expected
results again (3).
I wonder whether Olly or someone else can reproduce this.
I have not tried modifying any Xapian compile options, because I am an automake
newbie.
Would I have to edit Makefile.in (and how whould I do this), or would I just
pass arguments to configure?
Footnotes:
1: from 17 Jun 2004 14:25:37 +0100, see
<http://article.gmane.org/gmane.comp.search.xapian.general/892>
2: from 17 Jun 2004 00:30:50 +0000, see
<http://article.gmane.org/gmane.comp.search.xapian.general/876>
3:
$ ./xapian_threads
Writer opening 1.db
Writer flushing 1.db
Reader opening 1.db
1.db results: 10
Reader opening 1.db
1.db results: 10
Reader opening 1.db
1.db results: 10
Readers started
Writer flushing 1.db
1.db results: 10
1.db results: 10
1.db results: 10
Writer flushing 1.db
Reader reopening 1.db
1.db results: 30
Reader reopening 1.db
1.db results: 30
Reader reopening 1.db
1.db results: 30
1.db results: 30
1.db results: 30
1.db results: 30
Writer flushing 1.db
1.db results: 30
1.db results: 30
1.db results: 30
Reader reopening 1.db
1.db results: 40
--
Robert Pollak
GPG Key ID: 748646AD
-------------- next part --------------
#include <xapian.h>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
#include <sstream>
#define MAX_THREADS 3
using namespace std;
pthread_t _writer1, _writer2;
pthread_t _readers[MAX_THREADS];
pthread_mutex_t output_mutex;
void msg(const string& msg)
{
pthread_mutex_lock(&output_mutex);
cout << msg << endl;
pthread_mutex_unlock(&output_mutex);
}
void *do_writes(void *param)
{
char *dbpath = (char *)param;
msg(string("Writer opening ") + dbpath);
unlink((string(dbpath) + "/db_lock").c_str());
Xapian::WritableDatabase db = Xapian::Auto::open(dbpath,
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(string("Writer flushing ") + dbpath);
}
}
}
catch(Xapian::Error & err) {
msg(string("Writer accessing ") + dbpath + ": ERROR=" +
err.get_msg());
}
msg("Writer thread unexpectedly exited...");
pthread_exit(NULL);
}
void *do_reads(void *param)
{
char *dbpath = (char *)param;
msg(string("Reader opening ") + dbpath);
try {
// create the reader database once and continue to query it.
Xapian::Database db = Xapian::Auto::open(dbpath);
while(true) {
Xapian::Enquire enq(db);
Xapian::Query query("random");
Xapian::MSet set;
enq.set_query(query);
bool dbModified;
do {
dbModified = false;
try {
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(const Xapian::DatabaseModifiedError &) {
dbModified = true;
msg(string("Reader reopening ") + dbpath);
db.reopen();
}
} while(dbModified); // repeat only on error
stringstream result;
result << dbpath << " results: " <<
set.size();
msg(result.str());
sleep(1); // make the log more readable
}
}
catch(Xapian::Error & err) {
msg(string("Reader accessing ") + dbpath + ": ERROR=" +
err.get_msg());
}
pthread_exit(NULL);
}
void setup_writer_threads()
{
pthread_create(&_writer1, NULL, do_writes, (void *)"1.db");
pthread_create(&_writer2, NULL, do_writes, (void *)"2.db");
}
void setup_reader_threads()
{
int i = 0;
for(; i < MAX_THREADS; i++) {
int success = pthread_create(&(_readers[i]), NULL, do_reads, (void
*)"1.db") == 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_threads();
// let the writer threads 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(_writer1, NULL);
pthread_join(_writer2, NULL);
for(; i < MAX_THREADS; i++) {
pthread_join(_readers[i], NULL);
}
pthread_mutex_destroy(&output_mutex);
return 0;
}
Robert Pollak
2004-Jul-26 15:30 UTC
[Xapian-discuss] Multithread problem: Writing to a db disables reading from another one
I wrote:> I then expanded Richard's example by adding a second writer that writes > to a separate database (see attachment). > (I am also reopening the db if necessary.) > Now the queries give empty results!The queries didn't cause DatabaseModifiedErrors. Should't they? After reading Olly's <http://lists.tartarus.org/pipermail/xapian-discuss/2004-June/000148.html> I made the readers work by reopening the database preemptively before each query. -- Robert Pollak GPG Key ID: 748646AD
Olly Betts
2004-Aug-23 23:57 UTC
[Xapian-discuss] Multithread problem: Writing to a db disables reading from another one
On Tue, Jul 13, 2004 at 01:32:25PM +0200, Robert Pollak wrote:> I then expanded Richard's example by adding a second writer that writes to > a separate database (see attachment). > (I am also reopening the db if necessary.) > Now the queries give empty results! > Commenting out the creation of _writer2 makes the queries return the > expected results again (3). > > I wonder whether Olly or someone else can reproduce this.I've just tried it, compiling with GCC 2.95.4 (since that's what I currently happen to have a handy Xapian built with). I need to add "#include <stdio.h>" to get sprintf prototyped, and when I run the program it segfaults trying to use memcpy inside std::string inside quartz. I think this is probably the lack of thread safety in the string class which Richard mentioned. I'll try further tests, but probably not until next week.> I have not tried modifying any Xapian compile options, because I am an > automake newbie. > Would I have to edit Makefile.in (and how whould I do this), or would I > just pass arguments to configure?Just pass arguments to configure. To pass extra flags for compiling C++, run configure like this: ./configure CXXFLAGS=-magic Similarly for LDFLAGS (for linking), CFLAGS (for compiling C), and CPPFLAGS (for the preprocessor). "./configure --help" will remind you of these. Cheers, Olly