Commit f82eddef authored by Rusty Russell's avatar Rusty Russell

tdb2: update tools/speed.c, tools/tdbtool.c and tools/tdbtorture.c to new API

parent c8c9a469
......@@ -103,6 +103,7 @@ int main(int argc, char *argv[])
struct tdb_context *tdb;
struct timeval start, stop;
union tdb_attribute seed, stats;
enum TDB_ERROR ecode;
/* Try to keep benchmarks even. */
seed.base.attr = TDB_ATTRIBUTE_SEED;
......@@ -151,19 +152,19 @@ int main(int argc, char *argv[])
argc--;
}
if (transaction && tdb_transaction_start(tdb))
errx(1, "starting transaction: %s", tdb_errorstr(tdb));
if (transaction && (ecode = tdb_transaction_start(tdb)))
errx(1, "starting transaction: %s", tdb_errorstr(ecode));
/* Add 1000 records. */
printf("Adding %u records: ", num); fflush(stdout);
gettimeofday(&start, NULL);
for (i = 0; i < num; i++)
if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
if ((ecode = tdb_store(tdb, key, data, TDB_INSERT)) != 0)
errx(1, "Inserting key %u in tdb: %s",
i, tdb_errorstr(tdb));
i, tdb_errorstr(ecode));
gettimeofday(&stop, NULL);
if (transaction && tdb_transaction_commit(tdb))
errx(1, "committing transaction: %s", tdb_errorstr(tdb));
if (transaction && (ecode = tdb_transaction_commit(tdb)))
errx(1, "committing transaction: %s", tdb_errorstr(ecode));
printf(" %zu ns (%zu bytes)\n",
normalize(&start, &stop, num), file_size());
......@@ -172,22 +173,23 @@ int main(int argc, char *argv[])
if (++stage == stopat)
exit(0);
if (transaction && tdb_transaction_start(tdb))
errx(1, "starting transaction: %s", tdb_errorstr(tdb));
if (transaction && (ecode = tdb_transaction_start(tdb)))
errx(1, "starting transaction: %s", tdb_errorstr(ecode));
/* Finding 1000 records. */
printf("Finding %u records: ", num); fflush(stdout);
gettimeofday(&start, NULL);
for (i = 0; i < num; i++) {
int *dptr;
dptr = (int *)tdb_fetch(tdb, key).dptr;
if (!dptr || *dptr != i)
struct tdb_data dbuf;
if ((ecode = tdb_fetch(tdb, key, &dbuf)) != TDB_SUCCESS
|| *(int *)dbuf.dptr != i) {
errx(1, "Fetching key %u in tdb gave %u",
i, dptr ? *dptr : -1);
i, ecode ? ecode : *(int *)dbuf.dptr);
}
}
gettimeofday(&stop, NULL);
if (transaction && tdb_transaction_commit(tdb))
errx(1, "committing transaction: %s", tdb_errorstr(tdb));
if (transaction && (ecode = tdb_transaction_commit(tdb)))
errx(1, "committing transaction: %s", tdb_errorstr(ecode));
printf(" %zu ns (%zu bytes)\n",
normalize(&start, &stop, num), file_size());
if (seed.base.next)
......@@ -195,21 +197,22 @@ int main(int argc, char *argv[])
if (++stage == stopat)
exit(0);
if (transaction && tdb_transaction_start(tdb))
errx(1, "starting transaction: %s", tdb_errorstr(tdb));
if (transaction && (ecode = tdb_transaction_start(tdb)))
errx(1, "starting transaction: %s", tdb_errorstr(ecode));
/* Missing 1000 records. */
printf("Missing %u records: ", num); fflush(stdout);
gettimeofday(&start, NULL);
for (i = num; i < num*2; i++) {
int *dptr;
dptr = (int *)tdb_fetch(tdb, key).dptr;
if (dptr)
errx(1, "Fetching key %u in tdb gave %u", i, *dptr);
struct tdb_data dbuf;
ecode = tdb_fetch(tdb, key, &dbuf);
if (ecode != TDB_ERR_NOEXIST)
errx(1, "Fetching key %u in tdb gave %s",
i, tdb_errorstr(ecode));
}
gettimeofday(&stop, NULL);
if (transaction && tdb_transaction_commit(tdb))
errx(1, "committing transaction: %s", tdb_errorstr(tdb));
if (transaction && (ecode = tdb_transaction_commit(tdb)))
errx(1, "committing transaction: %s", tdb_errorstr(ecode));
printf(" %zu ns (%zu bytes)\n",
normalize(&start, &stop, num), file_size());
if (seed.base.next)
......@@ -217,8 +220,8 @@ int main(int argc, char *argv[])
if (++stage == stopat)
exit(0);
if (transaction && tdb_transaction_start(tdb))
errx(1, "starting transaction: %s", tdb_errorstr(tdb));
if (transaction && (ecode = tdb_transaction_start(tdb)))
errx(1, "starting transaction: %s", tdb_errorstr(ecode));
/* Traverse 1000 records. */
printf("Traversing %u records: ", num); fflush(stdout);
......@@ -229,8 +232,8 @@ int main(int argc, char *argv[])
if (i != (num - 1) * (num / 2))
errx(1, "Traverse tallied to %u", i);
gettimeofday(&stop, NULL);
if (transaction && tdb_transaction_commit(tdb))
errx(1, "committing transaction: %s", tdb_errorstr(tdb));
if (transaction && (ecode = tdb_transaction_commit(tdb)))
errx(1, "committing transaction: %s", tdb_errorstr(ecode));
printf(" %zu ns (%zu bytes)\n",
normalize(&start, &stop, num), file_size());
if (seed.base.next)
......@@ -238,21 +241,21 @@ int main(int argc, char *argv[])
if (++stage == stopat)
exit(0);
if (transaction && tdb_transaction_start(tdb))
errx(1, "starting transaction: %s", tdb_errorstr(tdb));
if (transaction && (ecode = tdb_transaction_start(tdb)))
errx(1, "starting transaction: %s", tdb_errorstr(ecode));
/* Delete 1000 records (not in order). */
printf("Deleting %u records: ", num); fflush(stdout);
gettimeofday(&start, NULL);
for (j = 0; j < num; j++) {
i = (j + 100003) % num;
if (tdb_delete(tdb, key) != 0)
if ((ecode = tdb_delete(tdb, key)) != TDB_SUCCESS)
errx(1, "Deleting key %u in tdb: %s",
i, tdb_errorstr(tdb));
i, tdb_errorstr(ecode));
}
gettimeofday(&stop, NULL);
if (transaction && tdb_transaction_commit(tdb))
errx(1, "committing transaction: %s", tdb_errorstr(tdb));
if (transaction && (ecode = tdb_transaction_commit(tdb)))
errx(1, "committing transaction: %s", tdb_errorstr(ecode));
printf(" %zu ns (%zu bytes)\n",
normalize(&start, &stop, num), file_size());
if (seed.base.next)
......@@ -260,21 +263,21 @@ int main(int argc, char *argv[])
if (++stage == stopat)
exit(0);
if (transaction && tdb_transaction_start(tdb))
errx(1, "starting transaction: %s", tdb_errorstr(tdb));
if (transaction && (ecode = tdb_transaction_start(tdb)))
errx(1, "starting transaction: %s", tdb_errorstr(ecode));
/* Re-add 1000 records (not in order). */
printf("Re-adding %u records: ", num); fflush(stdout);
gettimeofday(&start, NULL);
for (j = 0; j < num; j++) {
i = (j + 100003) % num;
if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
if ((ecode = tdb_store(tdb, key, data, TDB_INSERT)) != 0)
errx(1, "Inserting key %u in tdb: %s",
i, tdb_errorstr(tdb));
i, tdb_errorstr(ecode));
}
gettimeofday(&stop, NULL);
if (transaction && tdb_transaction_commit(tdb))
errx(1, "committing transaction: %s", tdb_errorstr(tdb));
if (transaction && (ecode = tdb_transaction_commit(tdb)))
errx(1, "committing transaction: %s", tdb_errorstr(ecode));
printf(" %zu ns (%zu bytes)\n",
normalize(&start, &stop, num), file_size());
if (seed.base.next)
......@@ -282,43 +285,43 @@ int main(int argc, char *argv[])
if (++stage == stopat)
exit(0);
if (transaction && tdb_transaction_start(tdb))
errx(1, "starting transaction: %s", tdb_errorstr(tdb));
if (transaction && (ecode = tdb_transaction_start(tdb)))
errx(1, "starting transaction: %s", tdb_errorstr(ecode));
/* Append 1000 records. */
printf("Appending %u records: ", num); fflush(stdout);
gettimeofday(&start, NULL);
for (i = 0; i < num; i++)
if (tdb_append(tdb, key, data) != 0)
if ((ecode = tdb_append(tdb, key, data)) != TDB_SUCCESS)
errx(1, "Appending key %u in tdb: %s",
i, tdb_errorstr(tdb));
i, tdb_errorstr(ecode));
gettimeofday(&stop, NULL);
if (transaction && tdb_transaction_commit(tdb))
errx(1, "committing transaction: %s", tdb_errorstr(tdb));
if (transaction && (ecode = tdb_transaction_commit(tdb)))
errx(1, "committing transaction: %s", tdb_errorstr(ecode));
printf(" %zu ns (%zu bytes)\n",
normalize(&start, &stop, num), file_size());
if (++stage == stopat)
exit(0);
if (transaction && tdb_transaction_start(tdb))
errx(1, "starting transaction: %s", tdb_errorstr(tdb));
if (transaction && (ecode = tdb_transaction_start(tdb)))
errx(1, "starting transaction: %s", tdb_errorstr(ecode));
/* Churn 1000 records: not in order! */
printf("Churning %u records: ", num); fflush(stdout);
gettimeofday(&start, NULL);
for (j = 0; j < num; j++) {
i = (j + 1000019) % num;
if (tdb_delete(tdb, key) != 0)
if ((ecode = tdb_delete(tdb, key)) != TDB_SUCCESS)
errx(1, "Deleting key %u in tdb: %s",
i, tdb_errorstr(tdb));
i, tdb_errorstr(ecode));
i += num;
if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
if ((ecode = tdb_store(tdb, key, data, TDB_INSERT)) != 0)
errx(1, "Inserting key %u in tdb: %s",
i, tdb_errorstr(tdb));
i, tdb_errorstr(ecode));
}
gettimeofday(&stop, NULL);
if (transaction && tdb_transaction_commit(tdb))
errx(1, "committing transaction: %s", tdb_errorstr(tdb));
if (transaction && (ecode = tdb_transaction_commit(tdb)))
errx(1, "committing transaction: %s", tdb_errorstr(ecode));
printf(" %zu ns (%zu bytes)\n",
normalize(&start, &stop, num), file_size());
......
......@@ -46,12 +46,9 @@ static int disable_mmap;
enum commands {
CMD_CREATE_TDB,
CMD_OPEN_TDB,
CMD_OPENJH_TDB,
#if 0
CMD_TRANSACTION_START,
CMD_TRANSACTION_COMMIT,
CMD_TRANSACTION_CANCEL,
#endif
CMD_ERASE,
CMD_DUMP,
CMD_INSERT,
......@@ -84,7 +81,6 @@ typedef struct {
COMMAND_TABLE cmd_table[] = {
{"create", CMD_CREATE_TDB},
{"open", CMD_OPEN_TDB},
{"openjh", CMD_OPENJH_TDB},
#if 0
{"transaction_start", CMD_TRANSACTION_START},
{"transaction_commit", CMD_TRANSACTION_COMMIT},
......@@ -131,13 +127,10 @@ static double _end_timer(void)
(tp2.tv_usec - tp1.tv_usec)*1.0e-6);
}
static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, void *priv, const char *format, ...)
static void tdb_log(struct tdb_context *tdb, enum tdb_log_level level,
void *priv, const char *message)
{
va_list ap;
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
fputs(message, stderr);
}
/* a tdb tool for manipulating a tdb database */
......@@ -226,9 +219,12 @@ static void help(void)
"\n");
}
static void terror(const char *why)
static void terror(enum TDB_ERROR err, const char *why)
{
printf("%s\n", why);
if (err != TDB_SUCCESS)
printf("%s:%s\n", tdb_errorstr(err), why);
else
printf("%s\n", why);
}
static void create_tdb(const char *tdbname)
......@@ -252,20 +248,16 @@ static uint64_t jenkins_hash(const void *key, size_t len, uint64_t seed,
return hash_any(key, len, seed);
}
static void open_tdb(const char *tdbname, tdb_hashfn_t hashfn)
static void open_tdb(const char *tdbname)
{
union tdb_attribute log_attr, hash_attr;
union tdb_attribute log_attr;
log_attr.base.attr = TDB_ATTRIBUTE_LOG;
log_attr.base.next = NULL;
log_attr.log.log_fn = tdb_log;
hash_attr.base.attr = TDB_ATTRIBUTE_HASH;
hash_attr.base.next = &log_attr;
hash_attr.hash.hash_fn = hashfn;
if (tdb) tdb_close(tdb);
tdb = tdb_open(tdbname, disable_mmap?TDB_NOMMAP:0, O_RDWR, 0600,
hashfn ? &hash_attr : &log_attr);
&log_attr);
if (!tdb) {
printf("Could not open %s: %s\n", tdbname, strerror(errno));
}
......@@ -274,9 +266,10 @@ static void open_tdb(const char *tdbname, tdb_hashfn_t hashfn)
static void insert_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
{
TDB_DATA key, dbuf;
enum TDB_ERROR ecode;
if ((keyname == NULL) || (keylen == 0)) {
terror("need key");
terror(TDB_SUCCESS, "need key");
return;
}
......@@ -285,22 +278,24 @@ static void insert_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
dbuf.dptr = (unsigned char *)data;
dbuf.dsize = datalen;
if (tdb_store(tdb, key, dbuf, TDB_INSERT) == -1) {
terror("insert failed");
ecode = tdb_store(tdb, key, dbuf, TDB_INSERT);
if (ecode) {
terror(ecode, "insert failed");
}
}
static void store_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
{
TDB_DATA key, dbuf;
enum TDB_ERROR ecode;
if ((keyname == NULL) || (keylen == 0)) {
terror("need key");
terror(TDB_SUCCESS, "need key");
return;
}
if ((data == NULL) || (datalen == 0)) {
terror("need data");
terror(TDB_SUCCESS, "need data");
return;
}
......@@ -312,50 +307,52 @@ static void store_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
printf("Storing key:\n");
print_rec(tdb, key, dbuf, NULL);
if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) {
terror("store failed");
ecode = tdb_store(tdb, key, dbuf, TDB_REPLACE);
if (ecode) {
terror(ecode, "store failed");
}
}
static void show_tdb(char *keyname, size_t keylen)
{
TDB_DATA key, dbuf;
enum TDB_ERROR ecode;
if ((keyname == NULL) || (keylen == 0)) {
terror("need key");
terror(TDB_SUCCESS, "need key");
return;
}
key.dptr = (unsigned char *)keyname;
key.dsize = keylen;
dbuf = tdb_fetch(tdb, key);
if (!dbuf.dptr) {
terror("fetch failed");
return;
ecode = tdb_fetch(tdb, key, &dbuf);
if (ecode) {
terror(ecode, "fetch failed");
return;
}
print_rec(tdb, key, dbuf, NULL);
free( dbuf.dptr );
return;
}
static void delete_tdb(char *keyname, size_t keylen)
{
TDB_DATA key;
enum TDB_ERROR ecode;
if ((keyname == NULL) || (keylen == 0)) {
terror("need key");
terror(TDB_SUCCESS, "need key");
return;
}
key.dptr = (unsigned char *)keyname;
key.dsize = keylen;
if (tdb_delete(tdb, key) != 0) {
terror("delete failed");
ecode = tdb_delete(tdb, key);
if (ecode) {
terror(ecode, "delete failed");
}
}
......@@ -363,23 +360,24 @@ static void move_rec(char *keyname, size_t keylen, char* tdbname)
{
TDB_DATA key, dbuf;
struct tdb_context *dst_tdb;
enum TDB_ERROR ecode;
if ((keyname == NULL) || (keylen == 0)) {
terror("need key");
terror(TDB_SUCCESS, "need key");
return;
}
if ( !tdbname ) {
terror("need destination tdb name");
terror(TDB_SUCCESS, "need destination tdb name");
return;
}
key.dptr = (unsigned char *)keyname;
key.dsize = keylen;
dbuf = tdb_fetch(tdb, key);
if (!dbuf.dptr) {
terror("fetch failed");
ecode = tdb_fetch(tdb, key, &dbuf);
if (ecode) {
terror(ecode, "fetch failed");
return;
}
......@@ -387,19 +385,17 @@ static void move_rec(char *keyname, size_t keylen, char* tdbname)
dst_tdb = tdb_open(tdbname, 0, O_RDWR, 0600, NULL);
if ( !dst_tdb ) {
terror("unable to open destination tdb");
terror(TDB_SUCCESS, "unable to open destination tdb");
return;
}
if ( tdb_store( dst_tdb, key, dbuf, TDB_REPLACE ) == -1 ) {
terror("failed to move record");
}
ecode = tdb_store( dst_tdb, key, dbuf, TDB_REPLACE);
if (ecode)
terror(ecode, "failed to move record");
else
printf("record moved\n");
tdb_close( dst_tdb );
return;
}
static int print_rec(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
......@@ -437,10 +433,13 @@ static int traverse_fn(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf,
static void info_tdb(void)
{
char *summary = tdb_summary(tdb, TDB_SUMMARY_HISTOGRAMS);
enum TDB_ERROR ecode;
char *summary;
if (!summary) {
printf("Error = %s\n", tdb_errorstr(tdb));
ecode = tdb_summary(tdb, TDB_SUMMARY_HISTOGRAMS, &summary);
if (ecode) {
terror(ecode, "Getting summary");
} else {
printf("%s", summary);
free(summary);
......@@ -480,13 +479,12 @@ static void speed_tdb(const char *tlimit)
key.dsize = strlen((char *)key.dptr);
dbuf.dptr = (unsigned char *)&r;
dbuf.dsize = sizeof(r);
tdb_fetch(tdb, key);
tdb_fetch(tdb, key, &dbuf);
t = _end_timer();
ops++;
} while (t < timelimit);
printf("%10.3f ops/sec\n", ops/t);
#if 0 /* FIXME */
ops = 0;
printf("Testing transaction speed for %u seconds\n", timelimit);
_start_timer();
......@@ -504,7 +502,6 @@ static void speed_tdb(const char *tlimit)
ops++;
} while (t < timelimit);
printf("%10.3f ops/sec\n", ops/t);
#endif
ops = 0;
printf("Testing traverse speed for %u seconds\n", timelimit);
......@@ -548,10 +545,11 @@ static int do_delete_fn(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf
static void first_record(struct tdb_context *the_tdb, TDB_DATA *pkey)
{
TDB_DATA dbuf;
*pkey = tdb_firstkey(the_tdb);
dbuf = tdb_fetch(the_tdb, *pkey);
if (!dbuf.dptr) terror("fetch failed");
enum TDB_ERROR ecode;
ecode = tdb_firstkey(the_tdb, pkey);
if (!ecode)
ecode = tdb_fetch(the_tdb, *pkey, &dbuf);
if (ecode) terror(ecode, "fetch failed");
else {
print_rec(the_tdb, *pkey, dbuf, NULL);
}
......@@ -560,11 +558,13 @@ static void first_record(struct tdb_context *the_tdb, TDB_DATA *pkey)
static void next_record(struct tdb_context *the_tdb, TDB_DATA *pkey)
{
TDB_DATA dbuf;
*pkey = tdb_nextkey(the_tdb, *pkey);
dbuf = tdb_fetch(the_tdb, *pkey);
if (!dbuf.dptr)
terror("fetch failed");
enum TDB_ERROR ecode;
ecode = tdb_nextkey(the_tdb, pkey);
if (!ecode)
ecode = tdb_fetch(the_tdb, *pkey, &dbuf);
if (ecode)
terror(ecode, "fetch failed");
else
print_rec(the_tdb, *pkey, dbuf, NULL);
}
......@@ -574,7 +574,7 @@ static void check_db(struct tdb_context *the_tdb)
if (!the_tdb) {
printf("Error: No database opened!\n");
} else {
if (tdb_check(the_tdb, NULL, NULL) == -1)
if (tdb_check(the_tdb, NULL, NULL) != 0)
printf("Integrity check for the opened database failed.\n");
else
printf("Database integrity is OK.\n");
......@@ -607,16 +607,12 @@ static int do_command(void)
return 0;
case CMD_OPEN_TDB:
bIterate = 0;
open_tdb(arg1, NULL);
return 0;
case CMD_OPENJH_TDB:
bIterate = 0;
open_tdb(arg1, jenkins_hash);
open_tdb(arg1);
return 0;
case CMD_SYSTEM:
/* Shell command */
if (system(arg1) == -1) {
terror("system() call failed\n");
terror(TDB_SUCCESS, "system() call failed\n");
}
return 0;
case CMD_QUIT:
......@@ -625,12 +621,11 @@ static int do_command(void)
/* all the rest require a open database */
if (!tdb) {
bIterate = 0;
terror("database not open");
terror(TDB_SUCCESS, "database not open");
help();
return 0;
}
switch (mycmd) {
#if 0
case CMD_TRANSACTION_START:
bIterate = 0;
tdb_transaction_start(tdb);
......@@ -643,7 +638,6 @@ static int do_command(void)
bIterate = 0;
tdb_transaction_cancel(tdb);
return 0;
#endif
case CMD_ERASE:
bIterate = 0;
tdb_traverse(tdb, do_delete_fn, NULL);
......@@ -711,7 +705,6 @@ static int do_command(void)
return 0;
case CMD_CREATE_TDB:
case CMD_OPEN_TDB:
case CMD_OPENJH_TDB:
case CMD_SYSTEM:
case CMD_QUIT:
/*
......
......@@ -24,7 +24,6 @@
#define TRANSACTION_PREPARE_PROB 2
#define LOCKSTORE_PROB 5
#define TRAVERSE_PROB 20
#define TRAVERSE_READ_PROB 20
#define TRAVERSE_MOD_PROB 100
#define TRAVERSE_ABORT_PROB 500
#define CULL_PROB 100
......@@ -43,16 +42,10 @@ static int count_pipe;
static union tdb_attribute log_attr;
static union tdb_attribute seed_attr;
#ifdef PRINTF_FMT
static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, void *private, const char *format, ...) PRINTF_FMT(4,5);
#endif
static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, void *private, const char *format, ...)
static void tdb_log(struct tdb_context *tdb, enum tdb_log_level level,
void *private, const char *message)
{
va_list ap;
va_start(ap, format);
vfprintf(stdout, format, ap);
va_end(ap);
fputs(message, stdout);
fflush(stdout);
#if 0
{
......@@ -202,7 +195,7 @@ static void addrec_db(void)
#if LOCKSTORE_PROB
if (random() % LOCKSTORE_PROB == 0) {
tdb_chainlock(db, key);
data = tdb_fetch(db, key);
tdb_fetch(db, key, &data);
if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
fatal("tdb_store failed");
}
......@@ -222,17 +215,8 @@ static void addrec_db(void)
}
#endif
#if TRAVERSE_READ_PROB
if (in_traverse == 0 && random() % TRAVERSE_READ_PROB == 0) {
in_traverse++;
tdb_traverse_read(db, NULL, NULL);
in_traverse--;
goto next;
}
#endif
data = tdb_fetch(db, key);
if (data.dptr) free(data.dptr);
if (tdb_fetch(db, key, &data) == TDB_SUCCESS)
free(data.dptr);
next:
free(k);
......@@ -296,7 +280,7 @@ static int run_child(int i, int seed, unsigned num_loops, unsigned start)
}
if (error_count == 0) {
tdb_traverse_read(db, NULL, NULL);
tdb_traverse(db, NULL, NULL);
#if TRANSACTION_PROB
if (always_transaction) {
while (in_transaction) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment