summaryrefslogtreecommitdiff
path: root/qdbm/qmttest.c
diff options
context:
space:
mode:
Diffstat (limited to 'qdbm/qmttest.c')
-rw-r--r--qdbm/qmttest.c300
1 files changed, 300 insertions, 0 deletions
diff --git a/qdbm/qmttest.c b/qdbm/qmttest.c
new file mode 100644
index 00000000..afc8b361
--- /dev/null
+++ b/qdbm/qmttest.c
@@ -0,0 +1,300 @@
+/*************************************************************************************************
+ * Test cases for thread-safety
+ * Copyright (C) 2000-2007 Mikio Hirabayashi
+ * This file is part of QDBM, Quick Database Manager.
+ * QDBM is free software; you can redistribute it and/or modify it under the terms of the GNU
+ * Lesser General Public License as published by the Free Software Foundation; either version
+ * 2.1 of the License or any later version. QDBM is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * You should have received a copy of the GNU Lesser General Public License along with QDBM; if
+ * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA.
+ *************************************************************************************************/
+
+
+#include <depot.h>
+#include <curia.h>
+#include <cabin.h>
+#include <villa.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <time.h>
+
+#if defined(MYPTHREAD)
+#include <sys/types.h>
+#include <pthread.h>
+#endif
+
+#undef TRUE
+#define TRUE 1 /* boolean true */
+#undef FALSE
+#define FALSE 0 /* boolean false */
+
+#define PATHBUFSIZ 1024 /* buffer for paths */
+#define RECBUFSIZ 32 /* buffer for records */
+
+typedef struct { /* type of structure of thread arguments */
+ int id; /* ID of the thread */
+ const char *name; /* prefix of the database */
+ int rnum; /* number of records */
+ int alive; /* alive or not */
+} MYARGS;
+
+
+/* for RISC OS */
+#if defined(__riscos__) || defined(__riscos)
+#include <unixlib/local.h>
+int __riscosify_control = __RISCOSIFY_NO_PROCESS;
+#endif
+
+
+/* global variables */
+const char *progname; /* program name */
+
+
+/* function prototypes */
+int main(int argc, char **argv);
+void usage(void);
+void pdperror(const char *name);
+void *procthread(void *args);
+int dotest(const char *name, int rnum, int tnum);
+
+
+/* main routine */
+int main(int argc, char **argv){
+ char *env, *name;
+ int rv, rnum, tnum;
+ cbstdiobin();
+ if((env = getenv("QDBMDBGFD")) != NULL) dpdbgfd = atoi(env);
+ progname = argv[0];
+ srand(time(NULL));
+ if(argc < 4) usage();
+ name = argv[1];
+ if((rnum = atoi(argv[2])) < 1) usage();
+ if((tnum = atoi(argv[3])) < 1) usage();
+ rv = dotest(name, rnum, tnum);
+ return rv;
+}
+
+
+/* print the usage and exit */
+void usage(void){
+ fprintf(stderr, "%s: test cases for thread-safety\n", progname);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, " %s name rnum tnum\n", progname);
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+
+/* print formatted string and flush the buffer */
+int printfflush(const char *format, ...){
+#if defined(MYPTHREAD)
+ static pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
+ va_list ap;
+ int rv;
+ if(pthread_mutex_lock(&mymutex) != 0) return -1;
+ va_start(ap, format);
+ rv = vprintf(format, ap);
+ if(fflush(stdout) == EOF) rv = -1;
+ va_end(ap);
+ pthread_mutex_unlock(&mymutex);
+ return rv;
+#else
+ va_list ap;
+ int rv;
+ va_start(ap, format);
+ rv = vprintf(format, ap);
+ if(fflush(stdout) == EOF) rv = -1;
+ va_end(ap);
+ return rv;
+#endif
+}
+
+
+/* print an error message */
+void pdperror(const char *name){
+ fprintf(stderr, "%s: %s: %s\n", progname, name, dperrmsg(dpecode));
+}
+
+
+/* pseudo random number generator */
+int myrand(void){
+ static int cnt = 0;
+ return (rand() * rand() + (rand() >> (sizeof(int) * 4)) + (cnt++)) & INT_MAX;
+}
+
+
+/* process the test */
+void *procthread(void *args){
+ MYARGS *myargs;
+ DEPOT *depot;
+ CURIA *curia;
+ VILLA *villa;
+ CBLIST *list;
+ CBMAP *map;
+ char name[PATHBUFSIZ], buf[RECBUFSIZ];
+ int i, err, len;
+ myargs = (MYARGS *)args;
+ err = FALSE;
+ sprintf(name, "%s-%04d", myargs->name, myargs->id);
+ dpremove(name);
+ crremove(name);
+ vlremove(name);
+ switch(myrand() % 4){
+ case 0:
+ printfflush("\n[Depot Test] name=%s rnum=%d\n", name, myargs->rnum);
+ if(!(depot = dpopen(name, DP_OWRITER | DP_OCREAT | DP_OTRUNC, -1))){
+ pdperror(name);
+ return "error";
+ }
+ for(i = 1; i <= myargs->rnum; i++){
+ len = sprintf(buf, "%d", myrand() % i + 1);
+ if(!dpput(depot, buf, len, buf, len, i % 2 == 0 ? DP_DOVER : DP_DCAT)){
+ pdperror(name);
+ err = TRUE;
+ }
+ if(myargs->rnum > 250 && i % (myargs->rnum / 250) == 0){
+ printfflush(".");
+ if(i == myargs->rnum || i % (myargs->rnum / 10) == 0){
+ printfflush("\n%s: (%d)\n", name, i);
+ }
+ }
+ }
+ if(!dpclose(depot)){
+ pdperror(name);
+ err = TRUE;
+ }
+ printfflush("\n%s: finished\n", name);
+ break;
+ case 1:
+ printfflush("\n[Curia Test] name=%s rnum=%d\n", name, myargs->rnum);
+ if(!(curia = cropen(name, CR_OWRITER | CR_OCREAT | CR_OTRUNC, -1, -1))){
+ pdperror(name);
+ return "error";
+ }
+ for(i = 1; i <= myargs->rnum; i++){
+ len = sprintf(buf, "%d", myrand() % i + 1);
+ if(!crput(curia, buf, len, buf, len, i % 2 == 0 ? CR_DOVER : CR_DCAT)){
+ pdperror(name);
+ err = TRUE;
+ }
+ if(myargs->rnum > 250 && i % (myargs->rnum / 250) == 0){
+ printfflush(".");
+ if(i == myargs->rnum || i % (myargs->rnum / 10) == 0){
+ printfflush("\n%s: (%d)\n", name, i);
+ }
+ }
+ }
+ if(!crclose(curia)){
+ pdperror(name);
+ err = TRUE;
+ }
+ printfflush("\n%s: finished\n", name);
+ break;
+ case 2:
+ printfflush("\n[Villa Test] name=%s rnum=%d\n", name, myargs->rnum);
+ if(!(villa = vlopen(name, VL_OWRITER | VL_OCREAT | VL_OTRUNC, VL_CMPLEX))){
+ pdperror(name);
+ return "error";
+ }
+ for(i = 1; i <= myargs->rnum; i++){
+ len = sprintf(buf, "%d", myrand() % i + 1);
+ if(!vlput(villa, buf, len, buf, len, i % 2 == 0 ? VL_DOVER : VL_DDUP)){
+ pdperror(name);
+ err = TRUE;
+ }
+ if(myargs->rnum > 250 && i % (myargs->rnum / 250) == 0){
+ printfflush(".");
+ if(i == myargs->rnum || i % (myargs->rnum / 10) == 0){
+ printfflush("\n%s: (%d)\n", name, i);
+ }
+ }
+ }
+ if(!vlclose(villa)){
+ pdperror(name);
+ err = TRUE;
+ }
+ printfflush("\n%s: finished\n", name);
+ break;
+ case 3:
+ printfflush("\n[Cabin Test] name=%s rnum=%d\n", name, myargs->rnum);
+ list = cblistopen();
+ map = cbmapopen();
+ for(i = 1; i <= myargs->rnum; i++){
+ len = sprintf(buf, "%d", myrand() % i + 1);
+ cblistpush(list, buf, len);
+ cbmapput(map, buf, len, buf, len, i % 2 == 0 ? TRUE : FALSE);
+ if(myargs->rnum > 250 && i % (myargs->rnum / 250) == 0){
+ printfflush(".");
+ if(i == myargs->rnum || i % (myargs->rnum / 10) == 0){
+ printfflush("\n%s: (%d)\n", name, i);
+ }
+ }
+ }
+ cbmapclose(map);
+ cblistclose(list);
+ printfflush("\n%s: finished\n", name);
+ break;
+ }
+ return err ? "error" : NULL;
+}
+
+
+/* drive the test */
+int dotest(const char *name, int rnum, int tnum){
+#if defined(MYPTHREAD)
+ pthread_t *thary;
+ MYARGS *argsary;
+ char *rv;
+ int i, err;
+ printfflush("<Thread-Safety Test>\n name=%s rnum=%d tnum=%d\n", name, rnum, tnum);
+ err = FALSE;
+ thary = cbmalloc(tnum * sizeof(pthread_t));
+ argsary = cbmalloc(tnum * sizeof(MYARGS));
+ for(i = 0; i < tnum; i++){
+ argsary[i].id = i + 1;
+ argsary[i].name = name;
+ argsary[i].rnum = rnum;
+ argsary[i].alive = TRUE;
+ if(pthread_create(thary + i, NULL, procthread, argsary + i) != 0){
+ argsary[i].alive = FALSE;
+ err = TRUE;
+ }
+ }
+ for(i = 0; i < tnum; i++){
+ if(!argsary[i].alive) continue;
+ if(pthread_join(thary[i], (void *)&rv) != 0 || rv) err = TRUE;
+ }
+ free(argsary);
+ free(thary);
+ if(!err) printfflush("\nall ok\n");
+ return err ? 1 : 0;
+#else
+ MYARGS *argsary;
+ int i, err;
+ printfflush("<Thread-Safety Test>\n name=%s rnum=%d tnum=%d\n", name, rnum, tnum);
+ err = FALSE;
+ argsary = cbmalloc(tnum * sizeof(MYARGS));
+ for(i = 0; i < tnum; i++){
+ argsary[i].id = i + 1;
+ argsary[i].name = name;
+ argsary[i].rnum = rnum;
+ argsary[i].alive = TRUE;
+ if(procthread(argsary + i)) err = TRUE;
+ }
+ free(argsary);
+ if(!err) printfflush("\nall ok\n");
+ return err ? 1 : 0;
+#endif
+}
+
+
+
+/* END OF FILE */