diff --git a/benchmarks/LLADD_THREADED.script b/benchmarks/LLADD_THREADED.script index 86da59d..43a814e 100644 --- a/benchmarks/LLADD_THREADED.script +++ b/benchmarks/LLADD_THREADED.script @@ -1,19 +1,19 @@ -./logicalMultThreaded 200 500 -./logicalMultThreaded 200 750 -./logicalMultThreaded 200 1000 -./logicalMultThreaded 200 1250 -./logicalMultThreaded 200 1500 -./logicalMultThreaded 200 1750 -./logicalMultThreaded 200 2000 -./logicalMultThreaded 200 2250 -./logicalMultThreaded 200 2500 -./logicalMultThreaded 200 2750 -./logicalMultThreaded 200 3000 -./logicalMultThreaded 200 3250 -./logicalMultThreaded 200 3500 -./logicalMultThreaded 200 3750 -./logicalMultThreaded 200 4000 -./logicalMultThreaded 200 4250 -./logicalMultThreaded 200 4500 -./logicalMultThreaded 200 4750 -./logicalMultThreaded 200 5000 +./linearHashNTAThreaded 50 2000 +./linearHashNTAThreaded 50 3000 +./linearHashNTAThreaded 50 4000 +./linearHashNTAThreaded 50 5000 +./linearHashNTAThreaded 50 6000 +./linearHashNTAThreaded 50 7000 +./linearHashNTAThreaded 50 8000 +./linearHashNTAThreaded 50 9000 +./linearHashNTAThreaded 50 10000 +./linearHashNTAThreaded 50 11000 +./linearHashNTAThreaded 50 12000 +./linearHashNTAThreaded 50 13000 +./linearHashNTAThreaded 50 14000 +./linearHashNTAThreaded 50 15000 +./linearHashNTAThreaded 50 16000 +./linearHashNTAThreaded 50 17000 +./linearHashNTAThreaded 50 18000 +./linearHashNTAThreaded 50 19000 +./linearHashNTAThreaded 50 20000 diff --git a/benchmarks/LOGICAL_THREADS.script b/benchmarks/LOGICAL_THREADS.script index 3f7f6a7..26e6043 100644 --- a/benchmarks/LOGICAL_THREADS.script +++ b/benchmarks/LOGICAL_THREADS.script @@ -1,34 +1,34 @@ -./logicalMultThreaded 1 500000 -./logicalMultThreaded 2 250000 -./logicalMultThreaded 3 166666.666666667 -./logicalMultThreaded 4 125000 -./logicalMultThreaded 5 100000 -./logicalMultThreaded 6 83333.3333333333 -./logicalMultThreaded 7 71428.5714285714 -./logicalMultThreaded 8 62500 -./logicalMultThreaded 9 55555.5555555556 -./logicalMultThreaded 10 50000 -./logicalMultThreaded 20 25000 -./logicalMultThreaded 30 16666.6666666667 -./logicalMultThreaded 40 12500 -./logicalMultThreaded 50 10000 -./logicalMultThreaded 60 8333.33333333333 -./logicalMultThreaded 70 7142.85714285714 -./logicalMultThreaded 80 6250 -./logicalMultThreaded 90 5555.55555555556 -./logicalMultThreaded 100 5000 -./logicalMultThreaded 110 4545.45454545455 -./logicalMultThreaded 120 4166.66666666667 -./logicalMultThreaded 130 3846.15384615385 -./logicalMultThreaded 140 3571.42857142857 -./logicalMultThreaded 150 3333.33333333333 -./logicalMultThreaded 160 3125 -./logicalMultThreaded 170 2941.17647058824 -./logicalMultThreaded 180 2777.77777777778 -./logicalMultThreaded 190 2631.57894736842 -./logicalMultThreaded 200 2500 -./logicalMultThreaded 210 2380.95238095238 -./logicalMultThreaded 220 2272.72727272727 -./logicalMultThreaded 230 2173.91304347826 -./logicalMultThreaded 240 2083.33333333333 -./logicalMultThreaded 250 2000 +./linearHashNTAMultiReader 1 50000 +./linearHashNTAMultiReader 2 25000 +./linearHashNTAMultiReader 3 16666.6666666667 +./linearHashNTAMultiReader 4 12500 +./linearHashNTAMultiReader 5 10000 +./linearHashNTAMultiReader 6 8333.33333333333 +./linearHashNTAMultiReader 7 7142.85714285714 +./linearHashNTAMultiReader 8 6250 +./linearHashNTAMultiReader 9 5555.55555555556 +./linearHashNTAMultiReader 10 5000 +./linearHashNTAMultiReader 20 2500 +./linearHashNTAMultiReader 30 1666.66666666667 +./linearHashNTAMultiReader 40 1250 +./linearHashNTAMultiReader 50 1000 +./linearHashNTAMultiReader 60 833.333333333333 +./linearHashNTAMultiReader 70 714.285714285714 +./linearHashNTAMultiReader 80 625 +./linearHashNTAMultiReader 90 555.555555555556 +./linearHashNTAMultiReader 100 500 +./linearHashNTAMultiReader 110 454.545454545455 +./linearHashNTAMultiReader 120 416.666666666667 +./linearHashNTAMultiReader 130 384.615384615385 +./linearHashNTAMultiReader 140 357.142857142857 +./linearHashNTAMultiReader 150 333.333333333333 +./linearHashNTAMultiReader 160 312.5 +./linearHashNTAMultiReader 170 294.117647058824 +./linearHashNTAMultiReader 180 277.777777777778 +./linearHashNTAMultiReader 190 263.157894736842 +./linearHashNTAMultiReader 200 250 +./linearHashNTAMultiReader 210 238.095238095238 +./linearHashNTAMultiReader 220 227.272727272727 +./linearHashNTAMultiReader 230 217.391304347826 +./linearHashNTAMultiReader 240 208.333333333333 +./linearHashNTAMultiReader 250 200 diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am index 1f663ef..2b1a208 100644 --- a/benchmarks/Makefile.am +++ b/benchmarks/Makefile.am @@ -1,7 +1,9 @@ LDADD=$(top_builddir)/src/2pc/lib2pc.a $(top_builddir)/src/libdfa/libdfa.a \ $(top_builddir)/src/lladd/liblladd.a $(top_builddir)/src/pbl/libpbl.a \ $(top_builddir)/src/libdfa/librw.a -bin_PROGRAMS=naiveHash logicalHash readLogicalHash naiveMultiThreaded logicalMultThreaded rawSet arrayListSet logicalMultiReaders linearHashNTA linkedListNTA +bin_PROGRAMS=naiveHash logicalHash readLogicalHash naiveMultiThreaded logicalMultThreaded rawSet \ + arrayListSet logicalMultiReaders linearHashNTA linkedListNTA pageOrientedListNTA \ + linearHashNTAThreaded linearHashNTAMultiReader linearHashNTAWriteRequests AM_CFLAGS= -g -Wall -pedantic -std=gnu99 SUBDIRS=berkeleyDB diff --git a/benchmarks/berkeleyDB/Makefile.am b/benchmarks/berkeleyDB/Makefile.am index d8a75c1..43f59b3 100644 --- a/benchmarks/berkeleyDB/Makefile.am +++ b/benchmarks/berkeleyDB/Makefile.am @@ -1,3 +1,3 @@ LDADD=-ldb -lpthread -bin_PROGRAMS=transapp bdbRaw bdbHash +bin_PROGRAMS=transapp bdbRaw bdbHash bdbHashThreaded AM_CFLAGS=-g diff --git a/benchmarks/berkeleyDB/bdbHashThreaded.c b/benchmarks/berkeleyDB/bdbHashThreaded.c new file mode 100644 index 0000000..6685072 --- /dev/null +++ b/benchmarks/berkeleyDB/bdbHashThreaded.c @@ -0,0 +1,681 @@ +#include +#include + +#include +#include + +// if we're using linux's crazy version of the pthread header, +// it probably forgot to include PTHREAD_STACK_MIN + +#ifndef PTHREAD_STACK_MIN +#include +#endif + +#include +#include +#include +#include +#include +#include + +#define ENV_DIRECTORY "TXNAPP" + +int activeThreads = 0; +int max_active = 0; + +pthread_mutex_t mutex; + + +void add_cat(DB_ENV *, DB *, char *, ...); +void run_xact(DB_ENV *, DB *, int, int); +/*void add_color(DB_ENV *, DB *, char *, int); + void add_fruit(DB_ENV *, DB *, char *, char *); */ +void *checkpoint_thread(void *); +void log_archlist(DB_ENV *); +void *logfile_thread(void *); +void db_open(DB_ENV *, DB **, char *, int); +void env_dir_create(void); +void env_open(DB_ENV **); +void usage(void); + +DB_ENV *dbenv; +DB *db_cats; /*, *db_color, *db_fruit; */ + +int num_xact; +int insert_per_xact; +void * runThread(void * arg); +int +main(int argc, char *argv[]) +{ + extern int optind; + + pthread_t ptid; + int ch, ret; + + /* while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; */ + + assert(argc == 3); + /* threads have static thread sizes. Ughh. */ + pthread_attr_t attr; + pthread_attr_init(&attr); + + pthread_mutex_init(&mutex, NULL); + + pthread_attr_setstacksize (&attr, 4 * PTHREAD_STACK_MIN); + + pthread_mutex_lock(&mutex); + + + + env_dir_create(); + env_open(&dbenv); + + /* Start a checkpoint thread. */ + if ((ret = pthread_create( + &ptid, &attr, checkpoint_thread, (void *)dbenv)) != 0) { + fprintf(stderr, + "txnapp: failed spawning checkpoint thread: %s\n", + strerror(ret)); + exit (1); + } + + /* Start a logfile removal thread. */ + if ((ret = pthread_create( + &ptid, &attr, logfile_thread, (void *)dbenv)) != 0) { + fprintf(stderr, + "txnapp: failed spawning log file removal thread: %s\n", + strerror(ret)); + exit (1); + } + + /* Open database: Key is fruit class; Data is specific type. */ + /* db_open(dbenv, &db_fruit, "fruit", 0); */ + + /* Open database: Key is a color; Data is an integer. */ + /*db_open(dbenv, &db_color, "color", 0); */ + + /* + * Open database: + * Key is a name; Data is: company name, address, cat breeds. + */ + db_open(dbenv, &db_cats, "cats", 1); + + /* add_fruit(dbenv, db_fruit, "apple", "yellow delicious"); + + add_color(dbenv, db_color, "blue", 0); + add_color(dbenv, db_color, "blue", 3); */ + + /* add_cat(dbenv, db_cats, + "Amy Adams", + "Sleepycat Software", + "394 E. Riding Dr., Carlisle, MA 01741, USA", + "abyssinian", + "bengal", + "chartreaux", + NULL);*/ + int r; + int num_threads = atoi(argv[1]); + /*int */num_xact = 1; //atoi(argv[2]); //100; + /*int */insert_per_xact = atoi(argv[2]); //1000; + // int num_threads = 100; + + + + pthread_t * threads = malloc(num_threads * sizeof(pthread_t)); + int i ; + for(i = 0; i < num_threads; i++) { + + if ((ret = pthread_create(&(threads[i]), &attr, runThread, (void *)i)) != 0){ + fprintf(stderr, + "txnapp: failed spawning worker thread: %s\n", + strerror(ret)); + exit (1); + } + + + /* + for(r = 0; r < num_xact; r ++) { + run_xact(dbenv, db_cats, 1+r*insert_per_xact, insert_per_xact); + } + */ + + } + + pthread_mutex_unlock(&mutex); + + for(i = 0; i < num_threads; i++) { + pthread_join(threads[i], NULL); + } + + free(threads); + + return (0); +} + + +void * runThread(void * arg) { + int offset = (int) arg; + + pthread_mutex_lock(&mutex); + activeThreads++; + if(activeThreads > max_active) { + max_active = activeThreads; + } + pthread_mutex_unlock(&mutex); + + + int r; + + for(r = 0; r < num_xact; r ++) { + run_xact(dbenv, db_cats, offset*(1+r)*insert_per_xact, insert_per_xact); + } + + pthread_mutex_lock(&mutex); + activeThreads--; + pthread_mutex_unlock(&mutex); + + + // printf("%d done\n", offset); +} + + +void +env_dir_create() +{ + struct stat sb; + + /* + * If the directory exists, we're done. We do not further check + * the type of the file, DB will fail appropriately if it's the + * wrong type. + */ + if (stat(ENV_DIRECTORY, &sb) == 0) + return; + + /* Create the directory, read/write/access owner only. */ + if (mkdir(ENV_DIRECTORY, S_IRWXU) != 0) { + fprintf(stderr, + "txnapp: mkdir: %s: %s\n", ENV_DIRECTORY, strerror(errno)); + exit (1); + } +} + +void +env_open(DB_ENV **dbenvp) +{ + DB_ENV *dbenv; + int ret; + + /* Create the environment handle. */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, + "txnapp: db_env_create: %s\n", db_strerror(ret)); + exit (1); + } + + /* Set up error handling. */ + dbenv->set_errpfx(dbenv, "txnapp"); + dbenv->set_errfile(dbenv, stderr); + + /* Do deadlock detection internally. */ + if ((ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT)) != 0) { + dbenv->err(dbenv, ret, "set_lk_detect: DB_LOCK_DEFAULT"); + exit (1); + } + + /* + * Open a transactional environment: + * create if it doesn't exist + * free-threaded handle + * run recovery + * read/write owner only + */ + if ((ret = dbenv->open(dbenv, ENV_DIRECTORY, + DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | + DB_INIT_MPOOL | DB_INIT_TXN | DB_RECOVER | DB_THREAD, + S_IRUSR | S_IWUSR)) != 0) { + dbenv->err(dbenv, ret, "dbenv->open: %s", ENV_DIRECTORY); + exit (1); + } + + *dbenvp = dbenv; +} + +void * +checkpoint_thread(void *arg) +{ + DB_ENV *dbenv; + int ret; + + dbenv = arg; + dbenv->errx(dbenv, "Checkpoint thread: %lu", (u_long)pthread_self()); + + /* Checkpoint once a minute. */ + for (;; sleep(60)) + if ((ret = dbenv->txn_checkpoint(dbenv, 0, 0, 0)) != 0) { + dbenv->err(dbenv, ret, "checkpoint thread"); + exit (1); + } + + /* NOTREACHED */ +} + +void * +logfile_thread(void *arg) +{ + DB_ENV *dbenv; + int ret; + char **begin, **list; + + dbenv = arg; + dbenv->errx(dbenv, + "Log file removal thread: %lu", (u_long)pthread_self()); + + /* Check once every 5 minutes. */ + for (;; sleep(300)) { + /* Get the list of log files. */ + if ((ret = + dbenv->log_archive(dbenv, &list, DB_ARCH_ABS)) != 0) { + dbenv->err(dbenv, ret, "DB_ENV->log_archive"); + exit (1); + } + + /* Remove the log files. */ + if (list != NULL) { + for (begin = list; *list != NULL; ++list) + if ((ret = remove(*list)) != 0) { + dbenv->err(dbenv, + ret, "remove %s", *list); + exit (1); + } + free (begin); + } + } + /* NOTREACHED */ +} + +void +log_archlist(DB_ENV *dbenv) +{ + int ret; + char **begin, **list; + + /* Get the list of database files. */ + if ((ret = dbenv->log_archive(dbenv, + &list, DB_ARCH_ABS | DB_ARCH_DATA)) != 0) { + dbenv->err(dbenv, ret, "DB_ENV->log_archive: DB_ARCH_DATA"); + exit (1); + } + if (list != NULL) { + for (begin = list; *list != NULL; ++list) + printf("database file: %s\n", *list); + free (begin); + } + + /* Get the list of log files. */ + if ((ret = dbenv->log_archive(dbenv, + &list, DB_ARCH_ABS | DB_ARCH_LOG)) != 0) { + dbenv->err(dbenv, ret, "DB_ENV->log_archive: DB_ARCH_LOG"); + exit (1); + } + if (list != NULL) { + for (begin = list; *list != NULL; ++list) + printf("log file: %s\n", *list); + free (begin); + } +} + +void +db_open(DB_ENV *dbenv, DB **dbp, char *name, int dups) +{ + DB *db; + int ret; + + /* Create the database handle. */ + if ((ret = db_create(&db, dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "db_create"); + exit (1); + } + + /* Optionally, turn on duplicate data items. */ + /* if (dups && (ret = db->set_flags(db, DB_DUP)) != 0) { + dbenv->err(dbenv, ret, "db->set_flags: DB_DUP"); + exit (1); + } */ + + /* + * Open a database in the environment: + * create if it doesn't exist + * free-threaded handle + * read/write owner only + */ + if ((ret = db->open(db, NULL, name, NULL, /*DB_BTREE*//* DB_RECNO */DB_HASH, + DB_AUTO_COMMIT | DB_DIRTY_READ | DB_TXN_SYNC | DB_CREATE | DB_THREAD, S_IRUSR | S_IWUSR)) != 0) { + (void)db->close(db, 0); + dbenv->err(dbenv, ret, "db->open: %s", name); + exit (1); + } + + *dbp = db; +} + +void +add_fruit(DB_ENV *dbenv, DB *db, char *fruit, char *name) +{ + DBT key, data; + DB_TXN *tid; + int ret; + + /* Initialization. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = fruit; + key.size = strlen(fruit); + data.data = name; + data.size = strlen(name); + + for (;;) { + /* Begin the transaction. */ + if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) { + dbenv->err(dbenv, ret, "DB_ENV->txn_begin"); + exit (1); + } + + /* Store the value. */ + switch (ret = db->put(db, tid, &key, &data, 0)) { + case 0: + /* Success: commit the change. */ + if ((ret = tid->commit(tid, 0)) != 0) { + dbenv->err(dbenv, ret, "DB_TXN->commit"); + exit (1); + } + return; + case DB_LOCK_DEADLOCK: + /* Deadlock: retry the operation. */ + if ((ret = tid->abort(tid)) != 0) { + dbenv->err(dbenv, ret, "DB_TXN->abort"); + exit (1); + } + break; + default: + /* Error: run recovery. */ + dbenv->err(dbenv, ret, "dbc->put: %s/%s", fruit, name); + exit (1); + } + } +} + +void +add_color(DB_ENV *dbenv, DB *dbp, char *color, int increment) +{ + DBT key, data; + DB_TXN *tid; + int original, ret; + char buf[64]; + + /* Initialization. */ + memset(&key, 0, sizeof(key)); + key.data = color; + key.size = strlen(color); + memset(&data, 0, sizeof(data)); + data.flags = DB_DBT_MALLOC; + + for (;;) { + /* Begin the transaction. */ + if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) { + dbenv->err(dbenv, ret, "DB_ENV->txn_begin"); + exit (1); + } + + /* + * Get the key. If it exists, we increment the value. If it + * doesn't exist, we create it. + */ + switch (ret = dbp->get(dbp, tid, &key, &data, 0)) { + case 0: + original = atoi(data.data); + break; + case DB_LOCK_DEADLOCK: + /* Deadlock: retry the operation. */ + if ((ret = tid->abort(tid)) != 0) { + dbenv->err(dbenv, ret, "DB_TXN->abort"); + exit (1); + } + continue; + case DB_NOTFOUND: + original = 0; + break; + default: + /* Error: run recovery. */ + dbenv->err( + dbenv, ret, "dbc->get: %s/%d", color, increment); + exit (1); + } + if (data.data != NULL) + free(data.data); + + /* Create the new data item. */ + (void)snprintf(buf, sizeof(buf), "%d", original + increment); + data.data = buf; + data.size = strlen(buf) + 1; + + /* Store the new value. */ + switch (ret = dbp->put(dbp, tid, &key, &data, 0)) { + case 0: + /* Success: commit the change. */ + if ((ret = tid->commit(tid, 0)) != 0) { + dbenv->err(dbenv, ret, "DB_TXN->commit"); + exit (1); + } + return; + case DB_LOCK_DEADLOCK: + /* Deadlock: retry the operation. */ + if ((ret = tid->abort(tid)) != 0) { + dbenv->err(dbenv, ret, "DB_TXN->abort"); + exit (1); + } + break; + default: + /* Error: run recovery. */ + dbenv->err( + dbenv, ret, "dbc->put: %s/%d", color, increment); + exit (1); + } + } +} + +void +add_cat(DB_ENV *dbenv, DB *db, char *name, ...) +{ + va_list ap; + DBC *dbc; + DBT key, data; + DB_TXN *tid; + int ret; + char *s; + + /* Initialization. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = name; + key.size = strlen(name); + +retry: /* Begin the transaction. */ + if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) { + dbenv->err(dbenv, ret, "DB_ENV->txn_begin"); + exit (1); + } + + /* Delete any previously existing item. */ + switch (ret = db->del(db, tid, &key, 0)) { + case 0: + case DB_NOTFOUND: + break; + case DB_LOCK_DEADLOCK: + /* Deadlock: retry the operation. */ + if ((ret = tid->abort(tid)) != 0) { + dbenv->err(dbenv, ret, "DB_TXN->abort"); + exit (1); + } + goto retry; + default: + dbenv->err(dbenv, ret, "db->del: %s", name); + exit (1); + } + + /* Create a cursor. */ + if ((ret = db->cursor(db, tid, &dbc, 0)) != 0) { + dbenv->err(dbenv, ret, "db->cursor"); + exit (1); + } + + /* Append the items, in order. */ + va_start(ap, name); + while ((s = va_arg(ap, char *)) != NULL) { + data.data = s; + data.size = strlen(s); + switch (ret = dbc->c_put(dbc, &key, &data, DB_KEYLAST)) { + case 0: + break; + case DB_LOCK_DEADLOCK: + va_end(ap); + + /* Deadlock: retry the operation. */ + if ((ret = dbc->c_close(dbc)) != 0) { + dbenv->err( + dbenv, ret, "dbc->c_close"); + exit (1); + } + if ((ret = tid->abort(tid)) != 0) { + dbenv->err(dbenv, ret, "DB_TXN->abort"); + exit (1); + } + goto retry; + default: + /* Error: run recovery. */ + dbenv->err(dbenv, ret, "dbc->put: %s/%s", name, s); + exit (1); + } + } + va_end(ap); + + /* Success: commit the change. */ + if ((ret = dbc->c_close(dbc)) != 0) { + dbenv->err(dbenv, ret, "dbc->c_close"); + exit (1); + } + if ((ret = tid->commit(tid, 0)) != 0) { + dbenv->err(dbenv, ret, "DB_TXN->commit"); + exit (1); + } +} + +void +run_xact(DB_ENV *dbenv, DB *db, int offset, int count) +{ + va_list ap; + DBC *dbc; + DBT key, data; + DB_TXN *tid; + int ret; + char *s; + + /* Initialization. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + int keyPtr; + int valPtr; + key.data = &keyPtr; + key.size = sizeof(int);/*strlen(name);*/ + data.data = &valPtr; + data.size = sizeof(int); + +retry: /* Begin the transaction. */ + if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) { + dbenv->err(dbenv, ret, "DB_ENV->txn_begin"); + exit (1); + } + + /* Delete any previously existing item. */ + /* switch (ret = db->del(db, tid, &key, 0)) { + case 0: + case DB_NOTFOUND: + break; + case DB_LOCK_DEADLOCK: + / * Deadlock: retry the operation. * / + if ((ret = tid->abort(tid)) != 0) { + dbenv->err(dbenv, ret, "DB_TXN->abort"); + exit (1); + } + goto retry; + default: + dbenv->err(dbenv, ret, "db->del: %s", name); + exit (1); + } */ + + /* Create a cursor. */ + if ((ret = db->cursor(db, tid, &dbc, 0)) != 0) { + dbenv->err(dbenv, ret, "db->cursor"); + exit (1); + } + + /* Append the items, in order. */ + // va_start(ap, name); + // while ((s = va_arg(ap, char *)) != NULL) { + int q; + for(q = offset; q < offset + count; q++) { + keyPtr = q; + valPtr = q; + /* data.data = s; + data.size = strlen(s); */ + // printf("A"); fflush(NULL); + switch (ret = dbc->c_put(dbc, &key, &data, DB_KEYLAST)) { + case 0: + // printf("B"); fflush(NULL); + break; + case DB_LOCK_DEADLOCK: + va_end(ap); + + /* Deadlock: retry the operation. */ + if ((ret = dbc->c_close(dbc)) != 0) { + dbenv->err( + dbenv, ret, "dbc->c_close"); + exit (1); + } + if ((ret = tid->abort(tid)) != 0) { + dbenv->err(dbenv, ret, "DB_TXN->abort"); + exit (1); + } + goto retry; + default: + /* Error: run recovery. */ + dbenv->err(dbenv, ret, "dbc->put: %d/%d", q, q); + exit (1); + } + } + va_end(ap); + + /* Success: commit the change. */ + if ((ret = dbc->c_close(dbc)) != 0) { + dbenv->err(dbenv, ret, "dbc->c_close"); + exit (1); + } + if ((ret = tid->commit(tid, 0)) != 0) { + dbenv->err(dbenv, ret, "DB_TXN->commit"); + exit (1); + } +} + +void +usage() +{ + (void)fprintf(stderr, "usage: txnapp\n"); + exit(1); +} diff --git a/benchmarks/generateScripts.pl b/benchmarks/generateScripts.pl index 79f01ae..ff9409c 100755 --- a/benchmarks/generateScripts.pl +++ b/benchmarks/generateScripts.pl @@ -2,6 +2,7 @@ use strict; +my $num_threads = 50; ## This perl script generates the input to timer.pl, which in turn ## generates the input to plotting.pl, which generates performance @@ -14,26 +15,46 @@ open(LLADD_RAW_PHYSICAL, ">LLADD_RAW_PHYSICAL.script"); open(BDB_RAW_INSERT, ">BDB_RAW_INSERT.script" ); open(BDB_HASH_INSERT, ">BDB_HASH_INSERT.script" ); +# New tests + +open(LLADD_NTA, ">LLADD_NTA.script"); +open(LLADD_LINKED_LIST, ">LLADD_LINKED_LIST.script"); +open(LLADD_PAGED_LIST, ">LLADD_PAGED_LIST.script"); +open(BDB_HASH_THREADED, ">BDB_HASH_THREADED.script"); + open(EVERYTHING, ">EVERYTHING.script" ); for(my $i = 1; $i <= 10; $i += .5) { my $insert_count = $i * 100000; - my $threaded_insert_count = $insert_count / 200; + my $threaded_insert_count = $insert_count / $num_threads; - print LLADD_THREADED "./logicalMultThreaded 200 $threaded_insert_count\n"; + print LLADD_THREADED "./linearHashNTAThreaded $num_threads $threaded_insert_count\n"; print LLADD_LOGICAL "./logicalHash 1 $insert_count\n"; print LLADD_PHYSICAL "./naiveHash 1 $insert_count\n"; print LLADD_RAW_PHYSICAL "./arrayListSet 1 $insert_count\n"; print BDB_RAW_INSERT "./berkeleyDB/bdbRaw 1 $insert_count\n"; print BDB_HASH_INSERT "./berkeleyDB/bdbHash 1 $insert_count\n"; - print EVERYTHING "./logicalMultThreaded 200 $threaded_insert_count\n"; + print LLADD_NTA "./linearHashNTA 1 $insert_count\n"; + print LLADD_LINKED_LIST "./linkedListNTA 1 $insert_count\n"; + print LLADD_PAGED_LIST "./pageOrientedListNTA 1 $insert_count\n"; + + print BDB_HASH_THREADED "./berkeleyDB/bdbHashThreaded $num_threads $threaded_insert_count\n"; + + + print EVERYTHING "./linearHashNTAThreaded $num_threads $threaded_insert_count\n"; print EVERYTHING "./logicalHash 1 $insert_count\n"; print EVERYTHING "./naiveHash 1 $insert_count\n"; print EVERYTHING "./arrayListSet 1 $insert_count\n"; print EVERYTHING "./berkeleyDB/bdbRaw 1 $insert_count\n"; + + print EVERYTHING "./linearHashNTA 1 $insert_count\n"; + print EVERYTHING "./linkedListNTA 1 $insert_count\n"; + print EVERYTHING "./pageOrientedListNTA 1 $insert_count\n"; + if($i < 4) { + print EVERYTHING "./berkeleyDB/bdbHashThreaded $num_threads $threaded_insert_count\n"; print EVERYTHING "./berkeleyDB/bdbHash 1 $insert_count\n"; } @@ -46,3 +67,7 @@ close(LLADD_RAW_PHYSICAL); close(BDB_RAW_INSERT); close(BDB_HASH_INSERT); close(EVERYTHING); +close(LLADD_NTA); +close(LLADD_LINKED_LIST); +close(LLADD_PAGED_LIST); +close(BDB_HASH_THREADED); diff --git a/benchmarks/generateScriptsThreads.pl b/benchmarks/generateScriptsThreads.pl index 82f1054..acde81a 100644 --- a/benchmarks/generateScriptsThreads.pl +++ b/benchmarks/generateScriptsThreads.pl @@ -10,26 +10,28 @@ use strict; open(LOGICAL_THREADS, ">LOGICAL_THREADS.script" ); for(my $i = 1; $i < 10; $i ++) { - my $total = 500000; + # my $total = 500000; + my $total = 50000; my $thread_count = $i; my $insert_count = $total / $i; - print LOGICAL_THREADS "./logicalMultThreaded $thread_count $insert_count\n"; +# print LOGICAL_THREADS "./logicalMultThreaded $thread_count $insert_count\n"; + print LOGICAL_THREADS "./linearHashNTAMultiReader $thread_count $insert_count\n"; } for(my $i = 10; $i <= 254; $i += 10) { - my $total = 500000; - +# my $total = 500000; + my $total = 50000; my $thread_count = $i; my $insert_count = $total / $i; - print LOGICAL_THREADS "./logicalMultThreaded $thread_count $insert_count\n"; - +# print LOGICAL_THREADS "./logicalMultThreaded $thread_count $insert_count\n"; + print LOGICAL_THREADS "./linearHashNTAMultiReader $thread_count $insert_count\n"; } close(LOGICAL_THREADS); diff --git a/benchmarks/linearHashNTA.c b/benchmarks/linearHashNTA.c index 2234948..4bc18f2 100644 --- a/benchmarks/linearHashNTA.c +++ b/benchmarks/linearHashNTA.c @@ -22,6 +22,7 @@ int main(int argc, char** argv) { int xid = Tbegin(); recordid hash = ThashCreate(xid, sizeof(int), sizeof(int)); + //recordid hash = ThashCreate(xid, VARIABLE_LENGTH, VARIABLE_LENGTH); Tcommit(xid); diff --git a/benchmarks/linearHashNTAMultiReader.c b/benchmarks/linearHashNTAMultiReader.c new file mode 100644 index 0000000..e282f2b --- /dev/null +++ b/benchmarks/linearHashNTAMultiReader.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +#include + +// if we're using linux's crazy version of the pthread header, +// it probably forgot to include PTHREAD_STACK_MIN + +#ifndef PTHREAD_STACK_MIN +#include +#endif + + +int i = 0; +int max_active = 0; + +pthread_mutex_t mutex; + +//static pthread_mutex_t hash_mutex = PTHREAD_MUTEX_INITIALIZER; +static int count; +static recordid hash; + +static void * go (void * arg_ptr) { + + pthread_mutex_lock(&mutex); + i++; + if(i > max_active) { + max_active = i; + } + pthread_mutex_unlock(&mutex); + + // pthread_mutex_lock(&hash_mutex); + + int k = *(int*)arg_ptr; + int j; + int xid = Tbegin(); + + unsigned int seed = k; + + for(j = 0; j < count ; j++) { + unsigned int r = rand_r(&seed) % 10000; + int * tmp = NULL; + ThashLookup(xid, hash, (byte*)&r, sizeof(int), (byte**)&tmp); + assert(r == *tmp); + } + // for(j = k * count; j < (k+1) *(count) ; j++) { + // TlogicalHashInsert(xid, hash, &j, sizeof(int), &j, sizeof(int)); + // printf("(%d)", k); + //} + + Tcommit(xid); + /* + for(j = k * count; j < (k+1) *(count) ; j++) { + int tmp = -100; + TlogicalHashLookup(xid, hash, &j, sizeof(int), &tmp, sizeof(int)); + assert(j == tmp); + } */ + + + // pthread_mutex_unlock(&hash_mutex); + + pthread_mutex_lock(&mutex); + i--; + pthread_mutex_unlock(&mutex); + + + return NULL; +} + + +int main(int argc, char** argv) { + + assert(argc == 3); + + int thread_count = atoi(argv[1]); + count = atoi(argv[2]); + + /* unlink("storefile.txt"); + unlink("logfile.txt"); + unlink("blob0_file.txt"); + unlink("blob1_file.txt");*/ + + pthread_t * workers = malloc(sizeof(pthread_t) * thread_count); + + Tinit(); + int xid = Tbegin(); + hash = ThashCreate(xid, sizeof(int), sizeof(int)); + + int k; + + for(k = 0; k < 20000; k++) { + ThashInsert(xid, hash, (byte*)&k, sizeof(int), (byte*)&k, sizeof(int)); + } + + Tcommit(xid); + + /* threads have static thread sizes. Ughh. */ + pthread_attr_t attr; + pthread_attr_init(&attr); + + pthread_mutex_init(&mutex, NULL); + + pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN); + + pthread_mutex_lock(&mutex); + + for(k = 0; k < thread_count; k++) { + int * k_copy = malloc(sizeof(int)); + *k_copy = k ; + pthread_create(&workers[k], &attr, go, k_copy); + + } + + pthread_mutex_unlock(&mutex); + + + for(k = 0; k < thread_count; k++) { + pthread_join(workers[k],NULL); + } + + Tdeinit(); + + printf("Max active at once: %d\n", max_active); + +} diff --git a/benchmarks/linearHashNTAThreaded.c b/benchmarks/linearHashNTAThreaded.c new file mode 100644 index 0000000..528aa07 --- /dev/null +++ b/benchmarks/linearHashNTAThreaded.c @@ -0,0 +1,159 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + + +// if we're using linux's crazy version of the pthread header, +// it probably forgot to include PTHREAD_STACK_MIN + +#ifndef PTHREAD_STACK_MIN +#include +#endif + +int activeThreads = 0; +int max_active = 0; + +double avg_var = 0; +double max_var = 0; +double avg_mean = 0; +double max_mean = 0; + +pthread_mutex_t mutex; + +//static pthread_mutex_t hash_mutex = PTHREAD_MUTEX_INITIALIZER; +static int count; +static recordid hash; + +static void * go (void * arg_ptr) { + // pthread_mutex_lock(&hash_mutex); + + pthread_mutex_lock(&mutex); + activeThreads++; + if(activeThreads > max_active) { + max_active = activeThreads; + } + pthread_mutex_unlock(&mutex); + + int k = *(int*)arg_ptr; + int j; + int xid = Tbegin(); + + double sum_x_squared = 0; + double sum = 0; + + for(j = k * count; j < (k+1) *(count) ; j++) { + + struct timeval start, endtime; + + gettimeofday(&start, NULL); + + ThashInsert(xid, hash, (byte*)&j, sizeof(int), (byte*)&j, sizeof(int)); + + gettimeofday(&endtime, NULL); + + double microSecondsPassed = 1000000 * (endtime.tv_sec - start.tv_sec); + + microSecondsPassed = (microSecondsPassed + endtime.tv_usec) - start.tv_usec; + + sum += microSecondsPassed; + sum_x_squared += (microSecondsPassed * microSecondsPassed) ; + + + // printf("(%d)", k); + } + + + Tcommit(xid); + /* + for(j = k * count; j < (k+1) *(count) ; j++) { + int tmp = -100; + TlogicalHashLookup(xid, hash, &j, sizeof(int), &tmp, sizeof(int)); + assert(j == tmp); + } */ + + double count_d = count; + double mean = sum / count_d; + double variance = sqrt((sum_x_squared / count_d) - (mean * mean)); + + + + // pthread_mutex_unlock(&hash_mutex); + + pthread_mutex_lock(&mutex); + activeThreads--; + + avg_mean += mean; + avg_var += variance; + + if(mean > max_mean ) { max_mean = mean; } + if(variance > max_var) { max_var = variance; } + + pthread_mutex_unlock(&mutex); + + + return NULL; +} + + +int main(int argc, char** argv) { + + assert(argc == 3); + + int thread_count = atoi(argv[1]); + count = atoi(argv[2]); + + unlink("storefile.txt"); + unlink("logfile.txt"); + unlink("blob0_file.txt"); + unlink("blob1_file.txt"); + + pthread_t * workers = malloc(sizeof(pthread_t) * thread_count); + + Tinit(); + int xid = Tbegin(); + hash = ThashCreate(xid, sizeof(int), sizeof(int)); + + Tcommit(xid); + + int k; + + /* threads have static thread sizes. Ughh. */ + pthread_attr_t attr; + pthread_attr_init(&attr); + + pthread_mutex_init(&mutex, NULL); + + pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN); + pthread_attr_setschedpolicy(&attr, SCHED_FIFO); + pthread_mutex_lock(&mutex); + + + for(k = 0; k < thread_count; k++) { + int * k_copy = malloc(sizeof(int)); + *k_copy = k ; + pthread_create(&workers[k], &attr, go, k_copy); + + } + + pthread_mutex_unlock(&mutex); + + for(k = 0; k < thread_count; k++) { + pthread_join(workers[k],NULL); + } + + + printf("mean: (max, avg) %f, %f\n", max_mean, avg_mean / (double)thread_count); + + printf("variance: (max, avg) %f, %f\n", max_var, avg_var / (double)thread_count); + + + Tdeinit(); +} diff --git a/benchmarks/linearHashNTAWriteRequests.c b/benchmarks/linearHashNTAWriteRequests.c new file mode 100644 index 0000000..9be0249 --- /dev/null +++ b/benchmarks/linearHashNTAWriteRequests.c @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +pthread_cond_t never; +pthread_mutex_t mutex; + +#define MAX_SECONDS 100 + +#define COUNTER_RESOLUTION 240 + +int buckets[COUNTER_RESOLUTION]; + +// if we're using linux's crazy version of the pthread header, +// it probably forgot to include PTHREAD_STACK_MIN + +#ifndef PTHREAD_STACK_MIN +#include +#endif + +int activeThreads = 0; +int max_active = 0; + +/*double avg_var = 0; +double max_var = 0; +double avg_mean = 0; +double max_mean = 0;*/ + +//static pthread_mutex_t hash_mutex = PTHREAD_MUTEX_INITIALIZER; +static int count; +static recordid hash; + +static void * go (void * arg_ptr) { + // pthread_mutex_lock(&hash_mutex); + + pthread_mutex_lock(&mutex); + activeThreads++; + if(activeThreads > max_active) { + max_active = activeThreads; + } + pthread_mutex_unlock(&mutex); + + int k = *(int*)arg_ptr; + int j; + int xid = Tbegin(); + + double sum_x_squared = 0; + double sum = 0; + + double log_multiplier = COUNTER_RESOLUTION / log(MAX_SECONDS * 1000000000.0); + + struct timeval timeout_tv; + struct timespec timeout; + + gettimeofday(&timeout_tv, NULL); + + timeout.tv_sec = timeout_tv.tv_sec; + timeout.tv_nsec = 1000 * timeout_tv.tv_usec; + + timeout.tv_nsec = (int)(1000000000.0 * ((double)random() / (double)RAND_MAX)); + + timeout.tv_sec++; + + // struct timeval start; + + pthread_mutex_lock(&mutex); + pthread_cond_timedwait(&never, &mutex, &timeout); + pthread_mutex_unlock(&mutex); + + + /* gettimeofday(&start, NULL); + assert(timeout.tv_sec <= start.tv_sec); + assert(timeout.tv_nsec <= start.tv_nsec || timeout.tv_sec < start.tv_sec);*/ + + + + for(j = k * count; j < (k+1) *(count) ; j++) { + + + // struct timeval start, + struct timeval endtime_tv; + struct timespec endtime; + // gettimeofday(&start, NULL); + + + // start = timeout; + + + /* gettimeofday(&start, NULL); + assert(timeout.tv_sec <= start.tv_sec); + assert(timeout.tv_nsec <= start.tv_nsec || timeout.tv_sec < start.tv_sec); + */ + + + + ThashInsert(xid, hash, (byte*)&j, sizeof(int), (byte*)&j, sizeof(int)); + + gettimeofday(&endtime_tv, NULL); + + endtime.tv_sec = endtime_tv.tv_sec; + endtime.tv_nsec = 1000 * endtime_tv.tv_usec; + + double microSecondsPassed = 1000000000.0 * (double)(endtime.tv_sec - timeout.tv_sec); + + + microSecondsPassed = (microSecondsPassed + (double)endtime.tv_nsec) - (double)timeout.tv_nsec; + + assert(microSecondsPassed > 0.0); + + + sum += microSecondsPassed; + sum_x_squared += (microSecondsPassed * microSecondsPassed) ; + + int bucket = (log_multiplier * log(microSecondsPassed)); + + if(bucket >= COUNTER_RESOLUTION) { bucket = COUNTER_RESOLUTION - 1; } + + timeout.tv_sec++; + pthread_mutex_lock(&mutex); + buckets[bucket]++; + pthread_cond_timedwait(&never, &mutex, &timeout); + pthread_mutex_unlock(&mutex); + + // printf("(%d)", k); + } + + + Tcommit(xid); + /* + for(j = k * count; j < (k+1) *(count) ; j++) { + int tmp = -100; + TlogicalHashLookup(xid, hash, &j, sizeof(int), &tmp, sizeof(int)); + assert(j == tmp); + } */ + + // double count_d = count; + // double mean = sum / count_d; + // double variance = sqrt((sum_x_squared / count_d) - (mean * mean)); + + + + // pthread_mutex_unlock(&hash_mutex); + + pthread_mutex_lock(&mutex); + activeThreads--; + + /* avg_mean += mean; + avg_var += variance; + + if(mean > max_mean ) { max_mean = mean; } + if(variance > max_var) { max_var = variance; } */ + + pthread_mutex_unlock(&mutex); + + + return NULL; +} + + +int main(int argc, char** argv) { + + assert(argc == 3); + + int thread_count = atoi(argv[1]); + count = atoi(argv[2]); + + unlink("storefile.txt"); + unlink("logfile.txt"); + unlink("blob0_file.txt"); + unlink("blob1_file.txt"); + + int l; + + for(l = 0; l < COUNTER_RESOLUTION; l++) { + buckets[l] = 0; + } + + pthread_t * workers = malloc(sizeof(pthread_t) * thread_count); + + Tinit(); + int xid = Tbegin(); + hash = ThashCreate(xid, sizeof(int), sizeof(int)); + + Tcommit(xid); + + int k; + + /* threads have static thread sizes. Ughh. */ + pthread_attr_t attr; + pthread_attr_init(&attr); + + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&never, NULL); + + pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN); + pthread_attr_setschedpolicy(&attr, SCHED_FIFO); + pthread_mutex_lock(&mutex); + + + for(k = 0; k < thread_count; k++) { + int * k_copy = malloc(sizeof(int)); + *k_copy = k ; + pthread_create(&workers[k], &attr, go, k_copy); + + } + + pthread_mutex_unlock(&mutex); + + for(k = 0; k < thread_count; k++) { + pthread_join(workers[k],NULL); + } + + double log_multiplier = (COUNTER_RESOLUTION / log(MAX_SECONDS * 1000000000.0)); + + + + for(k = 0; k < COUNTER_RESOLUTION; k++) { + printf("%3.4f\t%d\n", exp(((double)k)/log_multiplier)/1000000000.0, buckets[k]); + } + + /* printf("mean: (max, avg) %f, %f\n", max_mean, avg_mean / (double)thread_count); + + printf("variance: (max, avg) %f, %f\n", max_var, avg_var / (double)thread_count); */ + + Tdeinit(); +} diff --git a/benchmarks/pageOrientedListNTA.c b/benchmarks/pageOrientedListNTA.c new file mode 100644 index 0000000..1675d43 --- /dev/null +++ b/benchmarks/pageOrientedListNTA.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include + +//#define CHECK_RESULTS 1 + +int main(int argc, char** argv) { + + assert(argc == 3); + + int xact_count = atoi(argv[1]); + int count = atoi(argv[2]); + int k; + + /* unlink("storefile.txt"); + unlink("logfile.txt"); + unlink("blob0_file.txt"); + unlink("blob1_file.txt"); */ + + Tinit(); + int xid = Tbegin(); + + recordid hash = TpagedListAlloc(xid); + + Tcommit(xid); + + int i = 0; + + for(k = 0; k < xact_count; k++) { + + xid = Tbegin(); + + for(;i < count *(k+1) ; i++) { + + TpagedListInsert(xid, hash, (byte*)&i, sizeof(int), (byte*)&i, sizeof(int)); + + } + + Tcommit(xid); + + } + +#ifdef CHECK_RESULTS + + printf("Checking results.\n"); + xid = Tbegin(); + lladd_pagedList_iterator * it = TpagedListIterator(xid, hash); + + assert(i == xact_count * count); + + int seen[count * xact_count]; + for(i = 0; i < xact_count * count; i++) { + seen[i] = 0; + } + i = 0; + int * key; + int * val; + int keySize; + int valSize; + while(TpagedListNext(xid, it, (byte**)&key, &keySize, (byte**)&val, &valSize)) { + assert(*key == *val); + assert(keySize == sizeof(int)); + assert(valSize == sizeof(int)); + assert(!seen[*key]); + seen[*key]++; + + free(key); + free(val); + + i++; + + } + assert(i == xact_count * count); + for(int i = 0; i < count * xact_count; i++) { + assert(seen[i]==1); + } + + Tcommit(xid); + +#endif + + + + Tdeinit(); + +} diff --git a/configure.in b/configure.in index b5218eb..db38a30 100644 --- a/configure.in +++ b/configure.in @@ -44,6 +44,7 @@ AM_CONDITIONAL(HAVE_CHECK, test x$have_check = xtrue) #AC_CHECK_LIB(efence,memalign) #fi + # Linux has a broken O_DIRECT flag, but we allow people to override it from # the command line. test_host_prw=yes @@ -93,6 +94,9 @@ AC_FUNC_REALLOC AC_FUNC_STAT AC_CHECK_FUNCS([bzero fdatasync getcwd gettimeofday inet_ntoa localtime_r memmove memset mkdir powl posix_memalign socket sqrt strchr strdup strerror strrchr strstr strtoul]) +#AC_CONFIG_LIBMYSQLD + + AC_CONFIG_FILES([Makefile benchmarks/Makefile benchmarks/berkeleyDB/Makefile diff --git a/lladd/constants.h b/lladd/constants.h index 6c09ea5..07f53c4 100644 --- a/lladd/constants.h +++ b/lladd/constants.h @@ -82,14 +82,14 @@ terms specified in this license. /* #define MAX_BUFFER_SIZE 100003 */ /*#define MAX_BUFFER_SIZE 20029 */ -/*#define MAX_BUFFER_SIZE 10007 */ +#define MAX_BUFFER_SIZE 10007 /*#define MAX_BUFFER_SIZE 5003*/ -#define MAX_BUFFER_SIZE 2003 +/*#define MAX_BUFFER_SIZE 2003 */ /* #define MAX_BUFFER_SIZE 71 */ /*#define MAX_BUFFER_SIZE 7 */ /*#define BUFFER_ASOOCIATIVE 2 */ -#define MAX_TRANSACTIONS 1000 +#define MAX_TRANSACTIONS 100000 /** Operation types */ diff --git a/m4/check.m4 b/m4/check.m4 index 97bfd9c..a2e0812 100644 --- a/m4/check.m4 +++ b/m4/check.m4 @@ -2,7 +2,7 @@ dnl AM_PATH_CHECK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) dnl Test for check, and define CHECK_CFLAGS and CHECK_LIBS dnl -AC_DEFUN(AM_PATH_CHECK, +AC_DEFUN([AM_PATH_CHECK], [ AC_ARG_WITH(check, [ --with-check=PATH prefix where check is installed [default=auto]]) diff --git a/m4/lladd.ac b/m4/lladd.ac index 0e33813..9f4ddc0 100644 --- a/m4/lladd.ac +++ b/m4/lladd.ac @@ -2,7 +2,7 @@ dnl dnl Autoconf support for finding LLADD dnl -AC_DEFUN(AC_LLADD_HELP, [ +AC_DEFUN([AC_LLADD_HELP], [ cat < + +int main(void) { + Tinit(); + Tdeinit(); + return compensation_error(); +} + diff --git a/utilities/truncate_log.c b/utilities/truncate_log.c new file mode 100644 index 0000000..247dd54 --- /dev/null +++ b/utilities/truncate_log.c @@ -0,0 +1,14 @@ +#include +#include "../src/lladd/logger/logWriter.h" +int main(void) { + Tinit(); + syncLog(); + lsn_t trunc_to = flushedLSN(); + Tdeinit(); + + openLogWriter(); + truncateLog(trunc_to); + + return compensation_error(); +} +