Preliminary benchmark program uploads for SEDA-style response time percentiles vs requests / second

Also added a few cute little utilities:
  - truncate_log
  - run_recovery

Upped max # of concurrent transactions.  (Current throughput during benchmarking remains ~flat up to 32,000
threads, but past max concurrent transactions was 1,000...)
This commit is contained in:
Sears Russell 2005-03-12 22:11:18 +00:00
parent 18c772234d
commit 1bfb634103
20 changed files with 1436 additions and 76 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -1,3 +1,3 @@
LDADD=-ldb -lpthread
bin_PROGRAMS=transapp bdbRaw bdbHash
bin_PROGRAMS=transapp bdbRaw bdbHash bdbHashThreaded
AM_CFLAGS=-g

View file

@ -0,0 +1,681 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <pthread.h>
// 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 <limits.h>
#endif
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <db.h>
#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);
}

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -0,0 +1,127 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <lladd/transactional.h>
#include <unistd.h>
#include <pthread.h>
// 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 <limits.h>
#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);
}

View file

@ -0,0 +1,159 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <lladd/transactional.h>
#include <unistd.h>
#include <pthread.h>
#include <math.h>
#include <sys/time.h>
#include <time.h>
// 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 <limits.h>
#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();
}

View file

@ -0,0 +1,233 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <lladd/transactional.h>
#include <unistd.h>
#include <pthread.h>
#include <math.h>
#include <sys/time.h>
#include <time.h>
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 <limits.h>
#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();
}

View file

@ -0,0 +1,88 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <lladd/transactional.h>
#include <unistd.h>
//#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();
}

View file

@ -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

View file

@ -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 */

View file

@ -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]])

View file

@ -2,7 +2,7 @@ dnl
dnl Autoconf support for finding LLADD
dnl
AC_DEFUN(AC_LLADD_HELP, [
AC_DEFUN([AC_LLADD_HELP], [
cat <<EOF
Configure error with LLADD...
@ -17,7 +17,7 @@ EOF
dnl
dnl Main macro for finding a usable LLADD installation
dnl
AC_DEFUN(AC_CONFIG_LLADD, [
AC_DEFUN([AC_CONFIG_LLADD], [
ac_lladddir='system'
AC_ARG_WITH(lladd,

View file

@ -29,6 +29,7 @@ compensated_function int TpagedListInsert(int xid, recordid list, const byte * k
Tread(xid, list, &header);
recordid headerRid = list;
pagedListHeader firstHeader = header;
/* byte * garbage;
ret = (TpagedListFind(xid, list, key, keySize, &garbage) != -1);
if(ret) {
@ -46,7 +47,7 @@ compensated_function int TpagedListInsert(int xid, recordid list, const byte * k
while(rid.size == -1) {
if(compensation_error()) { break; }
if(header.nextPage.size == -1) {
header.nextPage = Talloc(xid, sizeof(pagedListHeader));
/* header.nextPage = Talloc(xid, sizeof(pagedListHeader));
DEBUG("allocing on new page %d\n", header.nextPage.page);
Tset(xid, headerRid, &header);
pagedListHeader newHead;
@ -54,11 +55,25 @@ compensated_function int TpagedListInsert(int xid, recordid list, const byte * k
newHead.nextPage.page =0;
newHead.nextPage.slot =0;
newHead.nextPage.size =-1;
Tset(xid, header.nextPage, &newHead);
Tset(xid, header.nextPage, &newHead); */
// We're at the end of the list
recordid newHeadRid = Talloc(xid, sizeof(pagedListHeader));
pagedListHeader newHead;
newHead.thisPage = 0;
newHead.nextPage = firstHeader.nextPage;
firstHeader.nextPage = newHeadRid;
Tset(xid, newHeadRid, &newHead);
Tset(xid, list, &firstHeader);
header = newHead;
headerRid = newHeadRid;
} else {
headerRid = header.nextPage;
Tread(xid, header.nextPage, &header);
}
headerRid = header.nextPage;
Tread(xid, header.nextPage, &header);
rid = TallocFromPage(xid, headerRid.page, entrySize);
DEBUG("Alloced rid: {%d %d %d}", rid.page, rid.slot, rid.size);
}
@ -75,6 +90,7 @@ compensated_function int TpagedListInsert(int xid, recordid list, const byte * k
DEBUG("Header.thisPage = %d\n", rid.slot);
Tset(xid, headerRid, &header);
free(dat);
} end_ret(compensation_error());
return ret;
}

View file

@ -1,5 +1,5 @@
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=logfile_dump
bin_PROGRAMS=logfile_dump run_recovery truncate_log
AM_CFLAGS= -g -Wall -pedantic -std=gnu99

8
utilities/run_recovery.c Normal file
View file

@ -0,0 +1,8 @@
#include <lladd/transactional.h>
int main(void) {
Tinit();
Tdeinit();
return compensation_error();
}

14
utilities/truncate_log.c Normal file
View file

@ -0,0 +1,14 @@
#include <lladd/transactional.h>
#include "../src/lladd/logger/logWriter.h"
int main(void) {
Tinit();
syncLog();
lsn_t trunc_to = flushedLSN();
Tdeinit();
openLogWriter();
truncateLog(trunc_to);
return compensation_error();
}