16 typedef struct RDBMSDesc {
20 ftsDB* (*init)(char *);
23 static RDBMSDesc DBDesc[] = {
24 { PostgreSQL, "pgsql", "PostgreSQL", PGInit },
25 { MySQL, "mysql", "MySQL", MYInit },
26 { NULLSQL, NULL, NULL, NULL }
35 for(i=0; DBDesc[i].rdbms != NULLSQL; i++) {
36 if ( DBDesc[i].init == NULL )
40 strcat(buf, DBDesc[i].shortname);
42 strcat(buf, "(default)");
47 "ftsbench - full text search benchmark ofr RDBMS\n"
48 "Initialization of DB:\n"
49 "\tftsbench -i [-b RDBMS] [-n NUMROW] [-l LEXFILE] [-g GAMMAFILE] [-f FLAGS] -d DBNAME\n"
50 "FLAGS are comma-separate list of:\n"
51 " gin - use GIN index\n"
52 " gist - use GiST index\n"
53 " func - use functional index\n",
58 "\tftsbench [-b RDBMS] [-c NCLIENTS] [-n NUMQUERY] [-l LEXFILE] [-g GAMMAFILE] [-f FLAGS] -d DBNAME\n"
59 "FLAGS are comma-separate list of:\n"
60 " and - AND'ing lexemes in query (default)\n"
61 " or - OR'ing lexemes in query\n"
62 " sort - sort result of query\n"
64 " -b RDBMS\t- type of DB: ",
70 " -l LEXFILE\t- file with words and its frequents\n"
71 " -g GAMMAFILE\t- file with doc's length distribution\n",
78 getRDBMS(char *name) {
81 for(i=0; DBDesc[i].rdbms != NULLSQL; i++) {
84 return DBDesc[i].rdbms;
85 } else if ( strcasecmp(name,DBDesc[i].shortname) == 0 ) {
86 if ( DBDesc[i].init == NULL ) {
87 fprintf(stderr,"Support of '%s' isn't compiled-in\n", DBDesc[i].longname);
90 return DBDesc[i].rdbms;
94 fprintf(stderr,"Can't find a RDBMS\n");
101 getFLAGS(char *flg) {
104 if ( strcasestr(flg,"gist") )
106 if ( strcasestr(flg,"gin") )
108 if ( strcasestr(flg,"func") )
110 if ( strcasestr(flg,"and") )
112 if ( strcasestr(flg,"or") )
114 if ( strcasestr(flg,"sort") )
117 if ( (flags & FLG_GIST) && (flags & FLG_GIN) ) {
118 fprintf(stderr,"GIN and GiST flags are mutually exclusive\n");
121 if ( (flags & FLG_AND) && (flags & FLG_OR) ) {
122 fprintf(stderr,"AND and OR flags are mutually exclusive\n");
130 initConnections(RDBMS rdbms, int n, char *connstr) {
131 ftsDB **dbs = (ftsDB**)malloc(sizeof(ftsDB*) * n);
135 fprintf(stderr,"Not enough mwmory\n");
140 dbs[i] = DBDesc[rdbms].init(connstr);
141 pthread_mutex_init(&dbs[i]->nqueryMutex, NULL);
148 timediff(struct timeval *begin, struct timeval *end) {
149 return ((double)( end->tv_sec - begin->tv_sec )) + ( (double)( end->tv_usec-begin->tv_usec ) ) / 1.0e+6;
153 elapsedtime(struct timeval *begin) {
155 gettimeofday(&end,NULL);
156 return timediff(begin,&end);
159 static int benchFlags = 0;
160 static int benchCount = 0;
161 static pthread_cond_t condFinish = PTHREAD_COND_INITIALIZER;
162 static pthread_mutex_t mutexFinish = PTHREAD_MUTEX_INITIALIZER;
163 static pthread_mutex_t mutexWordGen = PTHREAD_MUTEX_INITIALIZER;
166 execBench(void *in) {
167 ftsDB *db = (ftsDB*)in;
171 for(i=0;i<benchCount;i++) {
173 * generate_querywords() isn't a thread safe
175 pthread_mutex_lock( &mutexWordGen );
176 words = generate_querywords();
177 pthread_mutex_unlock( &mutexWordGen );
179 db->execQuery(db, words, benchFlags);
184 * send message about exitting
186 pthread_mutex_lock( &mutexFinish );
187 pthread_cond_broadcast( &condFinish );
188 pthread_mutex_unlock( &mutexFinish );
196 main(int argn, char *argv[]) {
198 int n = 0, nclients = 1;
202 RDBMS rdbms = NULLSQL;
205 StringBuf b = {NULL,0,0};
207 while((i=getopt(argn,argv,"ib:n:l:g:d:c:hf:")) != EOF) {
209 case 'i': initMode = 1; break;
210 case 'b': rdbms = getRDBMS(optarg); break;
211 case 'n': n=atoi(optarg); break;
212 case 'c': nclients=atoi(optarg); break;
213 case 'l': lex = strdup(optarg); break;
214 case 'g': doc = strdup(optarg); break;
215 case 'd': dbname = strdup(optarg); break;
216 case 'f': flags = getFLAGS(optarg); break;
223 if (rdbms == NULLSQL)
224 rdbms = getRDBMS(NULL);
226 if ( dbname == NULL || n<0 || nclients<1 )
229 printf("Running with '%s' RDBMS\n", DBDesc[ rdbms ].longname);
232 ftsDB *db = *initConnections(rdbms, 1, dbname);
235 if (!lex) lex = "gendata/lex";
236 if (!doc) doc = "gendata/gamma-lens";
237 finnegan_init(lex, doc);
239 db->startCreateScheme(db, flags);
243 db->InsertRow(db, i+1, b.str);
244 if ( prev!=time(NULL) ) {
245 printf("\r%d(%.02f%%) rows inserted", i, (100.0*i)/n);
250 printf("\r%d(100.00%%) rows inserted. Finalyze insertion... ", i);
252 db->finishCreateScheme(db);
255 ftsDB **dbs = initConnections(rdbms, nclients, dbname);
256 pthread_t *tid = (pthread_t*)malloc( sizeof(pthread_t) * nclients);
257 struct timeval begin;
260 struct timespec sleepTo = { 0, 0 };
265 if (!lex) lex = "gendata/query-lex";
266 if (!doc) doc = "gendata/query-lens";
267 finnegan_init(lex, doc);
272 printf("\r0(0.00%%) queries proceed");
277 gettimeofday(&begin,NULL);
279 pthread_mutex_lock( &mutexFinish );
280 for(i=0;i<nclients;i++) {
281 if ( pthread_create(tid+i, NULL, execBench, (void*)dbs[i]) != 0 ) {
282 fprintf(stderr,"pthread_create failed: %s\n", strerror(errno));
287 printf("\r%d(%.02f%%) queries proceed", 0, 0.0);
294 for(i=0;i<nclients;i++) {
295 pthread_mutex_lock(&dbs[i]->nqueryMutex);
296 total +=dbs[i]->nquery;
297 if ( dbs[i]->nquery < n )
299 pthread_mutex_unlock(&dbs[i]->nqueryMutex);
305 printf("\r%d(%.02f%%) queries proceed", total, (100.0*(float)total)/(nclients * n));
308 sleepTo.tv_sec = time(NULL) + 1;
309 res = pthread_cond_timedwait( &condFinish, &mutexFinish, &sleepTo );
311 if ( !(res == ETIMEDOUT || res == 0) ) {
312 fprintf(stderr,"pthread_cond_timedwait failed: %s", strerror(errno));
316 elapsed = elapsedtime(&begin);
317 pthread_mutex_unlock( &mutexFinish );
319 for(i=0;i<nclients;i++)
320 pthread_join(tid[i], NULL);
322 printf("\r%d(%.02f%%) queries proceed\n", total, (100.0*(float)total)/(nclients * n));
323 printf("Total time: %.02f sec, Queries per second: %.02f\n", elapsed, total/elapsed);