#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int item_size = 1024;
int opt_threads = 1;
int opt_batchsize = 1;
+int opt_writes = (1 << 12);
+int opt_bdb_async = FALSE;
GAsyncQueue *queue;
int outstanding = 0;
GMutex *lock;
GCond *cond_empty, *cond_full;
+int64_t get_ns()
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ return ts.tv_sec * 1000000000LL + ts.tv_nsec;
+}
+
struct item *get_item()
{
return (struct item *)g_async_queue_pop(queue);
gpointer fslog_thread(gpointer d)
{
- g_print("Launching filesystem writer thread...\n");
-
while (TRUE) {
struct item *item = get_item();
/****************************** Single-File Log ******************************/
gpointer flatlog_thread(gpointer d)
{
- g_print("Launching flat log writer thread...\n");
-
int fd = open("logfile", O_CREAT|O_WRONLY|O_TRUNC, 0666);
g_assert(fd >= 0);
/************************* Transactional Berkeley DB *************************/
gpointer bdb_thread(gpointer d)
{
- g_print("Launching BDB log writer thread...\n");
-
int res;
DB_ENV *env;
DB *db;
| DB_INIT_MPOOL | DB_INIT_TXN | DB_THREAD, 0644);
g_assert(res == 0);
+ if (opt_bdb_async) {
+ res = env->set_flags(env, DB_TXN_WRITE_NOSYNC, 1);
+ g_assert(res == 0);
+ }
+
res = db_create(&db, env, 0);
g_assert(res == 0);
g_assert(res == 0);
while (TRUE) {
- if (txn == NULL) {
+ if (txn == NULL && !opt_bdb_async) {
res = env->txn_begin(env, NULL, &txn, 0);
g_assert(res == 0);
}
value.data = item->data;
value.size = item->len;
- res = db->put(db, NULL, &key, &value, 0);
+ res = db->put(db, opt_bdb_async ? NULL : txn, &key, &value, 0);
g_assert(res == 0);
count++;
if (count % opt_batchsize == 0) {
- txn->commit(txn, 0);
- txn = NULL;
+ if (opt_bdb_async) {
+ env->txn_checkpoint(env, 0, 0, 0);
+ } else {
+ txn->commit(txn, 0);
+ txn = NULL;
+ }
}
finish_item(item);
int main(int argc, char *argv[])
{
+ int64_t time_start, time_end;
+
g_thread_init(NULL);
queue = g_async_queue_new();
lock = g_mutex_new();
int opt;
int backend = 0;
- while ((opt = getopt(argc, argv, "t:s:b:BFD")) != -1) {
+ while ((opt = getopt(argc, argv, "at:s:b:n:BFD")) != -1) {
switch (opt) {
+ case 'a':
+ // Make BDB log writes more asynchronous
+ opt_bdb_async = TRUE;
case 't':
// Set number of log worker threads
opt_threads = atoi(optarg);
// Set batch size
opt_batchsize = atoi(optarg);
break;
+ case 'n':
+ // Set object count
+ opt_writes = atoi(optarg);
+ break;
case 'B':
// Select BDB backend
backend = 'b';
return EXIT_FAILURE;
}
- for (int i = 0; i < (1 << 12); i++) {
+ time_start = get_ns();
+ for (int i = 0; i < opt_writes; i++) {
struct item *item = g_new(struct item, 1);
item->key = g_strdup_printf("item-%06d", i);
item->data = g_malloc(item_size);
while (outstanding > 0)
g_cond_wait(cond_empty, lock);
g_mutex_unlock(lock);
+ time_end = get_ns();
+
+ double elapsed = (time_end - time_start) / 1e9;
+ printf("Elapsed: %f s\nThroughput: %f txn/s, %f MiB/s\n",
+ elapsed, opt_writes / elapsed,
+ opt_writes / elapsed * item_size / (1 << 20));
+
+ if (backend == 'b' && opt_bdb_async)
+ backend = 'B';
+
+ FILE *f = fopen("../logbench.data", "a");
+ g_assert(f != NULL);
+ fprintf(f, "%c\t%d\t%d\t%d\t%f\t%f\t%f\n",
+ backend, item_size, opt_writes, opt_batchsize,
+ elapsed, opt_writes / elapsed,
+ opt_writes / elapsed * item_size / (1 << 20));
+ fclose(f);
return 0;
}