summaryrefslogtreecommitdiff
path: root/test/c
diff options
context:
space:
mode:
Diffstat (limited to 'test/c')
-rw-r--r--test/c/README2
-rw-r--r--test/c/chk.ctests7
-rw-r--r--test/c/common/test_util.h2
-rw-r--r--test/c/cutest/CuTest.c2
-rw-r--r--test/c/cutest/CuTest.h2
-rw-r--r--test/c/cutest/CuTests.c155
-rw-r--r--test/c/cutest/Runner.c6
-rw-r--r--test/c/run_failchk.sh132
-rw-r--r--test/c/suites/TestCallbackSetterAndGetter.c688
-rw-r--r--test/c/suites/TestChannel.c57
-rw-r--r--test/c/suites/TestDbHotBackup.c989
-rw-r--r--test/c/suites/TestDbTuner.c6
-rw-r--r--test/c/suites/TestEncryption.c2
-rw-r--r--test/c/suites/TestEnvConfig.c90
-rw-r--r--test/c/suites/TestEnvMethod.c2
-rw-r--r--test/c/suites/TestKeyExistErrorReturn.c2
-rw-r--r--test/c/suites/TestMutexAlignment.c70
-rw-r--r--test/c/suites/TestPartial.c2
-rw-r--r--test/c/suites/TestPartition.c508
-rw-r--r--test/c/suites/TestPreOpenSetterAndGetter.c1178
-rw-r--r--test/c/suites/TestQueue.c9
-rw-r--r--test/c/test_api_methods.c2
-rw-r--r--test/c/test_db185.c2
-rw-r--r--test/c/test_failchk.c1078
-rw-r--r--test/c/test_log_verify.c2
25 files changed, 4527 insertions, 468 deletions
diff --git a/test/c/README b/test/c/README
index 9205cfa2..43f6c58c 100644
--- a/test/c/README
+++ b/test/c/README
@@ -1,5 +1,5 @@
-The C test cases are currently (loosly) based on the CuTest harness. Loosely
+The C test cases are currently (loosely) based on the CuTest harness. Loosely
because the harness has been heavily modified from the original version.
There are still a few old test cases in the source tree. Those will be
diff --git a/test/c/chk.ctests b/test/c/chk.ctests
index 1c76e495..3306f8aa 100644
--- a/test/c/chk.ctests
+++ b/test/c/chk.ctests
@@ -37,7 +37,12 @@ echo "Building DB library, this can take a while."
CINC="-I$b -I$s -I$s/dbinc"
[ `uname` = "Linux" ] && CINC="$CINC -pthread"
-for i in `ls test_*.c`; do
+C_TESTS="\
+test_api_methods.c
+test_db185.c
+test_log_verify.c"
+
+for i in $C_TESTS; do
echo "=== Running $i ===" | tee -a compile.out
if cc -g -Wall $CINC $i $b/libdb.a -o t >> compile.out 2>&1; then
diff --git a/test/c/common/test_util.h b/test/c/common/test_util.h
index 74be1bb8..db1e789d 100644
--- a/test/c/common/test_util.h
+++ b/test/c/common/test_util.h
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2012, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*/
diff --git a/test/c/cutest/CuTest.c b/test/c/cutest/CuTest.c
index d7da5b22..68e7b6ac 100644
--- a/test/c/cutest/CuTest.c
+++ b/test/c/cutest/CuTest.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2010, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*/
diff --git a/test/c/cutest/CuTest.h b/test/c/cutest/CuTest.h
index 76cbceb4..3163fde0 100644
--- a/test/c/cutest/CuTest.h
+++ b/test/c/cutest/CuTest.h
@@ -1,7 +1,7 @@
/*
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2012, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*/
diff --git a/test/c/cutest/CuTests.c b/test/c/cutest/CuTests.c
index 430aa7fa..0e73fb96 100644
--- a/test/c/cutest/CuTests.c
+++ b/test/c/cutest/CuTests.c
@@ -6,6 +6,12 @@
#include "CuTest.h"
+extern int TestCallbackSetterAndGetterSuiteSetup(CuSuite *suite);
+extern int TestCallbackSetterAndGetterSuiteTeardown(CuSuite *suite);
+extern int TestCallbackSetterAndGetterTestSetup(CuTest *ct);
+extern int TestCallbackSetterAndGetterTestTeardown(CuTest *ct);
+extern int TestEnvCallbacks(CuTest *ct);
+extern int TestDbCallbacks(CuTest *ct);
extern int TestChannelSuiteSetup(CuSuite *suite);
extern int TestChannelSuiteTeardown(CuSuite *suite);
extern int TestChannelTestSetup(CuTest *test);
@@ -15,11 +21,14 @@ extern int TestDbHotBackupSuiteSetup(CuSuite *suite);
extern int TestDbHotBackupSuiteTeardown(CuSuite *suite);
extern int TestDbHotBackupTestSetup(CuTest *ct);
extern int TestDbHotBackupTestTeardown(CuTest *ct);
-extern int TestDbHotBackupSimpleEnv(CuTest *ct);
-extern int TestDbHotBackupPartitionDB(CuTest *ct);
-extern int TestDbHotBackupMultiDataDir(CuTest *ct);
-extern int TestDbHotBackupSetLogDir(CuTest *ct);
-extern int TestDbHotBackupQueueDB(CuTest *ct);
+extern int TestBackupSimpleEnvNoCallback(CuTest *ct);
+extern int TestBackupSimpleEnvWithCallback(CuTest *ct);
+extern int TestBackupSimpleEnvWithConfig(CuTest *ct);
+extern int TestBackupPartitionDB(CuTest *ct);
+extern int TestBackupMultiDataDir(CuTest *ct);
+extern int TestBackupSetLogDir(CuTest *ct);
+extern int TestBackupQueueDB(CuTest *ct);
+extern int TestBackupHeapDB(CuTest *ct);
extern int TestDbTuner(CuTest *ct);
extern int TestNoEncryptedDb(CuTest *ct);
extern int TestEncryptedDbFlag(CuTest *ct);
@@ -51,6 +60,7 @@ extern int TestSetTransactionTimeout(CuTest *ct);
extern int TestSetCachesize(CuTest *ct);
extern int TestSetThreadCount(CuTest *ct); /* SKIP */
extern int TestKeyExistErrorReturn(CuTest *ct);
+extern int TestMutexAlignment(CuTest *ct);
extern int TestPartialSuiteSetup(CuSuite *ct);
extern int TestPartialSuiteTeardown(CuSuite *ct);
extern int TestPartialTestSetup(CuTest *ct);
@@ -59,8 +69,49 @@ extern int TestDbPartialGet(CuTest *ct);
extern int TestDbPartialPGet(CuTest *ct);
extern int TestCursorPartialGet(CuTest *ct);
extern int TestCursorPartialPGet(CuTest *ct);
+extern int TestPartitionSuiteSetup(CuSuite *suite);
+extern int TestPartitionSuiteTeardown(CuSuite *suite);
+extern int TestPartitionTestSetup(CuTest *ct);
+extern int TestPartitionTestTeardown(CuTest *ct);
+extern int TestPartOneKeyNoData(CuTest *ct);
+extern int TestPartTwoKeyNoData(CuTest *ct);
+extern int TestPartDuplicatedKey(CuTest *ct);
+extern int TestPartUnsortedKey(CuTest *ct);
+extern int TestPartNumber(CuTest *ct);
+extern int TestPartKeyCallBothSet(CuTest *ct);
+extern int TestPartKeyCallNeitherSet(CuTest *ct);
+extern int TestPreOpenSetterAndGetterSuiteSetup(CuSuite *suite);
+extern int TestPreOpenSetterAndGetterSuiteTeardown(CuSuite *suite);
+extern int TestPreOpenSetterAndGetterTestSetup(CuTest *ct);
+extern int TestPreOpenSetterAndGetterTestTeardown(CuTest *ct);
+extern int TestEnvPreOpenSetterAndGetter(CuTest *ct);
+extern int TestDbPreOpenSetterAndGetter(CuTest *ct);
+extern int TestMpoolFilePreOpenSetterAndGetter(CuTest *ct);
+extern int TestSequencePreOpenSetterAndGetter(CuTest *ct);
extern int TestQueue(CuTest *ct);
+int RunCallbackSetterAndGetterTests(CuString *output)
+{
+ CuSuite *suite = CuSuiteNew("TestCallbackSetterAndGetter",
+ TestCallbackSetterAndGetterSuiteSetup,
+ TestCallbackSetterAndGetterSuiteTeardown);
+ int count;
+
+ SUITE_ADD_TEST(suite, TestEnvCallbacks,
+ TestCallbackSetterAndGetterTestSetup,
+ TestCallbackSetterAndGetterTestTeardown);
+ SUITE_ADD_TEST(suite, TestDbCallbacks,
+ TestCallbackSetterAndGetterTestSetup,
+ TestCallbackSetterAndGetterTestTeardown);
+
+ CuSuiteRun(suite);
+ CuSuiteSummary(suite, output);
+ CuSuiteDetails(suite, output);
+ count = suite->failCount;
+ CuSuiteDelete(suite);
+ return (count);
+}
+
int RunChannelTests(CuString *output)
{
CuSuite *suite = CuSuiteNew("TestChannel",
@@ -84,15 +135,21 @@ int RunDbHotBackupTests(CuString *output)
TestDbHotBackupSuiteSetup, TestDbHotBackupSuiteTeardown);
int count;
- SUITE_ADD_TEST(suite, TestDbHotBackupSimpleEnv,
+ SUITE_ADD_TEST(suite, TestBackupSimpleEnvNoCallback,
+ TestDbHotBackupTestSetup, TestDbHotBackupTestTeardown);
+ SUITE_ADD_TEST(suite, TestBackupSimpleEnvWithCallback,
+ TestDbHotBackupTestSetup, TestDbHotBackupTestTeardown);
+ SUITE_ADD_TEST(suite, TestBackupSimpleEnvWithConfig,
TestDbHotBackupTestSetup, TestDbHotBackupTestTeardown);
- SUITE_ADD_TEST(suite, TestDbHotBackupPartitionDB,
+ SUITE_ADD_TEST(suite, TestBackupPartitionDB,
TestDbHotBackupTestSetup, TestDbHotBackupTestTeardown);
- SUITE_ADD_TEST(suite, TestDbHotBackupMultiDataDir,
+ SUITE_ADD_TEST(suite, TestBackupMultiDataDir,
TestDbHotBackupTestSetup, TestDbHotBackupTestTeardown);
- SUITE_ADD_TEST(suite, TestDbHotBackupSetLogDir,
+ SUITE_ADD_TEST(suite, TestBackupSetLogDir,
TestDbHotBackupTestSetup, TestDbHotBackupTestTeardown);
- SUITE_ADD_TEST(suite, TestDbHotBackupQueueDB,
+ SUITE_ADD_TEST(suite, TestBackupQueueDB,
+ TestDbHotBackupTestSetup, TestDbHotBackupTestTeardown);
+ SUITE_ADD_TEST(suite, TestBackupHeapDB,
TestDbHotBackupTestSetup, TestDbHotBackupTestTeardown);
CuSuiteRun(suite);
@@ -232,6 +289,23 @@ int RunKeyExistErrorReturnTests(CuString *output)
return (count);
}
+int RunMutexAlignmentTests(CuString *output)
+{
+ CuSuite *suite = CuSuiteNew("TestMutexAlignment",
+ NULL, NULL);
+ int count;
+
+ SUITE_ADD_TEST(suite, TestMutexAlignment,
+ NULL, NULL);
+
+ CuSuiteRun(suite);
+ CuSuiteSummary(suite, output);
+ CuSuiteDetails(suite, output);
+ count = suite->failCount;
+ CuSuiteDelete(suite);
+ return (count);
+}
+
int RunPartialTests(CuString *output)
{
CuSuite *suite = CuSuiteNew("TestPartial",
@@ -255,6 +329,63 @@ int RunPartialTests(CuString *output)
return (count);
}
+int RunPartitionTests(CuString *output)
+{
+ CuSuite *suite = CuSuiteNew("TestPartition",
+ TestPartitionSuiteSetup, TestPartitionSuiteTeardown);
+ int count;
+
+ SUITE_ADD_TEST(suite, TestPartOneKeyNoData,
+ TestPartitionTestSetup, TestPartitionTestTeardown);
+ SUITE_ADD_TEST(suite, TestPartTwoKeyNoData,
+ TestPartitionTestSetup, TestPartitionTestTeardown);
+ SUITE_ADD_TEST(suite, TestPartDuplicatedKey,
+ TestPartitionTestSetup, TestPartitionTestTeardown);
+ SUITE_ADD_TEST(suite, TestPartUnsortedKey,
+ TestPartitionTestSetup, TestPartitionTestTeardown);
+ SUITE_ADD_TEST(suite, TestPartNumber,
+ TestPartitionTestSetup, TestPartitionTestTeardown);
+ SUITE_ADD_TEST(suite, TestPartKeyCallBothSet,
+ TestPartitionTestSetup, TestPartitionTestTeardown);
+ SUITE_ADD_TEST(suite, TestPartKeyCallNeitherSet,
+ TestPartitionTestSetup, TestPartitionTestTeardown);
+
+ CuSuiteRun(suite);
+ CuSuiteSummary(suite, output);
+ CuSuiteDetails(suite, output);
+ count = suite->failCount;
+ CuSuiteDelete(suite);
+ return (count);
+}
+
+int RunPreOpenSetterAndGetterTests(CuString *output)
+{
+ CuSuite *suite = CuSuiteNew("TestPreOpenSetterAndGetter",
+ TestPreOpenSetterAndGetterSuiteSetup,
+ TestPreOpenSetterAndGetterSuiteTeardown);
+ int count;
+
+ SUITE_ADD_TEST(suite, TestEnvPreOpenSetterAndGetter,
+ TestPreOpenSetterAndGetterTestSetup,
+ TestPreOpenSetterAndGetterTestTeardown);
+ SUITE_ADD_TEST(suite, TestDbPreOpenSetterAndGetter,
+ TestPreOpenSetterAndGetterTestSetup,
+ TestPreOpenSetterAndGetterTestTeardown);
+ SUITE_ADD_TEST(suite, TestMpoolFilePreOpenSetterAndGetter,
+ TestPreOpenSetterAndGetterTestSetup,
+ TestPreOpenSetterAndGetterTestTeardown);
+ SUITE_ADD_TEST(suite, TestSequencePreOpenSetterAndGetter,
+ TestPreOpenSetterAndGetterTestSetup,
+ TestPreOpenSetterAndGetterTestTeardown);
+
+ CuSuiteRun(suite);
+ CuSuiteSummary(suite, output);
+ CuSuiteDetails(suite, output);
+ count = suite->failCount;
+ CuSuiteDelete(suite);
+ return (count);
+}
+
int RunQueueTests(CuString *output)
{
CuSuite *suite = CuSuiteNew("TestQueue",
@@ -273,6 +404,7 @@ int RunQueueTests(CuString *output)
}
TestSuite g_suites[] = {
+ { "TestCallbackSetterAndGetter", RunCallbackSetterAndGetterTests },
{ "TestChannel", RunChannelTests },
{ "TestDbHotBackup", RunDbHotBackupTests },
{ "TestDbTuner", RunDbTunerTests },
@@ -280,7 +412,10 @@ TestSuite g_suites[] = {
{ "TestEnvConfig", RunEnvConfigTests },
{ "TestEnvMethod", RunEnvMethodTests },
{ "TestKeyExistErrorReturn", RunKeyExistErrorReturnTests },
+ { "TestMutexAlignment", RunMutexAlignmentTests },
{ "TestPartial", RunPartialTests },
+ { "TestPartition", RunPartitionTests },
+ { "TestPreOpenSetterAndGetter", RunPreOpenSetterAndGetterTests },
{ "TestQueue", RunQueueTests },
{ "", NULL },
};
diff --git a/test/c/cutest/Runner.c b/test/c/cutest/Runner.c
index c8812afe..4de4521f 100644
--- a/test/c/cutest/Runner.c
+++ b/test/c/cutest/Runner.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2010, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*/
@@ -85,9 +85,9 @@ int main(int argc, char **argv)
}
}
while(num_suites != 0)
- free(suites[num_suites--]);
+ free(suites[--num_suites]);
while(num_tests != 0)
- free(tests[num_tests--]);
+ free(tests[--num_tests]);
if (failed > 0)
return (1);
else
diff --git a/test/c/run_failchk.sh b/test/c/run_failchk.sh
new file mode 100644
index 00000000..1ab8c261
--- /dev/null
+++ b/test/c/run_failchk.sh
@@ -0,0 +1,132 @@
+#!/bin/bash
+
+#
+# test_failchk --
+# Test failchk in a simple threaded application of some numbers of readers
+# and writers competing to read and update a set of words.
+# A typical test scenario runs this programs several times concurrently,
+# with different options:
+# first with the -I option to clear out any home directory
+# one or more instances with -f to activate the failchk thread
+# one or more instance with neither -I nor -f, as minimally
+# involved workers.
+#
+# If no arguments are given, it selects a default mix of processes:
+# run_failchk.sh 100 2 '-r1 -w2' -w2
+#
+# This does 100 iterations of this failchk group of applications:
+# 2 copies of test_failchk with 1 reader and 2 writer threads
+# a solo test_failchk the default # of readers (4) and 2 writers
+# a copy of the last test_failchk adding a failchk thread
+# wait a few seconds
+# randomly kill one of the non-failchk process
+#
+# This shell script initializes the env with the default number of readers and
+# writers, then starts one "worker" process with each listed argument. The last
+# worker started also uses -f, to ensure that at least one process will be
+# running failchk. It is okay for -f to also be passed to one or more of the
+# other processes. One of the processes is selected at random to be killed.
+
+if test $# -eq 0 ; then
+ set -- 100 2 '-r1 -w2' -w2
+ echo Running $0 $@
+fi
+repeat=$1
+dup_procs=$2
+shift; shift
+nprocs=0
+victim=-1
+
+function timestamp {
+perl \
+ -e 'use strict;' \
+ -e 'use Time::HiRes qw(time);' \
+ -e 'use POSIX qw(strftime);' \
+ -e 'local $| = 1; # Line buffering on' \
+ -e 'while (<>) {' \
+ -e ' # HiRes time is a float, often down to nanoseconds.' \
+ -e ' my $t = time;' \
+ -e ' # Display the time of day, appending microseconds.' \
+ -e ' my $date = (strftime "%H:%M:%S", localtime $t ) .' \
+ -e ' sprintf ".%06d", ($t-int($t))*1000000;' \
+ -e ' printf("%s: %s", $date, $_);' \
+ -e '}'
+}
+
+function dofork {
+ # Keep a slight bit of history -- just the previous iteration
+ test -f $home/FAILCHK.$nprocs && \
+ mv -f $home/FAILCHK.$nprocs $home/FAILCHK.prev.$nprocs
+ test_failchk $* $arg > $home/FAILCHK.$nprocs 2>&1 &
+ pids[$nprocs]=$!
+ printf "Process %d(%s): test_failchk %s\n" $nprocs ${pids[$nprocs]} "$*"
+ nprocs=$((++nprocs))
+}
+
+make test_failchk
+
+home=TESTDIR
+rm $home/*
+test -d $home || mkdir $home
+
+initargs=$1
+shift
+
+function main {
+ for (( i = 0; $i < $repeat; i=$((++i)) )) ; do
+ test -f stat && mv stat stat.prev
+ test -d $home && cp -pr $home $home.prev
+ nprocs=0
+ dofork $initargs
+ sleep 2
+ for arg in "$@" ; do
+ dofork $arg
+ done
+
+ # Duplicate the last configuration, then add a for-sure failchk'er.
+ for (( j = 0; $j < $dup_procs; j=$((++j)) )) ; do
+ dofork $arg
+ done
+ # If the failchk process does real work, it could also trip over.
+ dofork -f $arg -w1 -r0
+
+ # $RANDOM is not very random in the lowest bits, div by 23 to scatter a little.
+ victim=$((($RANDOM / 23) % ($nprocs - 1)))
+ delay=$((($RANDOM / 37) % 15 + 4))
+ echo "$0 #$i: Processes: ${pids[@]}; delaying $delay seconds before killing #$victim"
+ sleep $delay
+ echo "$0 #$i: Killing ${pids[$victim]}"
+ # Stop if a process has exited prematurely
+ kill -9 ${pids[$victim]} || exit 100
+
+ for (( j = 0; $j < $nprocs; j=$((++j)) )) ; do
+ wait ${pids[$j]}
+ stat=$?
+ echo "Waited for process #$j ${pids[$j]} returned $stat"
+ # SIGTERM exits with 2, SIGKILL 137; anything else is bad.
+ if test $stat -gt 2 -a $stat -ne 137; then
+ signal=`expr $stat - 128`
+ test $signal -lt 0 && signal=0
+ printf \
+ "Unexpected failure for process %d: status %d signal %d\n" \
+ ${pids[$j]} $stat $signal
+ exit $stat
+ fi
+
+ done
+ echo ""
+ sleep 2
+ # Saving stats would be nice here; but db_stat can trip over a bad lock
+ # db_stat -NEh $home > stat || exit 50
+
+ # If a system might possibly be running multiple instances of this
+ # script then the follow lines needs to stay a comment. However,
+ # when running by itself you can notified of non-killed processes
+ # by enabling the pgrep.
+ # pgrep test_failchk && echo "PROCESSES REMAIN ACTIVE?!" && exit 101
+
+ done
+ echo $i iterations done
+}
+
+main $* 2>&1 | timestamp
diff --git a/test/c/suites/TestCallbackSetterAndGetter.c b/test/c/suites/TestCallbackSetterAndGetter.c
new file mode 100644
index 00000000..924ab955
--- /dev/null
+++ b/test/c/suites/TestCallbackSetterAndGetter.c
@@ -0,0 +1,688 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2012, 2015 Oracle and/or its affiliates. All rights reserved.
+ *
+ * $Id$
+ */
+
+/*
+ * Test setting and getting callbacks on the DB_ENV or DB handle. [#21553]
+ *
+ * It tests the callback setters/getters. These setters/getters are
+ * divided into the following two sets:
+ * a. The callback setters and getters on DB_ENV handle.
+ * b. The callback setters and getters on DB handle.
+ * The general flow for each callback setting/getting test is:
+ * 1. Create the handle.
+ * 2. Set the callback on the handle.
+ * 3. Get the callback and verify it.
+ * 4. Issue the open call on the handle.
+ * 5. Get the callback again and verify it.
+ * 6. Close the handle.
+ * The callbacks we provide do not guarantee to work, but they guarantee
+ * the handle can issue a call to open successfully.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db.h"
+#include "CuTest.h"
+#include "test_util.h"
+
+/*
+ * The callbacks for DB_ENV handle.
+ * Some of the callbacks are shared by DB handle as well, and there will be
+ * comments for them. The order follows:
+ * https://sleepycat.oracle.com/support.web/doc_builds/newdocs.db/api_reference/C/env.html
+ * so that checking code is easier.
+ */
+/* For DB_ENV->get_alloc & DB->get_alloc */
+typedef void *(*app_malloc_fcn)(size_t);
+typedef void *(*app_realloc_fcn)(void *, size_t);
+typedef void (*app_free_fcn)(void *);
+/* For DB_ENV->get_app_dispatch */
+typedef int (*tx_recover_fcn)(DB_ENV *dbenv, DBT *log_rec,
+ DB_LSN *lsn, db_recops op);
+/* For DB_ENV->get_backup_callbacks */
+typedef int (*open_func)(DB_ENV *, const char *dbname,
+ const char *target, void **handle);
+typedef int (*write_func)(DB_ENV *, u_int32_t offset_gbytes,
+ u_int32_t offset_bytes, u_int32_t size, u_int8_t *buf, void *handle);
+typedef int (*close_func)(DB_ENV *, const char *dbname, void *handle);
+/* For DB_ENV->get_errcall & DB->get_errcall */
+typedef void (*db_errcall_fcn)(const DB_ENV *dbenv,
+ const char *errpfx, const char *msg);
+/* For DB_ENV->get_feedback */
+typedef void (*dbenv_feedback_fcn)(DB_ENV *dbenv, int opcode, int percent);
+/* For DB_ENV->get_isalive */
+typedef int (*is_alive_fcn)(DB_ENV *dbenv, pid_t pid,
+ db_threadid_t tid, u_int32_t flags);
+/* For DB_ENV->get_msgcall & DB->get_msgcall */
+typedef void (*db_msgcall_fcn)(const DB_ENV *dbenv, const char *msg);
+/* For DB_ENV->get_thread_id_fn */
+typedef void (*thread_id_fcn)(DB_ENV *dbenv, pid_t *pid, db_threadid_t *tid);
+/* For DB_ENV->get_thread_id_string_fn */
+typedef char *(*thread_id_string_fcn)(DB_ENV *dbenv, pid_t pid,
+ db_threadid_t tid, char *buf);
+
+/*
+ * The callbacks for DB handle.
+ * If the DB handle shares a callback with DB_ENV handle, it will not be
+ * listed here, since it has been listed above. The order follows:
+ * https://sleepycat.oracle.com/support.web/doc_builds/newdocs.db/api_reference/C/db.html
+ * so that checking code is easier.
+ */
+/* For DB->get_dup_compare */
+typedef int (*dup_compare_fcn)(DB *db,
+ const DBT *dbt1, const DBT *dbt2, size_t *locp);
+/* For DB->get_feedback */
+typedef void (*db_feedback_fcn)(DB *dbp, int opcode, int percent);
+/* For DB->get_partition_callback */
+typedef u_int32_t (*db_partition_fcn) (DB *db, DBT *key);
+/* For DB->get_append_recno */
+typedef int (*db_append_recno_fcn)(DB *dbp, DBT *data, db_recno_t recno);
+/* For DB->get_bt_compare */
+typedef int (*bt_compare_fcn)(DB *db,
+ const DBT *dbt1, const DBT *dbt2, size_t *locp);
+/* For DB->get_bt_compress */
+typedef int (*bt_compress_fcn)(DB *db, const DBT *prevKey,
+ const DBT *prevData, const DBT *key, const DBT *data, DBT *dest);
+typedef int (*bt_decompress_fcn)(DB *db, const DBT *prevKey,
+ const DBT *prevData, DBT *compressed, DBT *destKey, DBT *destData);
+/* For DB->get_bt_prefix */
+typedef size_t (*bt_prefix_fcn)(DB *, const DBT *dbt1, const DBT *dbt2);
+/* For DB->get_h_compare */
+typedef int (*h_compare_fcn)(DB *db,
+ const DBT *dbt1, const DBT *dbt2, size_t *locp);
+/* For DB->get_h_hash */
+typedef u_int32_t (*h_hash_fcn)(DB *dbp, const void *bytes, u_int32_t length);
+
+/*
+ * The order for declarations follows above, so that checking code is easier.
+ * Their definitions follow the same order, testing order follows it as well.
+ */
+static void *t_malloc(size_t sz);
+static void *t_realloc(void *addr, size_t sz);
+static void t_free(void *addr);
+static int t_app_dispatch(DB_ENV *dbenv,
+ DBT *log_rec, DB_LSN *lsn, db_recops op);
+static int t_open_func(DB_ENV *, const char *dbname,
+ const char *target, void **handle);
+static int t_write_func(DB_ENV *, u_int32_t offset_gbytes,
+ u_int32_t offset_bytes, u_int32_t size, u_int8_t *buf, void *handle);
+static int t_close_func(DB_ENV *, const char *dbname, void *handle);
+static void t_errcall(const DB_ENV *dbenv,
+ const char *errpfx, const char *msg);
+static void t_dbenv_callback(DB_ENV *dbenv, int opcode, int percent);
+static int t_is_alive(DB_ENV *dbenv,
+ pid_t pid, db_threadid_t tid, u_int32_t flags);
+static void t_msgcall(const DB_ENV *dbenv, const char *msg);
+static void t_thread_id(DB_ENV *dbenv, pid_t *pid, db_threadid_t *tid);
+static char *t_thread_id_string(DB_ENV *dbenv,
+ pid_t pid, db_threadid_t tid, char *buf);
+static int t_dup_compare(DB *db, const DBT *dbt1, const DBT *dbt2, size_t *locp);
+static void t_db_feedback(DB *dbp, int opcode, int percent);
+static u_int32_t t_db_partition(DB *db, DBT *key);
+static int t_append_recno(DB *dbp, DBT *data, db_recno_t recno);
+static int t_bt_compare(DB *db, const DBT *dbt1, const DBT *dbt2, size_t *locp) ;
+static int t_compress(DB *db, const DBT *prevKey, const DBT *prevData,
+ const DBT *key, const DBT *data, DBT *dest);
+static int t_decompress(DB *db, const DBT *prevKey,const DBT *prevData,
+ DBT *compressed, DBT *destKey, DBT *destData);
+static size_t t_bt_prefix(DB *db, const DBT *dbt1, const DBT *dbt2);
+static int t_h_compare(DB *db, const DBT *dbt1, const DBT *dbt2, size_t *locp);
+static u_int32_t t_h_hash(DB *dbp, const void *bytes, u_int32_t length);
+
+/*
+ * Common head routine for functions setting one callback.
+ */
+#define TEST_FUNCTION_1ARG_HEAD(type) \
+ type func_rt = NULL
+
+/*
+ * Common pre-open routine for functions setting one callback.
+ * We get the callback after setting, and check the callback.
+ */
+#define TEST_FUNCTION_1ARG_PREOPEN(handle, setter, getter, func) \
+ CuAssert(ct, #handle"->"#setter, \
+ handle->setter(handle, func) == 0); \
+ CuAssert(ct, "preopen: "#handle"->"#getter, \
+ handle->getter(handle, &func_rt) == 0); \
+ CuAssert(ct, "preopen: check "#func, func == func_rt)
+
+/*
+ * Common post-open routine for functions setting one callback.
+ * After object(DB_ENV/DB) open, we check if we still can get the callback
+ * and check the callback. Also, we close the handle.
+ */
+#define TEST_FUNCTION_1ARG_POSTOPEN(handle, getter, func) \
+ CuAssert(ct, "postopen: "#handle"->"#getter, \
+ handle->getter(handle, &func_rt) == 0); \
+ CuAssert(ct, "postopen: check "#func, func == func_rt); \
+ info.handle = NULL; \
+ CuAssert(ct, #handle"->close", handle->close(handle, 0) == 0)
+
+/*
+ * Like TEST_FUNCTION_1ARG_PREOPEN, but both setter and getter have no return.
+ */
+#define TEST_FUNCTION_1ARG_PREOPEN_VOID(handle, setter, getter, func) \
+ handle->setter(handle, func); \
+ handle->getter(handle, &func_rt); \
+ CuAssert(ct, "preopen: check "#func, func == func_rt)
+
+/*
+ * Like TEST_FUNCTION_1ARG_POSTOPEN, but both setter and getter have no return.
+ */
+#define TEST_FUNCTION_1ARG_POSTOPEN_VOID(handle, getter, func) \
+ handle->getter(handle, &func_rt); \
+ CuAssert(ct, "postopen: check "#func, func == func_rt); \
+ info.handle = NULL; \
+ CuAssert(ct, #handle"->close", handle->close(handle, 0) == 0)
+
+/*
+ * Common head routine for functions setting two callbacks.
+ */
+#define TEST_FUNCTION_2ARG_HEAD(type1, type2) \
+ type1 func_rt1 = NULL; \
+ type2 func_rt2 = NULL
+
+/*
+ * Common pre-open routine for functions setting two callbacks.
+ * We get the callbacks after setting, and check the callbacks.
+ */
+#define TEST_FUNCTION_2ARG_PREOPEN(handle, setter, getter, func1, func2)\
+ CuAssert(ct, #handle"->"#setter, \
+ handle->setter(handle, func1, func2) == 0); \
+ CuAssert(ct, "preopen: "#handle"->"#getter, \
+ handle->getter(handle, &func_rt1, &func_rt2) == 0); \
+ CuAssert(ct, "preopen: check "#func1, func1 == func_rt1); \
+ CuAssert(ct, "preopen: check "#func2, func2 == func_rt2)
+
+/*
+ * Common post-open routine for functions setting two callbacks.
+ * After object(DB_ENV/DB) open, we check if we still can get the callbacks
+ * and check the callbacks. Also, we close the handle.
+ */
+#define TEST_FUNCTION_2ARG_POSTOPEN(handle, getter, func1, func2) \
+ CuAssert(ct, "postopen: "#handle"->"#getter, \
+ handle->getter(handle, &func_rt1, &func_rt2) == 0); \
+ CuAssert(ct, "postopen: check "#func1, func1 == func_rt1); \
+ CuAssert(ct, "postopen: check "#func2, func2 == func_rt2); \
+ info.handle = NULL; \
+ CuAssert(ct, #handle"->close", handle->close(handle, 0) == 0)
+
+/*
+ * Common head routine for functions setting three callbacks.
+ */
+#define TEST_FUNCTION_3ARG_HEAD(type1, type2, type3) \
+ type1 func_rt1 = NULL; \
+ type2 func_rt2 = NULL; \
+ type3 func_rt3 = NULL
+
+/*
+ * Common pre-open routine for functions setting three callback.
+ * We get the callbacks after setting, and check the callbacks.
+ */
+#define TEST_FUNCTION_3ARG_PREOPEN(handle, setter, getter, func1, func2,\
+ func3) \
+ CuAssert(ct, #handle"->"#setter, \
+ handle->setter(handle, func1, func2, func3) == 0); \
+ CuAssert(ct, "preopen: "#handle"->"#getter, handle->getter( \
+ handle, &func_rt1, &func_rt2, &func_rt3) == 0); \
+ CuAssert(ct, "preopen: check "#func1, func1 == func_rt1); \
+ CuAssert(ct, "preopen: check "#func2, func2 == func_rt2); \
+ CuAssert(ct, "preopen: check "#func3, func3 == func_rt3)
+
+/*
+ * Common post-open routine for functions setting three callbacks.
+ * After object(DB_ENV/DB) open, we check if we still can get the callbacks
+ * and check the callbacks. Also, we close the handle.
+ */
+#define TEST_FUNCTION_3ARG_POSTOPEN(handle, getter, func1, func2, func3)\
+ CuAssert(ct, "postopen: "#handle"->"#getter, handle->getter( \
+ handle, &func_rt1, &func_rt2, &func_rt3) == 0); \
+ CuAssert(ct, "postopen: check "#func1, func1 == func_rt1); \
+ CuAssert(ct, "postopen: check "#func2, func2 == func_rt2); \
+ CuAssert(ct, "postopen: check "#func3, func3 == func_rt3); \
+ info.handle = NULL; \
+ CuAssert(ct, #handle"->close", handle->close(handle, 0) == 0)
+
+/*
+ * Test DB_ENV's functions setting one callback.
+ */
+#define TEST_ENV_FUNCTIONS_1ARG(setter, getter, type, func) do { \
+ DB_ENV *dbenvp; \
+ TEST_FUNCTION_1ARG_HEAD(type); \
+ CuAssert(ct, "db_env_create", db_env_create(&dbenvp, 0) == 0); \
+ info.dbenvp = dbenvp; \
+ TEST_FUNCTION_1ARG_PREOPEN(dbenvp, setter, getter, func); \
+ CuAssert(ct, "dbenvp->open", dbenvp->open(dbenvp, TEST_ENV, \
+ DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | \
+ DB_INIT_LOG | DB_INIT_TXN, 0644) == 0); \
+ TEST_FUNCTION_1ARG_POSTOPEN(dbenvp, getter, func); \
+} while(0)
+
+/*
+ * Test DB_ENV's functions setting one callback, both setter and getter
+ * have no return.
+ */
+#define TEST_ENV_FUNCTIONS_1ARG_VOID(setter, getter, type, func) do { \
+ DB_ENV *dbenvp; \
+ TEST_FUNCTION_1ARG_HEAD(type); \
+ CuAssert(ct, "db_env_create", db_env_create(&dbenvp, 0) == 0); \
+ info.dbenvp = dbenvp; \
+ TEST_FUNCTION_1ARG_PREOPEN_VOID(dbenvp, setter, getter, func); \
+ CuAssert(ct, "dbenvp->open", dbenvp->open(dbenvp, TEST_ENV, \
+ DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | \
+ DB_INIT_LOG | DB_INIT_TXN, 0644) == 0); \
+ TEST_FUNCTION_1ARG_POSTOPEN_VOID(dbenvp, getter, func); \
+} while(0)
+
+/*
+ * Test DB_ENV's functions setting two callbacks.
+ */
+#define TEST_ENV_FUNCTIONS_2ARG(setter, getter, type1, func1, type2, func2)\
+ do { \
+ DB_ENV *dbenvp; \
+ TEST_FUNCTION_2ARG_HEAD(type1, type2); \
+ CuAssert(ct, "db_env_create", db_env_create(&dbenvp, 0) == 0); \
+ info.dbenvp = dbenvp; \
+ TEST_FUNCTION_2ARG_PREOPEN(dbenvp, setter, getter, \
+ func1, func2); \
+ CuAssert(ct, "dbenvp->open", dbenvp->open(dbenvp, TEST_ENV, \
+ DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | \
+ DB_INIT_LOG | DB_INIT_TXN, 0644) == 0); \
+ TEST_FUNCTION_2ARG_POSTOPEN(dbenvp, getter, func1, func2); \
+} while(0)
+
+/*
+ * Test DB_ENV's functions setting three callbacks.
+ */
+#define TEST_ENV_FUNCTIONS_3ARG(setter, getter, type1, func1, type2, \
+ func2, type3, func3) do { \
+ DB_ENV *dbenvp; \
+ TEST_FUNCTION_3ARG_HEAD(type1, type2, type3); \
+ CuAssert(ct, "db_env_create", db_env_create(&dbenvp, 0) == 0); \
+ info.dbenvp = dbenvp; \
+ TEST_FUNCTION_3ARG_PREOPEN(dbenvp, setter, getter, func1, func2,\
+ func3); \
+ CuAssert(ct, "dbenvp->open", dbenvp->open(dbenvp, TEST_ENV, \
+ DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_LOG | \
+ DB_INIT_TXN, 0644) == 0); \
+ TEST_FUNCTION_3ARG_POSTOPEN(dbenvp, getter, func1, func2, \
+ func3); \
+} while(0)
+
+/*
+ * Macro for opening database handle.
+ */
+#define TEST_DB_OPEN(dbtype) if (dbtype == DB_BTREE) { \
+ CuAssert(ct, "dbp->set_flags(DB_DUPSORT)", \
+ dbp->set_flags(dbp, DB_DUPSORT) == 0); \
+ } \
+ sprintf(buf, "%s/%d.db", TEST_ENV, indx++); \
+ CuAssert(ct, "dbp->open", dbp->open(dbp, NULL, buf, NULL, \
+ dbtype, DB_CREATE, 0644) == 0)
+
+/*
+ * Test DB's functions setting one callback.
+ */
+#define TEST_DB_FUNCTIONS_1ARG(setter, getter, dbtype, type, func) do { \
+ DB *dbp; \
+ char buf[DB_MAXPATHLEN]; \
+ TEST_FUNCTION_1ARG_HEAD(type); \
+ CuAssert(ct, "db_create", db_create(&dbp, NULL, 0) == 0); \
+ info.dbp = dbp; \
+ TEST_FUNCTION_1ARG_PREOPEN(dbp, setter, getter, func); \
+ TEST_DB_OPEN(dbtype); \
+ TEST_FUNCTION_1ARG_POSTOPEN(dbp, getter, func); \
+} while(0)
+
+/*
+ * Test DB's functions setting one callback, both setter and getter
+ * have no return.
+ */
+#define TEST_DB_FUNCTIONS_1ARG_VOID(setter, getter, dbtype, type, func) \
+ do { \
+ DB *dbp; \
+ char buf[DB_MAXPATHLEN]; \
+ TEST_FUNCTION_1ARG_HEAD(type); \
+ CuAssert(ct, "db_create", db_create(&dbp, NULL, 0) == 0); \
+ info.dbp = dbp; \
+ TEST_FUNCTION_1ARG_PREOPEN_VOID(dbp, setter, getter, func); \
+ TEST_DB_OPEN(dbtype); \
+ TEST_FUNCTION_1ARG_POSTOPEN_VOID(dbp, getter, func); \
+} while(0)
+
+/*
+ * Test DB's functions setting two callbacks.
+ */
+#define TEST_DB_FUNCTIONS_2ARG(setter, getter, dbtype, \
+ type1, func1, type2, func2) do { \
+ DB *dbp; \
+ char buf[DB_MAXPATHLEN]; \
+ TEST_FUNCTION_2ARG_HEAD(type1, type2); \
+ CuAssert(ct, "db_create", db_create(&dbp, NULL, 0) == 0); \
+ info.dbp = dbp; \
+ TEST_FUNCTION_2ARG_PREOPEN(dbp, setter, getter, func1, func2); \
+ TEST_DB_OPEN(dbtype); \
+ TEST_FUNCTION_2ARG_POSTOPEN(dbp, getter, func1, func2); \
+} while(0)
+
+/*
+ * Test DB's functions setting three callbacks.
+ */
+#define TEST_DB_FUNCTIONS_3ARG(setter, getter, dbtype, type1, func1, \
+ type2, func2, type3, func3) do { \
+ DB *dbp; \
+ char buf[DB_MAXPATHLEN]; \
+ TEST_FUNCTION_3ARG_HEAD(type1, type2, type3); \
+ CuAssert(ct, "db_create", db_create(&dbp, NULL, 0) == 0); \
+ info.dbp = dbp; \
+ TEST_FUNCTION_3ARG_PREOPEN(dbp, setter, getter, func1, func2, \
+ func3); \
+ TEST_DB_OPEN(dbtype); \
+ TEST_FUNCTION_3ARG_POSTOPEN(dbp, getter, func1, func2, func3); \
+} while(0)
+
+
+struct handlers {
+ DB_ENV *dbenvp;
+ DB *dbp;
+};
+static struct handlers info;
+static u_int32_t nparts = 5;
+
+int TestCallbackSetterAndGetterSuiteSetup(CuSuite *suite) {
+ return (0);
+}
+
+int TestCallbackSetterAndGetterSuiteTeardown(CuSuite *suite) {
+ return (0);
+}
+
+int TestCallbackSetterAndGetterTestSetup(CuTest *ct) {
+ setup_envdir(TEST_ENV, 1);
+ info.dbenvp = NULL;
+ info.dbp = NULL;
+ return (0);
+}
+
+int TestCallbackSetterAndGetterTestTeardown(CuTest *ct) {
+ if (info.dbp != NULL)
+ CuAssert(ct, "dbp->close",
+ info.dbp->close(info.dbp, 0) == 0);
+ if (info.dbenvp != NULL)
+ CuAssert(ct, "dbenvp->close",
+ info.dbenvp->close(info.dbenvp, 0) == 0);
+ return (0);
+}
+
+
+int TestEnvCallbacks(CuTest *ct) {
+
+ TEST_ENV_FUNCTIONS_3ARG(set_alloc, get_alloc, app_malloc_fcn,
+ t_malloc, app_realloc_fcn, t_realloc, app_free_fcn, t_free);
+ TEST_ENV_FUNCTIONS_1ARG(set_app_dispatch, get_app_dispatch,
+ tx_recover_fcn, t_app_dispatch);
+ TEST_ENV_FUNCTIONS_3ARG(set_backup_callbacks, get_backup_callbacks,
+ open_func, t_open_func, write_func, t_write_func, close_func,
+ t_close_func);
+ TEST_ENV_FUNCTIONS_1ARG_VOID(set_errcall, get_errcall,
+ db_errcall_fcn, t_errcall);
+ TEST_ENV_FUNCTIONS_1ARG(set_feedback, get_feedback,
+ dbenv_feedback_fcn, t_dbenv_callback);
+
+ /*
+ * The DB_ENV->set_is_alive requires the thread area be created,
+ * so we call DB_ENV->set_thread_count to enable the creation
+ * during environment open.
+ */
+ {
+ DB_ENV *dbenvp;
+ TEST_FUNCTION_1ARG_HEAD(is_alive_fcn);
+ setup_envdir(TEST_ENV, 1);
+ CuAssert(ct, "db_env_create", db_env_create(&dbenvp, 0) == 0);
+ info.dbenvp = dbenvp;
+ TEST_FUNCTION_1ARG_PREOPEN(dbenvp, set_isalive, get_isalive,
+ t_is_alive);
+ CuAssert(ct, "dbenvp->set_thread_count",
+ dbenvp->set_thread_count(dbenvp, 50) == 0);
+ CuAssert(ct, "dbenvp->open", dbenvp->open(dbenvp, TEST_ENV,
+ DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK |
+ DB_INIT_LOG | DB_INIT_TXN, 0644) == 0);
+ TEST_FUNCTION_1ARG_POSTOPEN(dbenvp, get_isalive, t_is_alive);
+ setup_envdir(TEST_ENV, 1);
+ }
+
+ TEST_ENV_FUNCTIONS_1ARG_VOID(set_msgcall, get_msgcall,
+ db_msgcall_fcn, t_msgcall);
+ TEST_ENV_FUNCTIONS_1ARG(set_thread_id, get_thread_id_fn,
+ thread_id_fcn, t_thread_id);
+ TEST_ENV_FUNCTIONS_1ARG(set_thread_id_string,
+ get_thread_id_string_fn, thread_id_string_fcn, t_thread_id_string);
+
+ return (0);
+}
+
+int TestDbCallbacks(CuTest *ct) {
+ int indx;
+
+ indx = 0;
+ TEST_DB_FUNCTIONS_3ARG(set_alloc, get_alloc, DB_BTREE, app_malloc_fcn,
+ t_malloc, app_realloc_fcn, t_realloc, app_free_fcn, t_free);
+ TEST_DB_FUNCTIONS_1ARG(set_dup_compare, get_dup_compare, DB_BTREE,
+ dup_compare_fcn, t_dup_compare);
+ TEST_DB_FUNCTIONS_1ARG_VOID(set_errcall, get_errcall, DB_BTREE,
+ db_errcall_fcn, t_errcall);
+ TEST_DB_FUNCTIONS_1ARG(set_feedback, get_feedback, DB_BTREE,
+ db_feedback_fcn, t_db_feedback);
+ TEST_DB_FUNCTIONS_1ARG_VOID(set_msgcall, get_msgcall, DB_BTREE,
+ db_msgcall_fcn, t_msgcall);
+
+ /*
+ * Test DB->set_partition and DB->get_partition_callbacks.
+ * Like others, we do setting before DB->open, and do
+ * getting before and after DB->open.
+ */
+ {
+ DB *dbp;
+ char buf[DB_MAXPATHLEN];
+ u_int32_t nparts_rt;
+ db_partition_fcn func_rt;
+
+ nparts_rt = 0;
+ func_rt = NULL;
+ CuAssert(ct, "db_create", db_create(&dbp, NULL, 0) == 0);
+ info.dbp = dbp;
+ CuAssert(ct, "dbp->set_partition", dbp->set_partition(dbp,
+ nparts, NULL, t_db_partition) == 0);
+ CuAssert(ct, "dbp->get_partition_callbacks",
+ dbp->get_partition_callback(dbp,
+ &nparts_rt, &func_rt) == 0);
+ CuAssert(ct, "check nparts", nparts_rt == nparts);
+ CuAssert(ct, "check partition callback",
+ func_rt == t_db_partition);
+ sprintf(buf, "%s/%d.db", TEST_ENV, indx++);
+ CuAssert(ct, "dbp->open", dbp->open(dbp, NULL, buf, NULL,
+ DB_BTREE, DB_CREATE, 0644) == 0);
+ CuAssert(ct, "dbp->get_partition_callbacks",
+ dbp->get_partition_callback(dbp,
+ &nparts_rt, &func_rt) == 0);
+ CuAssert(ct, "check nparts", nparts_rt == nparts);
+ CuAssert(ct, "check partition callback",
+ func_rt == t_db_partition);
+ info.dbp = NULL;
+ CuAssert(ct, "dbp->close", dbp->close(dbp, 0) == 0);
+ }
+
+ TEST_DB_FUNCTIONS_1ARG(set_append_recno, get_append_recno, DB_RECNO,
+ db_append_recno_fcn, t_append_recno);
+ TEST_DB_FUNCTIONS_1ARG(set_bt_compare, get_bt_compare, DB_BTREE,
+ bt_compare_fcn, t_bt_compare);
+ TEST_DB_FUNCTIONS_2ARG(set_bt_compress, get_bt_compress, DB_BTREE,
+ bt_compress_fcn, t_compress, bt_decompress_fcn, t_decompress);
+
+ /*
+ * DB->set_bt_prefix requires DB do not use the default comparision
+ * function, so we call DB->set_bt_compare to set the comparision
+ * callback first.
+ */
+ {
+ DB *dbp;
+ char buf[DB_MAXPATHLEN];
+ TEST_FUNCTION_1ARG_HEAD(bt_prefix_fcn);
+ CuAssert(ct, "db_create", db_create(&dbp, NULL, 0) == 0);
+ info.dbp = dbp;
+ TEST_FUNCTION_1ARG_PREOPEN(dbp, set_bt_prefix, get_bt_prefix,
+ t_bt_prefix);
+ CuAssert(ct, "dbp->set_bt_compare",
+ dbp->set_bt_compare(dbp, t_bt_compare) == 0);
+ TEST_DB_OPEN(DB_BTREE);
+ TEST_FUNCTION_1ARG_POSTOPEN(dbp, get_bt_prefix, t_bt_prefix);
+ }
+
+ TEST_DB_FUNCTIONS_1ARG(set_h_compare, get_h_compare, DB_HASH,
+ h_compare_fcn, t_h_compare);
+ TEST_DB_FUNCTIONS_1ARG(set_h_hash, get_h_hash, DB_HASH,
+ h_hash_fcn, t_h_hash);
+
+ return (0);
+}
+
+static void *t_malloc(size_t sz) {
+ void *p;
+ int ret;
+
+ if ((ret = __os_malloc(NULL, sz, &p)) != 0)
+ p = NULL;
+ return p;
+}
+
+static void *t_realloc(void *addr, size_t sz) {
+ void *p;
+ int ret;
+
+ p = addr;
+ if ((ret = __os_realloc(NULL, sz, &p)) != 0)
+ p = NULL;
+ return p;
+}
+
+static void t_free(void *addr) {
+ __os_free(NULL, addr);
+}
+
+static int t_app_dispatch(DB_ENV *dbenv,
+ DBT *log_rec, DB_LSN *lsn, db_recops op) {
+ return 0;
+}
+
+static int t_open_func(DB_ENV *dbenv, const char *dbname,
+ const char *target, void **handle) {
+ return 0;
+}
+
+static int t_write_func(DB_ENV *dbenv, u_int32_t offset_gbytes,
+ u_int32_t offset_bytes, u_int32_t size, u_int8_t *buf, void *handle) {
+ return 0;
+}
+
+static int t_close_func(DB_ENV *dbenv, const char *dbname, void *handle) {
+ return 0;
+}
+
+static void t_errcall(const DB_ENV *dbenv,
+ const char *errpfx, const char *msg) {
+ return;
+}
+
+static void t_dbenv_callback(DB_ENV *dbenv, int opcode, int percent) {
+ return;
+}
+
+static int t_is_alive(DB_ENV *dbenv,
+ pid_t pid, db_threadid_t tid, u_int32_t flags) {
+ return 1;
+}
+
+static void t_msgcall(const DB_ENV *dbenv, const char *msg) {
+ return;
+}
+
+static void t_thread_id(DB_ENV *dbenv, pid_t *pid, db_threadid_t *tid) {
+ __os_id(dbenv, pid, tid);
+}
+
+static char *t_thread_id_string(DB_ENV *dbenv,
+ pid_t pid, db_threadid_t tid, char *buf) {
+ buf[0] = '\0';
+ return buf;
+}
+
+static int t_dup_compare(DB *db,
+ const DBT *dbt1, const DBT *dbt2, size_t *locp) {
+ return t_bt_compare(db, dbt1, dbt2, locp);
+}
+
+static void t_db_feedback(DB *dbp, int opcode, int percent) {
+ return;
+}
+
+static u_int32_t t_db_partition(DB *db, DBT *key) {
+ return (key->size % nparts);
+}
+
+static int t_append_recno(DB *dbp, DBT *data, db_recno_t recno) {
+ size_t sz;
+ sz = sizeof(recno) > data->size ? data->size : sizeof(recno);
+ memcpy(data->data, &recno, sz);
+ return 0;
+}
+
+static int t_bt_compare(DB *db,
+ const DBT *dbt1, const DBT *dbt2, size_t *locp) {
+ u_int32_t len;
+ int ret;
+
+ locp = NULL;
+ len = dbt1->size > dbt2->size ? dbt2->size : dbt1->size;
+ if ((ret = memcmp(dbt1->data, dbt2->data, (size_t)len)) == 0) {
+ if (dbt1->size != dbt2->size)
+ ret = dbt1->size > dbt2->size ? 1 : -1;
+ }
+ return ret;
+}
+
+static int t_compress(DB *db, const DBT *prevKey, const DBT *prevData,
+ const DBT *key, const DBT *data, DBT *dest) {
+ return 0;
+}
+
+static int t_decompress(DB *db, const DBT *prevKey,const DBT *prevData,
+ DBT *compressed, DBT *destKey, DBT *destData) {
+ return 0;
+}
+
+static size_t t_bt_prefix(DB *db, const DBT *dbt1, const DBT *dbt2) {
+ u_int32_t len;
+
+ len = dbt1->size > dbt2->size ? dbt2->size : dbt1->size;
+ if (dbt1->size != dbt2->size)
+ len++;
+ return (size_t)len;
+}
+
+static int t_h_compare(DB *db,
+ const DBT *dbt1, const DBT *dbt2, size_t *locp) {
+ return t_bt_compare(db, dbt1, dbt2, locp);
+}
+
+static u_int32_t t_h_hash(DB *dbp, const void *bytes, u_int32_t length) {
+ return length;
+}
+
diff --git a/test/c/suites/TestChannel.c b/test/c/suites/TestChannel.c
index dfbf4e8d..03cebd91 100644
--- a/test/c/suites/TestChannel.c
+++ b/test/c/suites/TestChannel.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2011, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015 Oracle and/or its affiliates. All rights reserved.
*/
#include <ctype.h>
@@ -107,7 +107,6 @@ static void msg_disp2 __P((DB_ENV *, DB_CHANNEL *, DBT *, u_int32_t, u_int32_t))
static void msg_disp3 __P((DB_ENV *, DB_CHANNEL *, DBT *, u_int32_t, u_int32_t));
static void msg_disp4 __P((DB_ENV *, DB_CHANNEL *, DBT *, u_int32_t, u_int32_t));
static void msg_disp5 __P((DB_ENV *, DB_CHANNEL *, DBT *, u_int32_t, u_int32_t));
-static int mystrcmp __P((char *, const char *));
static void notify __P((DB_ENV *, u_int32_t, void *));
static int is_started __P((void *));
static void td __P((DB_ENV *));
@@ -170,9 +169,12 @@ int TestChannelTestTeardown(CuTest *test) {
static void
myerrcall(const DB_ENV *dbenv, const char *errpfx, const char *msg) {
struct report *rpt = get_rpt(dbenv);
+ char *msgp;
assert(rpt->msg_count < MAX_MSGS);
- assert((rpt->msg[rpt->msg_count++] = strdup(msg)) != NULL);
+ msgp = strdup(msg);
+ assert(msgp != NULL);
+ rpt->msg[rpt->msg_count++] = msgp;
}
static int
@@ -449,11 +451,10 @@ int TestChannelFeature(CuTest *ct) {
/* Wait til dbenv2 has reported 1 msg. */
info.dbenv = dbenv2;
info.count = 1;
- await_condition(has_msgs, &info, 60);
+ await_condition(has_msgs, &info, 90);
rpt = get_rpt(dbenv2);
CuAssertTrue(ct, rpt->msg_count == 1);
- CuAssertTrue(ct, mystrcmp(rpt->msg[0],
- "No message dispatch call-back function has been configured") == 0);
+ CuAssertTrue(ct, strncmp(rpt->msg[0], "BDB3670", strlen("BDB3670")) == 0);
printf("2. send request with no msg dispatch in place\n");
clear_rpt(dbenv2);
@@ -461,10 +462,9 @@ int TestChannelFeature(CuTest *ct) {
CuAssertTrue(ct, ret == DB_NOSERVER);
if (resp.data != NULL)
free(resp.data);
- await_condition(has_msgs, &info, 60);
+ await_condition(has_msgs, &info, 90);
CuAssertTrue(ct, rpt->msg_count == 1);
- CuAssertTrue(ct, mystrcmp(rpt->msg[0],
- "No message dispatch call-back function has been configured") == 0);
+ CuAssertTrue(ct, strncmp(rpt->msg[0], "BDB3670", strlen("BDB3670")) == 0);
CuAssertTrue(ct, (ret = dbenv2->repmgr_msg_dispatch(dbenv2, msg_disp, 0)) == 0);
@@ -476,8 +476,7 @@ int TestChannelFeature(CuTest *ct) {
free(resp.data);
await_done(dbenv2);
CuAssertTrue(ct, rpt->msg_count == 1);
- CuAssertTrue(ct, mystrcmp(rpt->msg[0],
- "Application failed to provide a response") == 0);
+ CuAssertTrue(ct, strncmp(rpt->msg[0], "BDB3671", strlen("BDB3671")) == 0);
printf("4. now with dispatch fn installed, send a simple async msg\n");
clear_rpt(dbenv2);
@@ -519,8 +518,7 @@ int TestChannelFeature(CuTest *ct) {
CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 3, &resp, 0, 0)) == DB_BUFFER_SMALL);
await_done(dbenv2);
CuAssertTrue(ct, rpt->msg_count == 1);
- CuAssertTrue(ct, mystrcmp(rpt->msg[0],
- "originator's USERMEM buffer too small") == 0);
+ CuAssertTrue(ct, strncmp(rpt->msg[0], "BDB3659", strlen("BDB3659")) == 0);
CuAssertTrue(ct, rpt->ret == EINVAL);
#define BUFLEN 20000
@@ -536,8 +534,7 @@ int TestChannelFeature(CuTest *ct) {
CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 2, &resp, 0, 0)) == DB_BUFFER_SMALL);
await_done(dbenv2);
CuAssertTrue(ct, rpt->msg_count == 1);
- CuAssertTrue(ct, mystrcmp(rpt->msg[0],
- "originator does not accept multi-segment response") == 0);
+ CuAssertTrue(ct, strncmp(rpt->msg[0], "BDB3658", strlen("BDB3658")) == 0);
CuAssertTrue(ct, rpt->ret == EINVAL);
printf("9. send USERMEM request with DB_MULTIPLE\n");
@@ -776,12 +773,9 @@ int TestChannelFeature(CuTest *ct) {
rpt = get_rpt(dbenv3);
CuAssertTrue(ct, rpt->ret == EINVAL);
CuAssertTrue(ct, rpt->msg_count == 3);
- CuAssertTrue(ct, mystrcmp(rpt->msg[0],
- "set_timeout() invalid on DB_CHANNEL supplied to msg dispatch function") == 0);
- CuAssertTrue(ct, mystrcmp(rpt->msg[1],
- "close() invalid on DB_CHANNEL supplied to msg dispatch function") == 0);
- CuAssertTrue(ct, mystrcmp(rpt->msg[2],
-"send_request() invalid on DB_CHANNEL supplied to msg dispatch function") == 0);
+ CuAssertTrue(ct, strncmp(rpt->msg[0], "BDB3660", strlen("BDB3660")) == 0);
+ CuAssertTrue(ct, strncmp(rpt->msg[1], "BDB3660", strlen("BDB3660")) == 0);
+ CuAssertTrue(ct, strncmp(rpt->msg[2], "BDB3660", strlen("BDB3660")) == 0);
ch->close(ch, 0);
free(buffer);
@@ -1263,23 +1257,6 @@ test_zeroes(ch, dest, ct)
free(resp.data);
}
-/*
- * Compare, but skip over BDB error msg number at beginning of `actual'.
- */
-static int
-mystrcmp(actual, expected)
- char *actual;
- const char *expected;
-{
- char *p;
-
- for (p = actual; *p != '\0' && !isspace(*p); p++)
- ;
- for (; *p != '\0' && isspace(*p); p++)
- ;
- return (strcmp(p, expected));
-}
-
static int get_avail_ports(ports, count)
u_int *ports;
int count;
@@ -1334,8 +1311,8 @@ static int get_avail_ports(ports, count)
i = incr;
while (i-- > 0) {
- if (ret = __repmgr_getaddr(NULL, "localhost", curport,
- AI_PASSIVE, &orig_ai) != 0)
+ if ((ret = __repmgr_getaddr(NULL, "localhost", curport,
+ AI_PASSIVE, &orig_ai)) != 0)
goto end;
for (ai = orig_ai; ai != NULL; ai = ai->ai_next) {
diff --git a/test/c/suites/TestDbHotBackup.c b/test/c/suites/TestDbHotBackup.c
index b330e734..753b182c 100644
--- a/test/c/suites/TestDbHotBackup.c
+++ b/test/c/suites/TestDbHotBackup.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2011, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*/
@@ -9,12 +9,24 @@
/*
* A C Unit test for db_hotbackup APIs [#20451]
*
- * Different testing environments:
- * without any configuration,
- * have partitioned databases,
- * have multiple add_data_dir configured,
- * have set_lg_dir configured,
- * with queue extent files.
+ * Test casess:
+ * 1. btree database without any environment/database configured, backup only
+ * the database file without callbacks;
+ * 2. btree database without any environment/database configured, backup only
+ * the database file with callbacks;
+ * 3. btree database without any environment/database configured, backup only
+ * the database file with backup configurations;
+ * 4. btree partitioned database, backup the whole environment into a single
+ * directory;
+ * 5. btree database with multiple add_data_dir configured, backup the whole
+ * environment including DB_CONFIG and maintain its directory structure in
+ * the backup directory;
+ * 6. btree database with set_lg_dir configured, backup the whole environment
+ * with callbacks including DB_CONFIG and maintain its directory structure in
+ * the backup directory;
+ * 7. queue database having multiple queue extent files, backup only the
+ * database file without callbacks;
+ * 8. heap database, backup only the database file without callbacks.
*
*/
@@ -27,38 +39,35 @@
#include "CuTest.h"
#include "test_util.h"
+/* microseconds in a second */
+#define US_PER_SEC 1000000
+
struct handlers {
DB_ENV *dbenvp;
DB *dbp;
};
-typedef enum {
- SIMPLE_ENV = 1,
- PARTITION_DB = 2,
- MULTI_DATA_DIR = 3,
- SET_LOG_DIR = 4,
- QUEUE_DB = 5
-} ENV_CONF_T;
-
-static int setup_test(ENV_CONF_T);
-static int open_dbp(DB_ENV **, DB **, ENV_CONF_T);
-static int store_records(DB *, ENV_CONF_T);
-static int cleanup_test(DB_ENV *, DB *);
+static int backup_close(DB_ENV *, const char *, void *);
static int backup_db(CuTest *, DB_ENV *, const char *, u_int32_t, int);
static int backup_env(CuTest *, DB_ENV *, u_int32_t, int);
-static int make_dbconfig(ENV_CONF_T);
-static int verify_db(ENV_CONF_T);
-static int verify_log(ENV_CONF_T);
-static int verify_dbconfig(ENV_CONF_T);
+static int backup_open(DB_ENV *, const char *, const char *, void **);
+static int backup_write(DB_ENV *, u_int32_t,
+ u_int32_t, u_int32_t, u_int8_t *, void *);
+static int cleanup_test(DB_ENV *, DB *);
static int cmp_files(const char *, const char *);
-int backup_open(DB_ENV *, const char *, const char *, void **);
-int backup_write(DB_ENV *, u_int32_t, u_int32_t, u_int32_t, u_int8_t *, void *);
-int backup_close(DB_ENV *, const char *, void *);
+static int make_dbconfig(const char *);
+static int open_dbp(DB_ENV **, DB **, DBTYPE,
+ u_int32_t, char **, const char *, const char *, u_int32_t, DBT *);
+static int setup_dir(u_int32_t, char **);
+static int store_records(DB *, u_int32_t);
+static int test_backup_onlydbfile(CuTest *, DBTYPE, int);
+static int verify_db_log(DBTYPE, u_int32_t,
+ u_int32_t, const char *, const char *);
+static int verify_dbconfig(u_int32_t);
#define BACKUP_DIR "BACKUP"
#define BACKUP_DB "backup.db"
#define LOG_DIR "LOG"
-#define NPARTS 3
char *data_dirs[3] = {"DATA1", "DATA2", NULL};
@@ -98,282 +107,394 @@ int TestDbHotBackupTestTeardown(CuTest *ct) {
return (0);
}
-int TestDbHotBackupSimpleEnv(CuTest *ct) {
+int TestBackupSimpleEnvNoCallback(CuTest *ct) {
+ CuAssertTrue(ct, test_backup_onlydbfile(ct, DB_BTREE, 0) == 0);
+
+ return (0);
+}
+
+int TestBackupSimpleEnvWithCallback(CuTest *ct) {
+ CuAssertTrue(ct, test_backup_onlydbfile(ct, DB_BTREE, 1) == 0);
+
+ return (0);
+}
+
+int TestBackupSimpleEnvWithConfig(CuTest *ct) {
DB_ENV *dbenv;
DB *dbp;
- ENV_CONF_T envconf;
+ DBTYPE dtype;
struct handlers *info;
char **names;
int cnt, has_callback;
- u_int32_t flag;
+ time_t end_time, secs1, secs2, start_time;
+ u_int32_t flag, value;
- envconf = SIMPLE_ENV;
+ dtype = DB_BTREE;
info = ct->context;
has_callback = 0;
flag = DB_EXCL;
+ end_time = secs1 = secs2 = start_time = 0;
- /* Step 1: set up test by making relative directories. */
- CuAssert(ct, "setup_test", setup_test(envconf) == 0);
+ /* Step 1: set up directories. */
+ CuAssert(ct, "setup_dir", setup_dir(0, NULL) == 0);
/* Step 2: open db handle. */
- CuAssert(ct,"open_dbp", open_dbp(&dbenv, &dbp, envconf) == 0);
+ CuAssert(ct, "open_dbp", open_dbp(&dbenv,
+ &dbp, dtype, 0, NULL, NULL, NULL, 0, NULL) == 0);
info->dbenvp = dbenv;
info->dbp = dbp;
- /* Step 3: store records into db. */
- CuAssert(ct,"store_records", store_records(dbp, envconf) == 0);
+ /*
+ * Step 3: store records into db so that there is more than
+ * 1 data page in the db.
+ */
+ CuAssert(ct, "store_records", store_records(dbp, 10) == 0);
CuAssert(ct, "DB->sync", dbp->sync(dbp, 0) == 0);
- /* Step 4: backup only the db file without callbacks. */
- CuAssert(ct, "backup_env",
+ /*
+ * Step 4: verify the backup handle is NULL,
+ * since we never configure the backup.
+ */
+ CuAssert(ct, "DB_ENV->get_backup_config",
+ dbenv->get_backup_config(dbenv,
+ DB_BACKUP_WRITE_DIRECT, &value) == EINVAL);
+
+ /*
+ * Step 5: backup without any backup configs.
+ * 5a: backup only the db file without callbacks and record the time.
+ */
+ start_time = time(NULL);
+ CuAssert(ct, "backup_db",
+ backup_db(ct, dbenv, BACKUP_DB, flag, has_callback) == 0);
+ end_time = time(NULL);
+ secs1 = end_time - start_time;
+
+ /* 5b: verify db file is in BACKUP_DIR. */
+ CuAssert(ct, "verify_db_log",
+ verify_db_log(dtype, 0, 0, NULL, NULL) == 0);
+
+ /* 5c: verify that no other files are in BACKUP_DIR. */
+ CuAssert(ct, "__os_dirlist",
+ __os_dirlist(NULL, BACKUP_DIR, 0, &names, &cnt) == 0);
+ CuAssert(ct, "too many files in backupdir", cnt == 1);
+
+ /* Clean up the backup directory. */
+ setup_envdir(BACKUP_DIR, 1);
+
+ /*
+ * Step 6: backup with backup configs.
+ * 6a: configure the backup handle: use direct I/O to write pages to
+ * the disk, the backup buffer size is 256 bytes (which is smaller
+ * than the db page size), the number of pages
+ * to read before pausing is 1, and the number of seconds to sleep
+ * between batches of reads is 1.
+ */
+ CuAssert(ct, "DB_ENV->set_backup_config",
+ dbenv->set_backup_config(dbenv, DB_BACKUP_WRITE_DIRECT, 1) == 0);
+ CuAssert(ct, "DB_ENV->set_backup_config",
+ dbenv->set_backup_config(dbenv, DB_BACKUP_SIZE, 256) == 0);
+ CuAssert(ct, "DB_ENV->set_backup_config",
+ dbenv->set_backup_config(dbenv, DB_BACKUP_READ_COUNT, 1) == 0);
+ CuAssert(ct, "DB_ENV->set_backup_config",
+ dbenv->set_backup_config(dbenv,
+ DB_BACKUP_READ_SLEEP, US_PER_SEC / 2) == 0);
+
+ /*
+ * 6b: backup only the db file without callbacks and
+ * record the time.
+ */
+ start_time = time(NULL);
+ CuAssert(ct, "backup_db",
backup_db(ct, dbenv, BACKUP_DB, flag, has_callback) == 0);
+ end_time = time(NULL);
+ secs2 = end_time - start_time;
- /* Step 5: check backup result. */
- /* 5a: dump the db and verify the content is same. */
- CuAssert(ct, "verify_db", verify_db(envconf) == 0);
+ /* 6c: verify db file is in BACKUP_DIR. */
+ CuAssert(ct, "verify_db_log",
+ verify_db_log(dtype, 0, 0, NULL, NULL) == 0);
- /* 5b: no other files are in backupdir. */
+ /* 6d: no other files are in BACKUP_DIR. */
CuAssert(ct, "__os_dirlist",
__os_dirlist(NULL, BACKUP_DIR, 0, &names, &cnt) == 0);
CuAssert(ct, "too many files in backupdir", cnt == 1);
+ /* 6e: verify the backup config. */
+ CuAssert(ct, "DB_ENV->get_backup_config",
+ dbenv->get_backup_config(dbenv,
+ DB_BACKUP_READ_SLEEP, &value) == 0);
+ CuAssertTrue(ct, value == US_PER_SEC / 2);
+ /*
+ * Verify the backup config DB_BACKUP_READ_SLEEP works. That is with
+ * the configuration, backup pauses for a number of microseconds
+ * between batches of reads. So for the same backup content, the backup
+ * time with the configuration should be longer than that without it.
+ */
+ CuAssertTrue(ct, secs2 > secs1);
+
+ CuAssert(ct, "DB_ENV->get_backup_config",
+ dbenv->get_backup_config(dbenv,
+ DB_BACKUP_READ_COUNT, &value) == 0);
+ CuAssertTrue(ct, value == 1);
+ CuAssert(ct, "DB_ENV->get_backup_config",
+ dbenv->get_backup_config(dbenv, DB_BACKUP_SIZE, &value) == 0);
+ CuAssertTrue(ct, value == 256);
+ CuAssert(ct, "DB_ENV->get_backup_config",
+ dbenv->get_backup_config(dbenv,
+ DB_BACKUP_WRITE_DIRECT, &value) == 0);
+ CuAssertTrue(ct, value == 1);
+
+ /*
+ * Step 7: re-configure the backup write direct config and
+ * verify the new config value.
+ */
+ CuAssert(ct, "DB_ENV->set_backup_config",
+ dbenv->set_backup_config(dbenv, DB_BACKUP_WRITE_DIRECT, 0) == 0);
+ CuAssert(ct, "DB_ENV->get_backup_config",
+ dbenv->get_backup_config(dbenv,
+ DB_BACKUP_WRITE_DIRECT, &value) == 0);
+ CuAssertTrue(ct, value == 0);
+
return (0);
}
-int TestDbHotBackupPartitionDB(CuTest *ct) {
+int TestBackupPartitionDB(CuTest *ct) {
DB_ENV *dbenv;
DB *dbp;
- ENV_CONF_T envconf;
+ DBT key1, key2, keys[2];
+ DBTYPE dtype;
struct handlers *info;
int has_callback;
- u_int32_t flag;
+ u_int32_t flag, value1, value2;
- envconf = PARTITION_DB;
+ dtype = DB_BTREE;
info = ct->context;
has_callback = 0;
flag = DB_BACKUP_CLEAN | DB_CREATE | DB_BACKUP_SINGLE_DIR;
- /* Step 1: set up test by making relative directories. */
- CuAssert(ct, "setup_test", setup_test(envconf) == 0);
+ /* Step 1: set up directories and make DB_CONFIG. */
+ CuAssert(ct, "setup_dir", setup_dir(1, data_dirs) == 0);
+ CuAssert(ct, "make_dbconfig",
+ make_dbconfig("set_data_dir DATA1") == 0);
+
+ /* Make the partition keys. */
+ memset(&key1, 0, sizeof(DBT));
+ memset(&key2, 0, sizeof(DBT));
+ value1 = 8;
+ key1.data = &value1;
+ key1.size = sizeof(value1);
+ value2 = 16;
+ key2.data = &value2;
+ key2.size = sizeof(value2);
+ keys[0] = key1;
+ keys[1] = key2;
/* Step 2: open db handle. */
- CuAssert(ct,"open_dbp", open_dbp(&dbenv, &dbp, envconf) == 0);
+ CuAssert(ct,"open_dbp", open_dbp(&dbenv,
+ &dbp, dtype, 1, data_dirs, data_dirs[0], NULL, 3, keys) == 0);
info->dbenvp = dbenv;
info->dbp = dbp;
/* Step 3: store records into db. */
- CuAssert(ct,"store_records", store_records(dbp, envconf) == 0);
+ CuAssert(ct, "store_records", store_records(dbp, 1) == 0);
CuAssert(ct, "DB->sync", dbp->sync(dbp, 0) == 0);
/* Step 4: backup the whole environment into a single directory. */
CuAssert(ct, "backup_env",
backup_env(ct, dbenv, flag, has_callback) == 0);
- /* Step 5: check backup result. */
- /* 5a: dump the db and verify the content is same. */
- CuAssert(ct, "verify_db", verify_db(envconf) == 0);
+ /*
+ * Step 5: check backup result.
+ * 5a: verify db files are in BACKUP/DATA1.
+ */
+ CuAssert(ct, "verify_db_log",
+ verify_db_log(dtype, 1, 0, data_dirs[0], NULL) == 0);
- /* 5b: verify that creation directory is not in backupdir. */
- CuAssert(ct, "__os_exist", __os_exists(NULL, "BACKUP/DATA1", 0) != 0);
+ /* 5b: verify that creation directory is not in BACKUPD_DIR. */
+ CuAssert(ct, "__os_exist", __os_exists(NULL, "BACKUP/DATA", 0) != 0);
- /* 5c: verify that log files are in backupdir. */
- CuAssert(ct, "verify_log", verify_log(envconf) == 0);
+ /* 5c: verify log files are in BACKUP_DIR. */
+ CuAssert(ct, "verify_db_log",
+ verify_db_log(dtype, 0, 1, NULL, NULL) == 0);
- /* 5d: verify that DB_CONFIG is not in backupdir*/
- CuAssert(ct, "verify_dbconfig", verify_dbconfig(envconf) == 0);
+ /* 5d: verify that DB_CONFIG is not in BACKUP_DIR. */
+ CuAssert(ct, "verify_dbconfig", verify_dbconfig(0) == 0);
return (0);
}
-int TestDbHotBackupMultiDataDir(CuTest *ct) {
+int TestBackupMultiDataDir(CuTest *ct) {
DB_ENV *dbenv;
DB *dbp;
- ENV_CONF_T envconf;
+ DBTYPE dtype;
struct handlers *info;
int has_callback;
u_int32_t flag;
- envconf = MULTI_DATA_DIR;
+ dtype = DB_BTREE;
info = ct->context;
has_callback = 0;
flag = DB_BACKUP_CLEAN | DB_CREATE | DB_BACKUP_FILES;
- /* Step 1: set up test by making relative directories. */
- CuAssert(ct, "setup_test", setup_test(envconf) == 0);
+ /* Step 1: set up directories and make DB_CONFIG. */
+ CuAssert(ct, "setup_dir", setup_dir(2, data_dirs) == 0);
+ CuAssert(ct, "make_dbconfig",
+ make_dbconfig("set_data_dir DATA1") == 0);
/* Step 2: open db handle. */
- CuAssert(ct,"open_dbp", open_dbp(&dbenv, &dbp, envconf) == 0);
+ CuAssert(ct,"open_dbp", open_dbp(&dbenv, &dbp,
+ dtype, 2, data_dirs, data_dirs[0], NULL, 0, NULL) == 0);
info->dbenvp = dbenv;
info->dbp = dbp;
/* Step 3: store records into db. */
- CuAssert(ct,"store_records", store_records(dbp, envconf) == 0);
+ CuAssert(ct, "store_records", store_records(dbp, 1) == 0);
CuAssert(ct, "DB->sync", dbp->sync(dbp, 0) == 0);
/* Step 4: backup the whole environment without callbacks. */
CuAssert(ct, "backup_env",
backup_env(ct, dbenv, flag, has_callback) == 0);
- /* Step 5: check backup result. */
- /* 5a: dump the db and verify the content is same. */
- CuAssert(ct, "verify_db", verify_db(envconf) == 0);
+ /*
+ * Step 5: check backup result.
+ * 5a: verify db files are in BACKUP/DATA1.
+ */
+ CuAssert(ct, "verify_db_log",
+ verify_db_log(dtype, 0, 0, data_dirs[0], data_dirs[0]) == 0);
/* 5b: verify that data_dirs are in backupdir. */
CuAssert(ct, "__os_exist", __os_exists(NULL, "BACKUP/DATA1", 0) == 0);
CuAssert(ct, "__os_exist", __os_exists(NULL, "BACKUP/DATA2", 0) == 0);
- /* 5c: verify that log files are in backupdir. */
- CuAssert(ct, "verify_log", verify_log(envconf) == 0);
+ /* 5c: verify that log files are in BACKUP_DIR. */
+ CuAssert(ct, "verify_db_log",
+ verify_db_log(dtype, 0, 1, NULL, NULL) == 0);
- /* 5d: verify that DB_CONFIG is in backupdir. */
- CuAssert(ct, "verify_dbconfig", verify_dbconfig(envconf) == 0);
+ /* 5d: verify that DB_CONFIG is in BACKUP_DIR. */
+ CuAssert(ct, "verify_dbconfig", verify_dbconfig(1) == 0);
return (0);
}
-int TestDbHotBackupSetLogDir(CuTest *ct) {
+int TestBackupSetLogDir(CuTest *ct) {
DB_ENV *dbenv;
DB *dbp;
- ENV_CONF_T envconf;
+ DBTYPE dtype;
struct handlers *info;
+ char *dirs[2];
int has_callback = 1;
u_int32_t flag;
- envconf = SET_LOG_DIR;
+ dtype = DB_BTREE;
info = ct->context;
has_callback = 1;
flag = DB_BACKUP_CLEAN | DB_CREATE | DB_BACKUP_FILES;
+ dirs[0] = LOG_DIR;
+ dirs[1] = NULL;
- /* Step 1: set up test by making relative directories. */
- CuAssert(ct, "setup_test", setup_test(envconf) == 0);
+ /* Step 1: set up directories and make DB_CONFIG. */
+ CuAssert(ct, "setup_dir", setup_dir(1, dirs) == 0);
+ CuAssert(ct, "make_dbconfig", make_dbconfig("set_lg_dir LOG") == 0);
/* Step 2: open db handle. */
- CuAssert(ct,"open_dbp", open_dbp(&dbenv, &dbp, envconf) == 0);
+ CuAssert(ct,"open_dbp", open_dbp(&dbenv, &dbp,
+ dtype, 0, NULL, NULL, LOG_DIR, 0, NULL) == 0);
info->dbenvp = dbenv;
info->dbp = dbp;
/* Step 3: store records into db. */
- CuAssert(ct,"store_records", store_records(dbp, envconf) == 0);
+ CuAssert(ct, "store_records", store_records(dbp, 1) == 0);
CuAssert(ct, "DB->sync", dbp->sync(dbp, 0) == 0);
- /* Step 4: backup a whole environment with callbacks. */
+ /* Step 4: backup the whole environment with callbacks. */
CuAssert(ct, "backup_env",
backup_env(ct, dbenv, flag, has_callback) == 0);
- /* Step 5: check backup result. */
- /* 5a: dump the db and verify the content is same. */
- CuAssert(ct, "verify_db", verify_db(envconf) == 0);
+ /*
+ * Step 5: check backup result.
+ * 5a: verify the db file is in BACKUP_DIR.
+ */
+ CuAssert(ct, "verify_db_log",
+ verify_db_log(dtype, 0, 0, NULL, NULL) == 0);
- /* 5b: verify that log files are in backupdir/log_dir. */
- CuAssert(ct, "verify_log", verify_log(envconf) == 0);
+ /* 5b: verify that log files are in BACKUP/LOG. */
+ CuAssert(ct, "verify_db_log",
+ verify_db_log(dtype, 0, 1, LOG_DIR, LOG_DIR) == 0);
- /* 5c: verify that DB_CONFIG is in backupdir*/
- CuAssert(ct, "verify_dbconfig", verify_dbconfig(envconf) == 0);
+ /* 5c: verify that DB_CONFIG is in BACKUP_DIR. */
+ CuAssert(ct, "verify_dbconfig", verify_dbconfig(1) == 0);
return (0);
}
-int TestDbHotBackupQueueDB(CuTest *ct) {
- DB_ENV *dbenv;
- DB *dbp;
- ENV_CONF_T envconf;
- struct handlers *info;
- int has_callback;
- u_int32_t flag;
-
- envconf = QUEUE_DB;
- info = ct->context;
- has_callback = 0;
- flag = DB_BACKUP_CLEAN | DB_CREATE;
-
- /* Step 1: set up test by making relative directories. */
- CuAssert(ct, "setup_test", setup_test(envconf) == 0);
+int TestBackupQueueDB(CuTest *ct) {
+ CuAssertTrue(ct, test_backup_onlydbfile(ct, DB_QUEUE, 0) == 0);
- /* Step 2: open db handle. */
- CuAssert(ct,"open_dbp", open_dbp(&dbenv, &dbp, envconf) == 0);
- info->dbenvp = dbenv;
- info->dbp = dbp;
-
- /* Step 3: store records into db. */
- CuAssert(ct,"store_records", store_records(dbp, envconf) == 0);
- CuAssert(ct, "DB->sync", dbp->sync(dbp, 0) == 0);
-
- /* Step 4: backup the whole environment without callbacks. */
- CuAssert(ct, "backup_env",
- backup_env(ct, dbenv, flag, has_callback) == 0);
-
- /* Step 5: check backup result. */
- /* 5a: dump the db and verify the content is same. */
- CuAssert(ct, "verify_db", verify_db(envconf) == 0);
-
- /* 5b: verify that log files are in backupdir. */
- CuAssert(ct, "verify_log", verify_log(envconf) == 0);
+ return (0);
+}
- /* 5c: vertify that DB_CONFIG is not in backupdir. */
- CuAssert(ct, "verify_dbconfig", verify_dbconfig(envconf) == 0);
+int TestBackupHeapDB(CuTest *ct) {
+ CuAssertTrue(ct, test_backup_onlydbfile(ct, DB_HEAP, 0) == 0);
return (0);
}
static int
-setup_test(envconf)
- ENV_CONF_T envconf;
+setup_dir(len, dirs)
+ u_int32_t len;
+ char **dirs;
{
char path[1024];
- int i, ret;
-
- /* Make directories based on config. */
- switch (envconf) {
- case SIMPLE_ENV:
- break;
- case PARTITION_DB:
- snprintf(path, sizeof(path),"%s%c%s",
- TEST_ENV, PATH_SEPARATOR[0], data_dirs[0]);
- if ((ret = setup_envdir(path, 1)) != 0)
- return (ret);
- break;
- case MULTI_DATA_DIR:
- for (i = 0; i < 2; i++) {
- snprintf(path, sizeof(path),"%s%c%s",
- TEST_ENV, PATH_SEPARATOR[0], data_dirs[i]);
+ u_int32_t i;
+ int ret;
+
+ /* Make related directories. */
+ if (len > 0) {
+ for (i = 0; i < len; i++) {
+ ret = snprintf(path, sizeof(path),"%s%c%s",
+ TEST_ENV, PATH_SEPARATOR[0], dirs[i]);
+ if (ret <= 0 || ret >= sizeof(path)) {
+ ret = EINVAL;
+ return (ret);
+ }
if ((ret = setup_envdir(path, 1)) != 0)
return (ret);
}
- break;
- case SET_LOG_DIR:
- snprintf(path, sizeof(path),"%s%c%s",
- TEST_ENV, PATH_SEPARATOR[0], LOG_DIR);
- if ((ret = setup_envdir(path, 1)) != 0)
- return (ret);
- break;
- case QUEUE_DB:
- break;
- default:
- return (EINVAL);
}
- /* Make DB_CONFIG for PARTITION_DB, MULT_DATA_DIR and SET_LOG_DIR. */
- if(envconf >= 2 && envconf <= 4)
- make_dbconfig(envconf);
-
return (0);
}
+/*
+ * open_dbp:
+ * DB_ENV **dbenvp.
+ * DB **dbpp.
+ * DBTYPE dtype: the database type to create.
+ * u_int32_t ddir_len: the number of data directories.
+ * char **data_dir: data directories to add.
+ * const char *create_dir: database creation diretory.
+ * const char *lg_dir: log directory.
+ * u_int32_t nparts: the number of partitions.
+ * DBT *part_key: the partition keys.
+ */
static int
-open_dbp(dbenvp, dbpp, envconf)
+open_dbp(dbenvp, dbpp, dtype,
+ ddir_len, data_dir, create_dir, lg_dir, nparts, part_key)
DB_ENV **dbenvp;
DB **dbpp;
- ENV_CONF_T envconf;
+ DBTYPE dtype;
+ u_int32_t ddir_len, nparts;
+ char **data_dir;
+ const char *create_dir, *lg_dir;
+ DBT *part_key;
{
DB_ENV *dbenv;
DB *dbp;
- DBT key1, key2, keys[2];
- DBTYPE dtype;
- int i, ret, value1, value2;
+ const char *part_dir[2];
+ u_int32_t i;
+ int ret;
dbenv = NULL;
dbp = NULL;
- dtype = DB_BTREE;
ret = 0;
if ((ret = db_env_create(&dbenv, 0)) != 0) {
@@ -386,35 +507,23 @@ open_dbp(dbenvp, dbpp, envconf)
dbenv->set_errfile(dbenv, stderr);
dbenv->set_errpfx(dbenv, "TestDbHotBackup");
- /* Configure the environment. */
- switch (envconf) {
- case SIMPLE_ENV:
- case PARTITION_DB:
- break;
/* Add data directories. */
- case MULTI_DATA_DIR:
- for (i = 0; i < 2; i++) {
+ if (ddir_len > 0 && data_dir != NULL) {
+ for (i = 0; i < ddir_len; i++) {
if ((ret = dbenv->add_data_dir(dbenv,
- data_dirs[i])) != 0) {
+ data_dir[i])) != 0) {
fprintf(stderr, "DB_ENV->add_data_dir: %s\n",
db_strerror(ret));
return (ret);
}
}
- break;
+ }
+
/* Set log directory. */
- case SET_LOG_DIR:
- if ((ret = dbenv->set_lg_dir(dbenv, LOG_DIR)) != 0) {
- fprintf(stderr, "DB_ENV->set_lg_dir: %s\n",
- db_strerror(ret));
- return (ret);
- }
- break;
- case QUEUE_DB:
- dtype = DB_QUEUE;
- break;
- default:
- return (EINVAL);
+ if (lg_dir != NULL && (ret = dbenv->set_lg_dir(dbenv, lg_dir)) != 0) {
+ fprintf(stderr, "DB_ENV->set_lg_dir: %s\n",
+ db_strerror(ret));
+ return (ret);
}
/* Open the environment. */
@@ -435,33 +544,32 @@ open_dbp(dbenvp, dbpp, envconf)
dbp->set_errfile(dbp, stderr);
dbp->set_errpfx(dbp, "TestDbHotBackup");
- /* Set db creation directory for PARTTION_DB and MULTI_DATA_DRI. */
- if (envconf == PARTITION_DB || envconf == MULTI_DATA_DIR) {
- if ((ret = dbp->set_create_dir(dbp, data_dirs[0])) != 0) {
- fprintf(stderr, "DB_ENV->add_data_dir: %s\n",
- db_strerror(ret));
- return (ret);
- }
+ /* Set database creation directory. */
+ if (create_dir != NULL &&
+ (ret = dbp->set_create_dir(dbp, create_dir)) != 0) {
+ fprintf(stderr, "DB_ENV->add_data_dir: %s\n",
+ db_strerror(ret));
+ return (ret);
}
/* Set partition. */
- if (envconf == PARTITION_DB) {
- value1 = 8;
- key1.data = &value1;
- key1.size = sizeof(value1);
- value2 = 16;
- key2.data = &value2;
- key2.size = sizeof(value2);
- keys[0] = key1;
- keys[1] = key2;
- if ((ret = dbp->set_partition(dbp, NPARTS, keys, NULL)) != 0) {
+ if (dtype == DB_BTREE && nparts > 0 && part_key != NULL) {
+ if ((ret = dbp->set_partition(dbp,
+ nparts, part_key, NULL)) != 0) {
dbp->err(dbp, ret, "DB->set_partition");
return (ret);
}
+ if (create_dir != NULL) {
+ part_dir[0]= create_dir;
+ part_dir[1] = NULL;
+ if ((ret =
+ dbp->set_partition_dirs(dbp, part_dir)) != 0)
+ return (ret);
+ }
}
/* Set queue record length and extent size. */
- if (envconf == QUEUE_DB) {
+ if (dtype == DB_QUEUE) {
if ((ret = dbp->set_re_len(dbp, 50)) != 0) {
dbp->err(dbp, ret, "DB->set_re_len");
return (ret);
@@ -470,13 +578,18 @@ open_dbp(dbenvp, dbpp, envconf)
dbp->err(dbp, ret, "DB->set_q_extentsize");
return (ret);
}
- }
- /* Set flag for Btree. */
- else {
+ } else if (dtype == DB_BTREE) {
+ /* Set flag for Btree. */
if ((ret = dbp->set_flags(dbp, DB_DUPSORT)) != 0) {
dbp->err(dbp, ret, "DB->set_flags");
return (ret);
}
+ } else if (dtype == DB_HEAP) {
+ /* Set heap region size. */
+ if ((ret = dbp->set_heap_regionsize(dbp, 1)) != 0) {
+ dbp->err(dbp, ret, "DB->set_heap_regionsize");
+ return (ret);
+ }
}
if ((ret = dbp->set_pagesize(dbp, 512)) != 0) {
@@ -494,19 +607,33 @@ open_dbp(dbenvp, dbpp, envconf)
return (0);
}
+/*
+ * store_records:
+ * DB **dbpp.
+ * u_int32_t iter: put 26 * dups key/data pairs into the database.
+ */
static int
-store_records(dbp, envconf)
+store_records(dbp, dups)
DB *dbp;
- ENV_CONF_T envconf;
+ u_int32_t dups;
{
DBT key, data;
- int i, ret;
- size_t num;
- u_int32_t flag;
+ DBTYPE dtype;
+ u_int32_t flag, i, j, num;
+ int ret;
- char *buf = "abcdefghijefghijklmnopqrstuvwxyz";
- num = strlen(buf);
- flag = envconf == QUEUE_DB ? DB_APPEND : 0;
+ char *buf = "abcdefghijklmnopqrstuvwxyz";
+ num = (u_int32_t)strlen(buf);
+ flag = 0;
+
+ /* Only accepts dups which is between 1 and 26 inclusively. */
+ if (dups < 1 || dups > num)
+ return (EINVAL);
+
+ if ((dbp->get_type(dbp, &dtype)) != 0)
+ return (EINVAL);
+ if (dtype == DB_HEAP || dtype == DB_QUEUE || dtype == DB_RECNO)
+ flag = DB_APPEND;
memset(&key, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
@@ -515,12 +642,20 @@ store_records(dbp, envconf)
key.data = &i;
key.size = sizeof(i);
- data.data = &buf[i];
- data.size = sizeof(char);
-
- if ((ret = dbp->put(dbp, NULL, &key, &data, flag)) != 0) {
- dbp->err(dbp, ret, "DB->put");
- return (ret);
+ /*
+ * If "dups" > 1, we are putting duplicate records into the db
+ * and the number of records for each key is "dups". We already
+ * set DB_DUPSORT when opening the db.
+ */
+ for (j = 1; j <= dups; j++) {
+ data.data = &buf[0];
+ data.size = j * sizeof(char);
+
+ if ((ret = dbp->put(dbp,
+ NULL, &key, &data, flag)) != 0) {
+ dbp->err(dbp, ret, "DB->put");
+ return (ret);
+ }
}
}
return (ret);
@@ -550,11 +685,11 @@ cleanup_test(dbenv, dbp)
/*
* backup_env:
- * CuTest *ct
- * DB_ENV *dbenv: the environment to backup
- * u_int32_t flags: hotbackup flags
- * int has_callback: 0 if not use callback, 1 otherwise
-*/
+ * CuTest *ct.
+ * DB_ENV *dbenv: the environment to backup.
+ * u_int32_t flags: hotbackup flags.
+ * int has_callback: 0 if not use callback, 1 otherwise.
+ */
static int
backup_env(ct, dbenv, flags, has_callback)
CuTest *ct;
@@ -574,13 +709,12 @@ backup_env(ct, dbenv, flags, has_callback)
/*
* backup_db:
- * CuTest *ct
- * DB_ENV *dbenv: the environment to backup
- * const char *dname: the name of db file to backup
- * u_int32_t flags: hot_backup flags
- * int has_callback: 0 if not use callback, 1 otherwise
-*/
-
+ * CuTest *ct.
+ * DB_ENV *dbenv: the environment to backup.
+ * const char *dname: the name of db file to backup.
+ * u_int32_t flags: hot_backup flags.
+ * int has_callback: 0 if not use callback, 1 otherwise.
+ */
static int
backup_db(ct, dbenv, dname, flags, has_callback)
CuTest *ct;
@@ -599,152 +733,143 @@ backup_db(ct, dbenv, dname, flags, has_callback)
return (0);
}
+/*
+ * verify_db_log:
+ * DBTYPE dtype: the database type.
+ * u_int32_t is_part: 0 if the database is not partitioned, 1 otherwise.
+ * u_int32_t is_lg: 1 if verifying the log files, 0 otherwise.
+ * const char *test_cmpdir: the db creation directory or log directory
+ * under TEST_ENV.
+ * const char *backup_cmpdir: the db creation directory or log directory
+ * under BACKUP_DIR.
+ */
static int
-verify_db(envconf)
- ENV_CONF_T envconf;
+verify_db_log(dtype, is_part, is_lg, test_cmpdir, backup_cmpdir)
+ DBTYPE dtype;
+ u_int32_t is_part, is_lg;
+ const char *test_cmpdir, *backup_cmpdir;
{
- char buf1[100], buf2[100], path1[100], path2[100], pfx[10];
+ char *buf1, *buf2, *path1, *path2, *pfx;
char **names1, **names2;
int cnt1, cnt2, i, m_cnt, ret, t_cnt1, t_cnt2;
+ buf1 = buf2 = path1 = path2 = pfx = NULL;
names1 = names2 = NULL;
cnt1 = cnt2 = i = m_cnt = ret = t_cnt1 = t_cnt2 = 0;
- /* Get the data directory paths. */
- if (envconf == PARTITION_DB) {
- snprintf(path1, sizeof(path1), "%s%c%s",
- TEST_ENV, PATH_SEPARATOR[0], data_dirs[0]);
- snprintf(path2, sizeof(path2), "%s", BACKUP_DIR);
- } else if (envconf == MULTI_DATA_DIR) {
- snprintf(path1, sizeof(path1), "%s%c%s",
- TEST_ENV, PATH_SEPARATOR[0], data_dirs[0]);
- snprintf(path2, sizeof(path2), "%s%c%s",
- BACKUP_DIR, PATH_SEPARATOR[0], data_dirs[0]);
- } else {
- snprintf(path1, sizeof(path1), "%s", TEST_ENV);
- snprintf(path2, sizeof(path2), "%s", BACKUP_DIR);
- }
+ /* Either verify db files or log files. */
+ if (is_part != 0 &&
+ (is_lg != 0 || (dtype != DB_BTREE && dtype != DB_HASH)))
+ return (EINVAL);
+
+ /* Get the data or log directory paths. */
+ if ((ret = __os_calloc(NULL, 100, 1, &path1)) != 0)
+ goto err;
+ if ((ret = __os_calloc(NULL, 100, 1, &path2)) != 0)
+ goto err;
+
+ if (test_cmpdir != NULL) {
+ ret = snprintf(path1, 100, "%s%c%s",
+ TEST_ENV, PATH_SEPARATOR[0], test_cmpdir);
+ if (ret <= 0 || ret >= 100) {
+ ret = EINVAL;
+ goto err;
+ }
+ ret = 0;
+ } else
+ snprintf(path1, 100, "%s", TEST_ENV);
+
+ if (backup_cmpdir != NULL) {
+ ret = snprintf(path2, 100, "%s%c%s",
+ BACKUP_DIR, PATH_SEPARATOR[0], backup_cmpdir);
+ if (ret <= 0 || ret >= 100) {
+ ret = EINVAL;
+ goto err;
+ }
+ ret = 0;
+ } else
+ snprintf(path2, 100, "%s", BACKUP_DIR);
- /* Define the prefix of partition db and queue extent files. */
- if (envconf == PARTITION_DB)
- snprintf(pfx, sizeof(pfx), "%s", "__dbp.");
- else if (envconf == QUEUE_DB)
- snprintf(pfx, sizeof(pfx), "%s", "__dbq.");
+ /* Define the prefix of partition db, queue extent or log files. */
+ if ((ret = __os_calloc(NULL, 10, 1, &pfx)) != 0)
+ goto err;
+ if (is_lg != 0)
+ snprintf(pfx, 10, "%s", "log.");
+ else if (is_part != 0)
+ snprintf(pfx, 10, "%s", "__dbp.");
+ else if (dtype == DB_QUEUE)
+ snprintf(pfx, 10, "%s", "__dbq.");
else
pfx[0] = '\0';
- /* Get the lists of db file, partition db files and queue extent. */
+ /* Get the lists of db file, partition files, queue extent or logs. */
if ((ret = __os_dirlist(NULL, path1, 0, &names1, &cnt1)) != 0)
return (ret);
if ((ret = __os_dirlist(NULL, path2, 0, &names2, &cnt2)) != 0)
return (ret);
- /* Get the numbers of db files. */
+ /* Get the file numbers. */
m_cnt = cnt1 > cnt2 ? cnt1 : cnt2;
t_cnt1 = cnt1;
t_cnt2 = cnt2;
for (i = 0; i < m_cnt; i++) {
- if (i < cnt1 &&
- strncmp(names1[i], BACKUP_DB, strlen(BACKUP_DB)) != 0 &&
+ if (i < cnt1 && ((is_lg != 0 &&
+ strncmp(names1[i], pfx, strlen(pfx)) != 0) ||
+ (strncmp(names1[i], BACKUP_DB, strlen(BACKUP_DB)) != 0 &&
(strlen(pfx) > 0 ?
- strncmp(names1[i], pfx, strlen(pfx)) != 0 : 1)) {
- t_cnt1--;
- names1[i] = NULL;
+ strncmp(names1[i], pfx, strlen(pfx)) != 0 : 1)))) {
+ t_cnt1--;
+ names1[i] = NULL;
}
- if (i < cnt2 &&
- strncmp(names2[i], BACKUP_DB, strlen(BACKUP_DB)) != 0 &&
+ if (i < cnt2 && ((is_lg != 0 &&
+ strncmp(names2[i], pfx, strlen(pfx)) != 0) ||
+ (strncmp(names2[i], BACKUP_DB, strlen(BACKUP_DB)) != 0 &&
(strlen(pfx) > 0 ?
- strncmp(names2[i], pfx, strlen(pfx)) != 0 : 1)) {
- t_cnt2--;
- names2[i] = NULL;
- }
+ strncmp(names2[i], pfx, strlen(pfx)) != 0 : 1)))) {
+ t_cnt2--;
+ names2[i] = NULL;
+ }
}
- if ((ret = t_cnt1 == t_cnt2 ? 0 : EINVAL) != 0)
- return (ret);
+ if ((ret = t_cnt1 == t_cnt2 ? 0 : EXIT_FAILURE) != 0)
+ goto err;
- /* Compare each db file. */
+ /* Compare each file. */
+ if ((ret = __os_calloc(NULL, 100, 1, &buf1)) != 0)
+ goto err;
+ if ((ret = __os_calloc(NULL, 100, 1, &buf2)) != 0)
+ goto err;
for (i = 0; i < cnt1; i++) {
if (names1[i] == NULL)
continue;
- snprintf(buf1, sizeof(buf1), "%s%c%s",
+ snprintf(buf1, 100, "%s%c%s",
path1, PATH_SEPARATOR[0], names1[i]);
- snprintf(buf2, sizeof(buf2), "%s%c%s",
+ snprintf(buf2, 100, "%s%c%s",
path2, PATH_SEPARATOR[0], names1[i]);
if ((ret = cmp_files(buf1, buf2)) != 0)
break;
}
+err: if (buf1 != NULL)
+ __os_free(NULL, buf1);
+ if (buf2 != NULL)
+ __os_free(NULL, buf2);
+ if (path1 != NULL)
+ __os_free(NULL, path1);
+ if (path2 != NULL)
+ __os_free(NULL, path2);
+ if (pfx != NULL)
+ __os_free(NULL, pfx);
return (ret);
}
+/*
+ * verify_dbconfig:
+ * u_int32_t is_exist: 1 if DB_CONFIG is expected to exist
+ * in BACKUP_DIR, 0 otherwise.
+ */
static int
-verify_log(envconf)
- ENV_CONF_T envconf;
-{
- char buf1[100], buf2[100], lg1[100], lg2[100], pfx[10];
- char **names1, **names2;
- int cnt1, cnt2, i, m_cnt, ret, t_cnt1, t_cnt2;
-
- cnt1 = cnt2 = i = m_cnt = ret = t_cnt1 = t_cnt2 = 0;
-
- /* Get the log paths. */
- if (envconf == SET_LOG_DIR) {
- snprintf(lg1, sizeof(lg1),
- "%s%c%s", TEST_ENV, PATH_SEPARATOR[0], LOG_DIR);
- snprintf(lg2, sizeof(lg2),
- "%s%c%s", BACKUP_DIR, PATH_SEPARATOR[0], LOG_DIR);
- }
- else {
- snprintf(lg1, sizeof(lg1), "%s", TEST_ENV);
- snprintf(lg2, sizeof(lg2), "%s", BACKUP_DIR);
- }
-
- /* Define the prefix of log file. */
- snprintf(pfx, sizeof(pfx), "%s", "log.");
-
- /* Get the lists of log files. */
- if ((ret = __os_dirlist(NULL, lg1, 0, &names1, &cnt1)) != 0)
- return (ret);
- if ((ret = __os_dirlist(NULL, lg2, 0, &names2, &cnt2)) != 0)
- return (ret);
-
- /* Get the numbers of log files. */
- m_cnt = cnt1 > cnt2 ? cnt1 : cnt2;
- t_cnt1 = cnt1;
- t_cnt2 = cnt2;
- for (i = 0; i < m_cnt; i++) {
- if (i < cnt1 &&
- strncmp(names1[i], pfx, strlen(pfx)) != 0) {
- t_cnt1--;
- names1[i] = NULL;
- }
- if (i < cnt2 &&
- strncmp(names2[i], pfx, strlen(pfx)) != 0) {
- t_cnt2--;
- names2[i] = NULL;
- }
- }
- if ((ret = t_cnt1 == t_cnt2 ? 0 : EINVAL) != 0)
- return (ret);
-
- /* Compare each log file. */
- for (i = 0; i < cnt1; i++) {
- if (names1[i] == NULL)
- continue;
- snprintf(buf1, sizeof(buf1), "%s%c%s",
- lg1, PATH_SEPARATOR[0], names1[i]);
- snprintf(buf2, sizeof(buf2), "%s%c%s",
- lg2, PATH_SEPARATOR[0], names1[i]);
- if ((ret = cmp_files(buf1, buf2)) != 0)
- break;
- }
-
- return (ret);
-}
-
-static int
-verify_dbconfig(envconf)
- ENV_CONF_T envconf;
+verify_dbconfig(is_exist)
+ u_int32_t is_exist;
{
char *path1, *path2;
int ret;
@@ -752,42 +877,37 @@ verify_dbconfig(envconf)
path1 = path2 = NULL;
ret = 0;
- if ((ret = __os_calloc(NULL, 1024, 1, &path1)) != 0)
+ if ((ret = __os_calloc(NULL, 100, 1, &path1)) != 0)
goto err;
- if ((ret = __os_calloc(NULL, 1024, 1, &path2)) != 0)
+ if ((ret = __os_calloc(NULL, 100, 1, &path2)) != 0)
goto err;
- switch(envconf) {
- /* DB_CONFIG is not in backupdir for this test cases. */
- case SIMPLE_ENV:
- case PARTITION_DB:
- case QUEUE_DB:
- if((ret = __os_exists(NULL, "BACKUP/DB_CONFIG", 0)) != 0)
- return (0);
- break;
- /* DB_CONFIG is in backupdir for MULTI_DATA_DIR and SET_LOG_DIR. */
- case MULTI_DATA_DIR:
- case SET_LOG_DIR:
- snprintf(path1, 1024, "%s%c%s",
+ if (is_exist == 0) {
+ if ((ret = __os_exists(NULL, "BACKUP/DB_CONFIG", 0)) != 0) {
+ ret = 0;
+ goto err;
+ } else {
+ ret = EXIT_FAILURE;
+ goto err;
+ }
+ } else {
+ snprintf(path1, 100, "%s%c%s",
TEST_ENV, PATH_SEPARATOR[0], "DB_CONFIG");
- snprintf(path2, 1024, "%s%c%s",
+ snprintf(path2, 100, "%s%c%s",
BACKUP_DIR, PATH_SEPARATOR[0], "DB_CONFIG");
if ((ret = cmp_files(path1, path2)) != 0)
goto err;
- break;
- default:
- return (EINVAL);
}
-err:
- if (path1 != NULL)
+err: if (path1 != NULL)
__os_free(NULL, path1);
if (path2 != NULL)
__os_free(NULL, path2);
return (ret);
}
-int backup_open(dbenv, dbname, target, handle)
+static int
+backup_open(dbenv, dbname, target, handle)
DB_ENV *dbenv;
const char *dbname;
const char *target;
@@ -817,7 +937,8 @@ int backup_open(dbenv, dbname, target, handle)
return (ret);
}
-int backup_write(dbenv, gigs, offset, size, buf, handle)
+static int
+backup_write(dbenv, gigs, offset, size, buf, handle)
DB_ENV *dbenv;
u_int32_t gigs, offset, size;
u_int8_t *buf;
@@ -841,7 +962,8 @@ int backup_write(dbenv, gigs, offset, size, buf, handle)
return (ret);
}
-int backup_close(dbenv, dbname, handle)
+static int
+backup_close(dbenv, dbname, handle)
DB_ENV *dbenv;
const char *dbname;
void *handle;
@@ -859,34 +981,37 @@ int backup_close(dbenv, dbname, handle)
}
static int
-make_dbconfig(envconf)
- ENV_CONF_T envconf;
+make_dbconfig(content)
+ const char * content;
{
- const char *path = "TESTDIR/DB_CONFIG";
- char str[1024];
FILE *fp;
+ char *str;
+ int ret, size;
- if (envconf >= PARTITION_DB && envconf <= SET_LOG_DIR)
- fp = fopen(path, "w");
- else
- return (0);
+ ret = 0;
- switch(envconf) {
- case PARTITION_DB:
- case MULTI_DATA_DIR:
- snprintf(str, 1024, "%s", "set_data_dir DATA1");
- break;
- case SET_LOG_DIR:
- snprintf(str, 1024, "%s", "set_lg_dir LOG");
- break;
- default:
+ if (content == NULL)
+ return (0);
+ if ((fp = fopen("TESTDIR/DB_CONFIG", "w")) == NULL)
return (EINVAL);
+
+ if ((ret = __os_calloc(NULL, 1024, 1, &str)) != 0)
+ goto err;
+ size = snprintf(str, 1024, "%s", content);
+ if (size < 0 || size >= 1024) {
+ ret = EINVAL;
+ goto err;
}
- fputs(str, fp);
- fclose(fp);
+ if (fputs(str, fp) == EOF)
+ ret = EXIT_FAILURE;
- return (0);
+err: if (fclose(fp) == EOF)
+ ret = EXIT_FAILURE;
+ if (str != NULL)
+ __os_free(NULL, str);
+
+ return (ret);
}
static int
@@ -911,29 +1036,29 @@ cmp_files(name1, name2)
goto err;
/* Open the input files. */
- if ( (ret = __os_open(NULL, name1, 0, DB_OSO_RDONLY, 0, &fhp1)) != 0 ||
- (t_ret = __os_open(NULL, name2, 0, DB_OSO_RDONLY, 0, &fhp2)) != 0) {
- if (ret == 0)
- ret = t_ret;
- goto err;
+ if ((ret = __os_open(NULL, name1, 0, DB_OSO_RDONLY, 0, &fhp1)) != 0 ||
+ (t_ret = __os_open(NULL, name2, 0,
+ DB_OSO_RDONLY, 0, &fhp2)) != 0) {
+ if (ret == 0)
+ ret = t_ret;
+ goto err;
}
/* Read and compare the file content. */
while ((ret = __os_read(NULL, fhp1, buf1, MEGABYTE, &nr1)) == 0 &&
nr1 > 0 && (ret = __os_read(NULL, fhp2,
buf2, MEGABYTE, &nr2)) == 0 && nr2 > 0) {
- if (nr1 != nr2) {
- ret = EINVAL;
- break;
- }
- if ((ret = memcmp(buf1, buf2, nr1)) != 0)
- break;
+ if (nr1 != nr2) {
+ ret = EXIT_FAILURE;
+ break;
+ }
+ if ((ret = memcmp(buf1, buf2, nr1)) != 0)
+ break;
}
if(ret == 0 && nr1 > 0 && nr2 > 0 && nr1 != nr2)
- ret = EINVAL;
+ ret = EXIT_FAILURE;
-err:
- if (buf1 != NULL)
+err: if (buf1 != NULL)
__os_free(NULL, buf1);
if (buf2 != NULL)
__os_free(NULL, buf2);
@@ -943,3 +1068,77 @@ err:
ret = t_ret;
return (ret);
}
+
+static int
+test_backup_onlydbfile(ct, dbtype, has_callback)
+ CuTest *ct;
+ DBTYPE dbtype;
+ int has_callback;
+{
+ DB_ENV *dbenv;
+ DB *dbp;
+ struct handlers *info;
+ char **names;
+ int (*closep)(DB_ENV *, const char *, void *);
+ int (*openp)(DB_ENV *, const char *, const char *, void **);
+ int (*writep)(DB_ENV *,u_int32_t,
+ u_int32_t, u_int32_t, u_int8_t *, void *);
+ int cnt, i, t_cnt;
+ u_int32_t flag;
+
+ info = ct->context;
+ flag = DB_EXCL;
+ closep = NULL;
+ openp = NULL;
+ writep = NULL;
+
+ /* Step 1: set up directories. */
+ CuAssert(ct, "setup_dir", setup_dir(0, NULL) == 0);
+
+ /* Step 2: open db handle. */
+ CuAssert(ct,"open_dbp", open_dbp(&dbenv, &dbp,
+ dbtype, 0, NULL, NULL, NULL, 0, NULL) == 0);
+ info->dbenvp = dbenv;
+ info->dbp = dbp;
+
+ /* Step 3: store records into db. */
+ CuAssert(ct, "store_records", store_records(dbp, 10) == 0);
+ CuAssert(ct, "DB->sync", dbp->sync(dbp, 0) == 0);
+
+ /* Step 4: backup only the db file. */
+ CuAssert(ct, "backup_db",
+ backup_db(ct, dbenv, BACKUP_DB, flag, has_callback) == 0);
+
+ /*
+ * Step 5: check backup result.
+ * 5a: verify db file is in BACKUP_DIR.
+ */
+ CuAssert(ct, "verify_db_log",
+ verify_db_log(dbtype, 0, 0, NULL, NULL) == 0);
+
+ /* 5b: verify no other files are in BACKUP_DIR. */
+ CuAssert(ct, "__os_dirlist",
+ __os_dirlist(NULL, BACKUP_DIR, 0, &names, &cnt) == 0);
+ if (dbtype != DB_QUEUE)
+ CuAssert(ct, "too many files in backupdir", cnt == 1);
+ else {
+ t_cnt = cnt;
+ for (i = 0; i < t_cnt; i++) {
+ if (strncmp(names[i], "__dbq.", 6) == 0)
+ cnt--;
+ }
+ CuAssert(ct, "too many files in backupdir", cnt == 1);
+ }
+
+ /* Step 6: verify the backup callback. */
+ CuAssert(ct, "DB_ENV->get_backup_callbacks",
+ dbenv->get_backup_callbacks(dbenv,
+ &openp, &writep, &closep) == (has_callback != 0 ? 0 : EINVAL));
+ if (has_callback != 0) {
+ CuAssertTrue(ct, openp == backup_open);
+ CuAssertTrue(ct, writep == backup_write);
+ CuAssertTrue(ct, closep == backup_close);
+ }
+
+ return (0);
+}
diff --git a/test/c/suites/TestDbTuner.c b/test/c/suites/TestDbTuner.c
index 08a16bb3..e59837fe 100644
--- a/test/c/suites/TestDbTuner.c
+++ b/test/c/suites/TestDbTuner.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2010, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*/
@@ -33,7 +33,7 @@ int open_db(DB_ENV **, DB **, char *, char *, u_int32_t, int);
int run_test(CuTest *, u_int32_t, int, int, int, int, int);
int store_db(DB *, int, int, int, int);
-const char *progname = "TestDbTuner";
+const char *progname_dbtuner = "TestDbTuner";
int total_cases, success_cases;
int TestDbTuner(CuTest *ct) {
@@ -201,7 +201,7 @@ open_db(dbenvp, dbpp, dbname, home, pgsize, duptype)
*dbenvp = dbenv;
dbenv->set_errfile(dbenv, stderr);
- dbenv->set_errpfx(dbenv, progname);
+ dbenv->set_errpfx(dbenv, progname_dbtuner);
if ((ret =
dbenv->set_cachesize(dbenv, (u_int32_t)0,
diff --git a/test/c/suites/TestEncryption.c b/test/c/suites/TestEncryption.c
index d0176306..60810034 100644
--- a/test/c/suites/TestEncryption.c
+++ b/test/c/suites/TestEncryption.c
@@ -1,7 +1,7 @@
/*
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2011, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*
diff --git a/test/c/suites/TestEnvConfig.c b/test/c/suites/TestEnvConfig.c
index f19b7b48..03467dc2 100644
--- a/test/c/suites/TestEnvConfig.c
+++ b/test/c/suites/TestEnvConfig.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2002, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2015 Oracle and/or its affiliates. All rights reserved.
*/
#include <sys/types.h>
@@ -14,6 +14,11 @@
#include "CuTest.h"
#include "test_util.h"
+struct context {
+ FILE *fp;
+ char *path;
+};
+
#define ENV { \
if (dbenv != NULL) \
CuAssertTrue(ct, dbenv->close(dbenv, 0) == 0); \
@@ -30,11 +35,30 @@ int TestEnvConfigSuiteTeardown(CuSuite *ct) {
}
int TestEnvConfigTestSetup(CuTest *ct) {
+ struct context *info;
+
+ if ((info = calloc(1, sizeof(*info))) == NULL)
+ return (ENOMEM);
+ ct->context = info;
setup_envdir(TEST_ENV, 1);
return (0);
}
int TestEnvConfigTestTeardown(CuTest *ct) {
+ struct context *info;
+ FILE *fp;
+ char *path;
+
+ info = ct->context;
+ assert(info != NULL);
+ fp = info->fp;
+ path = info->path;
+ if (fp != NULL)
+ fclose(fp);
+ if (path != NULL)
+ free(path);
+ free(info);
+ ct->context = NULL;
teardown_envdir(TEST_ENV);
return (0);
}
@@ -61,9 +85,20 @@ int TestSetTxMax(CuTest *ct) {
int TestSetLogMax(CuTest *ct) {
DB_ENV *dbenv;
+ struct context *info;
+ FILE *msgfile;
+ char *path;
u_int32_t v;
dbenv = NULL;
+ if ((path = calloc(100, sizeof(char))) == NULL)
+ return (ENOMEM);
+ snprintf(path, 100, "%s%c%s", TEST_ENV, PATH_SEPARATOR[0], "msgfile");
+ if ((msgfile = fopen(path, "w")) == NULL)
+ return (EINVAL);
+ info = ct->context;
+ info->fp = msgfile;
+ info->path = path;
/* lg_max: reset at run-time. */
ENV
CuAssertTrue(ct, dbenv->set_lg_max(dbenv, 37 * 1024 * 1024) == 0);
@@ -72,9 +107,18 @@ int TestSetLogMax(CuTest *ct) {
CuAssertTrue(ct, dbenv->get_lg_max(dbenv, &v) == 0);
CuAssertTrue(ct, v == 37 * 1024 * 1024);
ENV
+ /* New log maximum size is ignored when joining the environment. */
CuAssertTrue(ct, dbenv->set_lg_max(dbenv, 63 * 1024 * 1024) == 0);
+ /* Redirect the error message to suppress the warning. */
+ dbenv->set_msgfile(dbenv, msgfile);
CuAssertTrue(ct, dbenv->open(dbenv, TEST_ENV, DB_JOINENV, 0666) == 0);
CuAssertTrue(ct, dbenv->get_lg_max(dbenv, &v) == 0);
+ CuAssertTrue(ct, v == 37 * 1024 * 1024);
+ /* Direct the error message back to the standard output. */
+ dbenv->set_msgfile(dbenv, NULL);
+ /* Re-config the log maximum size after opening the environment. */
+ CuAssertTrue(ct, dbenv->set_lg_max(dbenv, 63 * 1024 * 1024) == 0);
+ CuAssertTrue(ct, dbenv->get_lg_max(dbenv, &v) == 0);
CuAssertTrue(ct, v == 63 * 1024 * 1024);
return (0);
}
@@ -234,9 +278,20 @@ int TestSetLockMaxObjects(CuTest *ct) {
int TestSetLockTimeout(CuTest *ct) {
DB_ENV *dbenv;
+ struct context *info;
+ FILE *msgfile;
+ char *path;
db_timeout_t timeout;
dbenv = NULL;
+ if ((path = calloc(100, sizeof(char))) == NULL)
+ return (ENOMEM);
+ snprintf(path, 100, "%s%c%s", TEST_ENV, PATH_SEPARATOR[0], "msgfile");
+ if ((msgfile = fopen(path, "w")) == NULL)
+ return (EINVAL);
+ info = ct->context;
+ info->fp = msgfile;
+ info->path = path;
/* lock timeout: reset at run-time. */
ENV
CuAssertTrue(ct,
@@ -247,20 +302,42 @@ int TestSetLockTimeout(CuTest *ct) {
dbenv->get_timeout(dbenv, &timeout, DB_SET_LOCK_TIMEOUT) == 0);
CuAssertTrue(ct, timeout == 37);
ENV
+ /* New lock timeout is ignored when joining the environment. */
CuAssertTrue(ct,
dbenv->set_timeout(dbenv, 63, DB_SET_LOCK_TIMEOUT) == 0);
+ /* Redirect the error message to suppress the warning. */
+ dbenv->set_msgfile(dbenv, msgfile);
CuAssertTrue(ct, dbenv->open(dbenv, TEST_ENV, DB_JOINENV, 0666) == 0);
CuAssertTrue(ct,
dbenv->get_timeout(dbenv, &timeout, DB_SET_LOCK_TIMEOUT) == 0);
+ CuAssertTrue(ct, timeout == 37);
+ /* Direct the error message back to the standard output. */
+ dbenv->set_msgfile(dbenv, NULL);
+ /* Re-config the lock timeout after opening the environment. */
+ CuAssertTrue(ct,
+ dbenv->set_timeout(dbenv, 63, DB_SET_LOCK_TIMEOUT) == 0);
+ CuAssertTrue(ct,
+ dbenv->get_timeout(dbenv, &timeout, DB_SET_LOCK_TIMEOUT) == 0);
CuAssertTrue(ct, timeout == 63);
return (0);
}
int TestSetTransactionTimeout(CuTest *ct) {
DB_ENV *dbenv;
+ struct context *info;
+ FILE *msgfile;
+ char *path;
db_timeout_t timeout;
dbenv = NULL;
+ if ((path = calloc(100, sizeof(char))) == NULL)
+ return (ENOMEM);
+ snprintf(path, 100, "%s%c%s", TEST_ENV, PATH_SEPARATOR[0], "msgfile");
+ if ((msgfile = fopen(path, "w")) == NULL)
+ return (EINVAL);
+ info = ct->context;
+ info->fp = msgfile;
+ info->path = path;
/* txn timeout: reset at run-time. */
ENV
CuAssertTrue(ct,
@@ -271,11 +348,22 @@ int TestSetTransactionTimeout(CuTest *ct) {
dbenv->get_timeout(dbenv, &timeout, DB_SET_TXN_TIMEOUT) == 0);
CuAssertTrue(ct, timeout == 37);
ENV
+ /* New transaction timeout is ignored when joining the environment. */
CuAssertTrue(ct,
dbenv->set_timeout(dbenv, 63, DB_SET_TXN_TIMEOUT) == 0);
+ /* Redirect the error message to suppress the warning. */
+ dbenv->set_msgfile(dbenv, msgfile);
CuAssertTrue(ct, dbenv->open(dbenv, TEST_ENV, DB_JOINENV, 0666) == 0);
CuAssertTrue(ct,
dbenv->get_timeout(dbenv, &timeout, DB_SET_TXN_TIMEOUT) == 0);
+ CuAssertTrue(ct, timeout == 37);
+ /* Direct the error message back to the standard output. */
+ dbenv->set_msgfile(dbenv, NULL);
+ /* Re-config the transaction timeout after opening the environment. */
+ CuAssertTrue(ct,
+ dbenv->set_timeout(dbenv, 63, DB_SET_TXN_TIMEOUT) == 0);
+ CuAssertTrue(ct,
+ dbenv->get_timeout(dbenv, &timeout, DB_SET_TXN_TIMEOUT) == 0);
CuAssertTrue(ct, timeout == 63);
return (0);
}
diff --git a/test/c/suites/TestEnvMethod.c b/test/c/suites/TestEnvMethod.c
index 7da0f785..febdb272 100644
--- a/test/c/suites/TestEnvMethod.c
+++ b/test/c/suites/TestEnvMethod.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2010, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*/
diff --git a/test/c/suites/TestKeyExistErrorReturn.c b/test/c/suites/TestKeyExistErrorReturn.c
index 75078bc2..9c870867 100644
--- a/test/c/suites/TestKeyExistErrorReturn.c
+++ b/test/c/suites/TestKeyExistErrorReturn.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2010, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*/
diff --git a/test/c/suites/TestMutexAlignment.c b/test/c/suites/TestMutexAlignment.c
new file mode 100644
index 00000000..285c59e8
--- /dev/null
+++ b/test/c/suites/TestMutexAlignment.c
@@ -0,0 +1,70 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2012, 2015 Oracle and/or its affiliates. All rights reserved.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "db.h"
+#include "CuTest.h"
+#include "test_util.h"
+
+int TestMutexAlignment(CuTest *ct) {
+ int procs, threads, alignment, lockloop;
+ int max_procs, max_threads;
+ char *bin;
+ char cmdstr[1000], cmd[1000];
+
+ /* Step 1: Check required binary file existence, set args */
+#ifdef DB_WIN32
+#ifdef _WIN64
+#ifdef DEBUG
+ bin = "x64\\Debug\\test_mutex.exe";
+#else
+ bin = "x64\\Release\\test_mutex.exe";
+#endif
+#else
+#ifdef DEBUG
+ bin = "Win32\\Debug\\test_mutex.exe";
+#else
+ bin = "Win32\\Release\\test_mutex.exe";
+#endif
+#endif
+ sprintf(cmdstr, "%s -p %%d -t %%d -a %%d -n %%d >/nul 2>&1", bin);
+ lockloop = 100;
+ max_procs = 2;
+ max_threads = 2;
+#else
+ bin = "./test_mutex";
+ sprintf(cmdstr, "%s -p %%d -t %%d -a %%d -n %%d >/dev/null 2>&1", bin);
+ lockloop = 2000;
+ max_procs = 4;
+ max_threads = 4;
+#endif
+
+ if (__os_exists(NULL, bin, NULL) != 0) {
+ printf("Error! Can not find %s. It need to be built in order to\
+ run this test.\n", bin);
+ CuAssert(ct, bin, 0);
+ return (EXIT_FAILURE);
+ }
+
+ /* Step 2: Test with different combinations. */
+ for (procs = 1; procs <= max_procs; procs *= 2) {
+ for (threads= 1; threads <= max_threads; threads *= 2) {
+ if (procs ==1 && threads == 1)
+ continue;
+ for (alignment = 32; alignment <= 128; alignment *= 2) {
+ sprintf(cmd, cmdstr, procs, threads, alignment,
+ lockloop);
+ printf("%s\n", cmd);
+ CuAssert(ct, cmd, system(cmd) == 0);
+ }
+ }
+ }
+ return (EXIT_SUCCESS);
+}
diff --git a/test/c/suites/TestPartial.c b/test/c/suites/TestPartial.c
index cacc6d51..d87ce12b 100644
--- a/test/c/suites/TestPartial.c
+++ b/test/c/suites/TestPartial.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2011, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*/
diff --git a/test/c/suites/TestPartition.c b/test/c/suites/TestPartition.c
new file mode 100644
index 00000000..7c460a2f
--- /dev/null
+++ b/test/c/suites/TestPartition.c
@@ -0,0 +1,508 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2012, 2015 Oracle and/or its affiliates. All rights reserved.
+ *
+ * $Id$
+ */
+
+/*
+ * A C Unit test for DB->set_partition API. [#21373]
+ *
+ * Test cases:
+ * One of the key DBTs has no data;
+ * Two of the key DBTs have no data;
+ * Two key DBTs have the same non-NULL data;
+ * The key DBTs are not sorted;
+ * The partition number is not equal to key array size plus 1;
+ * Both partition key and callback are set;
+ * Neither partition key nor callback are set.
+ *
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db.h"
+#include "CuTest.h"
+#include "test_util.h"
+
+static int close_db(DB_ENV *, DB *, CuTest *);
+static int create_db(DB_ENV **, DB **dbpp, int bigcache, CuTest *);
+static u_int32_t partitionCallback(DB *, DBT *);
+static int put_data(DB *);
+
+static FILE *errfp;
+static char *content;
+static u_int32_t nparts;
+
+int TestPartitionSuiteSetup(CuSuite *suite) {
+ errfp = NULL;
+ content = "abcdefghijklmnopqrstuvwxyz";
+ nparts = 5;
+ return (0);
+}
+
+int TestPartitionSuiteTeardown(CuSuite *suite) {
+ return (0);
+}
+
+int TestPartitionTestSetup(CuTest *ct) {
+ if (errfp != NULL)
+ fclose(errfp);
+ setup_envdir(TEST_ENV, 1);
+ errfp = fopen("TESTDIR/errfile", "w");
+ return (0);
+}
+
+int TestPartitionTestTeardown(CuTest *ct) {
+ if (errfp != NULL) {
+ fclose(errfp);
+ errfp = NULL;
+ }
+ return (0);
+}
+
+int TestPartOneKeyNoData(CuTest *ct) {
+ DB_ENV *dbenv;
+ DB *dbp;
+ /* Allocate the memory from stack. */
+ DBT keys[4];
+ u_int32_t i;
+
+ dbenv = NULL;
+ dbp = NULL;
+ nparts = 5;
+
+ /* Do not assign any data to the first DBT. */
+ memset(&keys[0], 0, sizeof(DBT));
+ for (i = 1 ; i < (nparts - 1); i++) {
+ memset(&keys[i], 0, sizeof(DBT));
+ keys[i].data = &content[(i + 1) * (strlen(content) / nparts)];
+ keys[i].size = sizeof(char);
+ }
+
+ /* Do not set any database flags. */
+ CuAssertTrue(ct, create_db(&dbenv, &dbp, 0, ct) == 0);
+ /*
+ * Verify that before the database is opened, DB->set_partition can
+ * be called multiple times regardless of its return code.
+ */
+ keys[0].flags = DB_DBT_MALLOC;
+ CuAssertTrue(ct, dbp->set_partition(dbp, nparts, keys, NULL) != 0);
+ keys[0].flags = 0;
+ CuAssertTrue(ct, dbp->set_partition(dbp, nparts, keys, NULL) == 0);
+ CuAssertTrue(ct, dbp->set_partition(dbp, nparts, keys, NULL) == 0);
+ CuAssertTrue(ct, dbp->open(dbp, NULL,
+ "test.db", NULL, DB_BTREE, DB_CREATE, 0644) != 0);
+ CuAssertTrue(ct, close_db(dbenv, dbp, ct) == 0);
+ fclose(errfp);
+ errfp = NULL;
+
+ /* Set DB_DUPSORT flags. */
+ setup_envdir(TEST_ENV, 1);
+ errfp = fopen("TESTDIR/errfile", "w");
+ CuAssertTrue(ct, create_db(&dbenv, &dbp, 0, ct) == 0);
+ CuAssertTrue(ct, dbp->set_partition(dbp, nparts, keys, NULL) == 0);
+ CuAssertTrue(ct, dbp->set_flags(dbp, DB_DUPSORT) == 0);
+ CuAssertTrue(ct, dbp->open(dbp, NULL,
+ "test.db", NULL, DB_BTREE, DB_CREATE, 0644) != 0);
+ CuAssertTrue(ct, close_db(dbenv, dbp, ct) == 0);
+ fclose(errfp);
+ errfp = NULL;
+
+ /* Set DB_DUP flags. */
+ setup_envdir(TEST_ENV, 1);
+ CuAssertTrue(ct, create_db(&dbenv, &dbp, 0, ct) == 0);
+ CuAssertTrue(ct, dbp->set_partition(dbp, nparts, keys, NULL) == 0);
+ CuAssertTrue(ct, dbp->set_flags(dbp, DB_DUP) == 0);
+ CuAssertTrue(ct, dbp->open(dbp, NULL,
+ "test.db", NULL, DB_BTREE, DB_CREATE, 0644) == 0);
+ CuAssertTrue(ct, put_data(dbp) == 0);
+ CuAssertTrue(ct, close_db(dbenv, dbp, ct) == 0);
+ return (0);
+}
+
+int TestPartTwoKeyNoData(CuTest *ct) {
+ DB_ENV *dbenv;
+ DB *dbp;
+ DBT *keys;
+ u_int32_t i;
+
+ dbenv = NULL;
+ dbp = NULL;
+ keys = NULL;
+ nparts = 5;
+
+ CuAssertTrue(ct, (keys = malloc((nparts - 1) * sizeof(DBT))) != NULL);
+ memset(keys, 0, (nparts - 1) * sizeof(DBT));
+ /* Do not assign any data to the first 2 DBTs. */
+ keys[0].size = keys[1].size = 0;
+ for (i = 2 ; i < (nparts - 1); i++) {
+ keys[i].data = &content[(i + 1) * (strlen(content) / nparts)];
+ keys[i].size = sizeof(char);
+ }
+
+ /* Do not set any database flags. */
+ CuAssertTrue(ct, create_db(&dbenv, &dbp, 0, ct) == 0);
+ CuAssertTrue(ct, dbp->set_partition(dbp, nparts, keys, NULL) == 0);
+ CuAssertTrue(ct, dbp->open(dbp, NULL,
+ "test.db", NULL, DB_BTREE, DB_CREATE, 0644) != 0);
+ CuAssertTrue(ct, close_db(dbenv, dbp, ct) == 0);
+ fclose(errfp);
+ errfp = NULL;
+
+ /* Set DB_DUPSORT flags. */
+ setup_envdir(TEST_ENV, 1);
+ errfp = fopen("TESTDIR/errfile", "w");
+ CuAssertTrue(ct, create_db(&dbenv, &dbp, 0, ct) == 0);
+ CuAssertTrue(ct, dbp->set_partition(dbp, nparts, keys, NULL) == 0);
+ CuAssertTrue(ct, dbp->set_flags(dbp, DB_DUPSORT) == 0);
+ CuAssertTrue(ct, dbp->open(dbp, NULL,
+ "test.db", NULL, DB_BTREE, DB_CREATE, 0644) != 0);
+ CuAssertTrue(ct, close_db(dbenv, dbp, ct) == 0);
+ fclose(errfp);
+ errfp = NULL;
+
+ /* Set DB_DUP flags. */
+ setup_envdir(TEST_ENV, 1);
+ CuAssertTrue(ct, create_db(&dbenv, &dbp, 0, ct) == 0);
+ CuAssertTrue(ct, dbp->set_partition(dbp, nparts, keys, NULL) == 0);
+ CuAssertTrue(ct, dbp->set_flags(dbp, DB_DUP) == 0);
+ CuAssertTrue(ct, dbp->open(dbp, NULL,
+ "test.db", NULL, DB_BTREE, DB_CREATE, 0644) == 0);
+ CuAssertTrue(ct, put_data(dbp) == 0);
+ CuAssertTrue(ct, close_db(dbenv, dbp, ct) == 0);
+ free(keys);
+ return (0);
+}
+
+int TestPartDuplicatedKey(CuTest *ct) {
+ DB_ENV *dbenv;
+ DB *dbp;
+ DBT *keys;
+ u_int32_t i;
+
+ dbenv = NULL;
+ dbp = NULL;
+ keys = NULL;
+ nparts = 5;
+
+ CuAssertTrue(ct, (keys = malloc((nparts - 1) * sizeof(DBT))) != NULL);
+ memset(keys, 0, (nparts - 1) * sizeof(DBT));
+ /* Assign the same data to the first 2 DBTs. */
+ for (i = 0 ; i < (nparts - 1); i++) {
+ if (i < 2)
+ keys[i].data = &content[strlen(content) / nparts];
+ else
+ keys[i].data = &content[(i + 1) *
+ (strlen(content) / nparts)];
+ keys[i].size = sizeof(char);
+ }
+
+ /* Do not set any database flags. */
+ CuAssertTrue(ct, create_db(&dbenv, &dbp, 0, ct) == 0);
+ CuAssertTrue(ct, dbp->set_partition(dbp, nparts, keys, NULL) == 0);
+ CuAssertTrue(ct, dbp->open(dbp, NULL,
+ "test.db", NULL, DB_BTREE, DB_CREATE, 0644) != 0);
+ CuAssertTrue(ct, close_db(dbenv, dbp, ct) == 0);
+ fclose(errfp);
+ errfp = NULL;
+
+ /* Set DB_DUPSORT flags. */
+ setup_envdir(TEST_ENV, 1);
+ errfp = fopen("TESTDIR/errfile", "w");
+ CuAssertTrue(ct, create_db(&dbenv, &dbp, 0, ct) == 0);
+ CuAssertTrue(ct, dbp->set_partition(dbp, nparts, keys, NULL) == 0);
+ CuAssertTrue(ct, dbp->set_flags(dbp, DB_DUPSORT) == 0);
+ CuAssertTrue(ct, dbp->open(dbp, NULL,
+ "test.db", NULL, DB_BTREE, DB_CREATE, 0644) != 0);
+ CuAssertTrue(ct, close_db(dbenv, dbp, ct) == 0);
+ fclose(errfp);
+ errfp = NULL;
+
+ /* Set DB_DUP flags. */
+ setup_envdir(TEST_ENV, 1);
+ CuAssertTrue(ct, create_db(&dbenv, &dbp, 0, ct) == 0);
+ CuAssertTrue(ct, dbp->set_partition(dbp, nparts, keys, NULL) == 0);
+ CuAssertTrue(ct, dbp->set_flags(dbp, DB_DUP) == 0);
+ CuAssertTrue(ct, dbp->open(dbp, NULL,
+ "test.db", NULL, DB_BTREE, DB_CREATE, 0644) == 0);
+ CuAssertTrue(ct, put_data(dbp) == 0);
+ CuAssertTrue(ct, close_db(dbenv, dbp, ct) == 0);
+ free(keys);
+ return (0);
+}
+
+int TestPartUnsortedKey(CuTest *ct) {
+ DB_ENV *dbenv;
+ DB *dbp;
+ DBT *keys;
+ u_int32_t i, indx;
+
+ dbenv = NULL;
+ dbp = NULL;
+ keys = NULL;
+ nparts = 6;
+
+ CuAssertTrue(ct, (keys = malloc((nparts - 1) * sizeof(DBT))) != NULL);
+ memset(keys, 0, (nparts - 1) * sizeof(DBT));
+ /* Assign unsorted keys to the array. */
+ for (i = 0, indx = 0; i < (nparts - 1); i++) {
+ if (i == (nparts - 2) && i % 2 == 0)
+ indx = i;
+ else if (i % 2 != 0)
+ indx = i - 1;
+ else
+ indx = i + 1;
+ keys[i].data =
+ &content[(indx + 1) * (strlen(content) / nparts)];
+ keys[i].size = sizeof(char);
+ }
+
+ CuAssertTrue(ct, create_db(&dbenv, &dbp, 0, ct) == 0);
+ CuAssertTrue(ct,
+ dbp->set_partition(dbp, nparts - 1, &keys[1], NULL) == 0);
+ CuAssertTrue(ct, dbp->open(dbp, NULL,
+ "test.db", NULL, DB_BTREE, DB_CREATE, 0644) == 0);
+ CuAssertTrue(ct, put_data(dbp) == 0);
+ CuAssertTrue(ct, dbp->close(dbp, 0) == 0);
+
+ /*
+ * Reconfig with a different partition number and
+ * re-open the database.
+ */
+ CuAssertTrue(ct, db_create(&dbp, dbenv, 0) == 0);
+ CuAssertTrue(ct, dbp->set_partition(dbp, nparts, keys, NULL) == 0);
+ CuAssertTrue(ct, dbp->open(dbp, NULL,
+ "test.db", NULL, DB_BTREE, 0, 0644) != 0);
+ CuAssertTrue(ct, dbp->close(dbp, 0) == 0);
+
+ /*
+ * Reconfig with a different set of partition keys and
+ * re-open the database.
+ */
+ CuAssertTrue(ct, db_create(&dbp, dbenv, 0) == 0);
+ CuAssertTrue(ct, dbp->set_partition(dbp, nparts - 1, keys, NULL) == 0);
+ CuAssertTrue(ct, dbp->open(dbp, NULL,
+ "test.db", NULL, DB_BTREE, 0, 0644) != 0);
+ CuAssertTrue(ct, close_db(dbenv, dbp, ct) == 0);
+ free(keys);
+ return (0);
+}
+
+int TestPartNumber(CuTest *ct) {
+ DB_ENV *dbenv;
+ DB *dbp;
+ DBT *keys;
+ u_int32_t i;
+
+ dbenv = NULL;
+ dbp = NULL;
+ keys = NULL;
+ nparts = 1000000;
+
+ CuAssertTrue(ct, (keys = malloc((nparts - 1) * sizeof(DBT))) != NULL);
+ memset(keys, 0, (nparts - 1) * sizeof(DBT));
+ /* Assign data to the keys. */
+ for (i = 0 ; i < (nparts - 1); i++) {
+ CuAssertTrue(ct,
+ (keys[i].data = malloc(sizeof(u_int32_t))) != NULL);
+ memcpy(keys[i].data, &i, sizeof(u_int32_t));
+ keys[i].size = sizeof(u_int32_t);
+ }
+
+ /* Partition number is less than 2. */
+ CuAssertTrue(ct, create_db(&dbenv, &dbp, 1, ct) == 0);
+ CuAssertTrue(ct, dbp->set_partition(dbp, 1, keys, NULL) != 0);
+
+ /* Partition number is bigger than the limit 1000000. */
+ CuAssertTrue(ct,
+ dbp->set_partition(dbp, nparts + 1, keys, NULL) == EINVAL);
+
+ /* Partition number is equal to the limit 1000000. */
+ CuAssertTrue(ct, dbp->set_partition(dbp, nparts, keys, NULL) == 0);
+
+ /* Partition keys do not fix into a single database page. */
+ CuAssertTrue(ct, dbp->set_pagesize(dbp, 512) == 0);
+ CuAssertTrue(ct, dbp->set_partition(dbp, 800, keys, NULL) == 0);
+ CuAssertTrue(ct, dbp->open(dbp, NULL,
+ "test.db", NULL, DB_BTREE, DB_CREATE, 0644) == 0);
+ CuAssertTrue(ct, put_data(dbp) == 0);
+ CuAssertTrue(ct, close_db(dbenv, dbp, ct) == 0);
+
+ for (i = 0 ; i < (nparts - 1); i++)
+ free(keys[i].data);
+ free(keys);
+ return (0);
+}
+
+int TestPartKeyCallBothSet(CuTest *ct) {
+ DB_ENV *dbenv;
+ DB *dbp;
+ DBT *keys;
+ u_int32_t i;
+
+ dbenv = NULL;
+ dbp = NULL;
+ keys = NULL;
+ nparts = 5;
+
+ CuAssertTrue(ct, (keys = malloc((nparts - 1) * sizeof(DBT))) != NULL);
+ memset(keys, 0, (nparts - 1) * sizeof(DBT));
+ /* Do not assign any data to the first DBT. */
+ for (i = 0 ; i < (nparts - 1); i++) {
+ keys[i].data = &content[(i + 1) * (strlen(content) / nparts)];
+ keys[i].size = sizeof(char);
+ }
+
+ /* Set both partition key and callback, expect it fails. */
+ CuAssertTrue(ct, create_db(&dbenv, &dbp, 0, ct) == 0);
+ CuAssertTrue(ct,
+ dbp->set_partition(dbp, nparts, keys, partitionCallback) != 0);
+
+ /* Set partition by key and open the database. */
+ CuAssertTrue(ct, dbp->set_partition(dbp, nparts, keys, NULL) == 0);
+ CuAssertTrue(ct, dbp->open(dbp, NULL,
+ "test.db", NULL, DB_BTREE, DB_CREATE, 0644) == 0);
+ CuAssertTrue(ct, put_data(dbp) == 0);
+ CuAssertTrue(ct, dbp->close(dbp, 0) == 0);
+
+ /* Reconfig the partition with callback, expect it fails. */
+ CuAssertTrue(ct, db_create(&dbp, dbenv, 0) == 0);
+ CuAssertTrue(ct,
+ dbp->set_partition(dbp, nparts, NULL, partitionCallback) == 0);
+ CuAssertTrue(ct, dbp->open(dbp, NULL,
+ "test.db", NULL, DB_BTREE, 0, 0644) != 0);
+ CuAssertTrue(ct, close_db(dbenv, dbp, ct) == 0);
+ fclose(errfp);
+ errfp = NULL;
+
+ /* Set partition by callback and open the database. */
+ setup_envdir(TEST_ENV, 1);
+ errfp = fopen("TESTDIR/errfile", "w");
+ CuAssertTrue(ct, create_db(&dbenv, &dbp, 0, ct) == 0);
+ CuAssertTrue(ct,
+ dbp->set_partition(dbp, nparts, NULL, partitionCallback) == 0);
+ CuAssertTrue(ct, dbp->open(dbp, NULL,
+ "test.db", NULL, DB_BTREE, DB_CREATE, 0644) == 0);
+ CuAssertTrue(ct, put_data(dbp) == 0);
+ CuAssertTrue(ct, dbp->close(dbp, 0) == 0);
+
+ /* Reconfig the partition with key, expect it fails. */
+ CuAssertTrue(ct, db_create(&dbp, dbenv, 0) == 0);
+ CuAssertTrue(ct, dbp->set_partition(dbp, nparts, keys, NULL) == 0);
+ CuAssertTrue(ct, dbp->open(dbp, NULL,
+ "test.db", NULL, DB_BTREE, 0, 0644) != 0);
+ CuAssertTrue(ct, close_db(dbenv, dbp, ct) == 0);
+ free(keys);
+ return (0);
+}
+
+int TestPartKeyCallNeitherSet(CuTest *ct) {
+ DB_ENV *dbenv;
+ DB *dbp;
+
+ dbenv = NULL;
+ dbp = NULL;
+
+ CuAssertTrue(ct, create_db(&dbenv, &dbp, 0, ct) == 0);
+ CuAssertTrue(ct, dbp->set_partition(dbp, nparts, NULL, NULL) != 0);
+ CuAssertTrue(ct, close_db(dbenv, dbp, ct) == 0);
+
+ return (0);
+}
+
+static int
+create_db(dbenvp, dbpp, bigcache, ct)
+ DB_ENV **dbenvp;
+ DB **dbpp;
+ int bigcache;
+ CuTest *ct;
+{
+ DB_ENV *dbenv;
+ DB *dbp;
+
+ dbenv = NULL;
+ dbp = NULL;
+
+ CuAssertTrue(ct, db_env_create(&dbenv, 0) == 0);
+ *dbenvp = dbenv;
+ /* Big cache size is needed in some test case. */
+ if (bigcache != 0 )
+ CuAssertTrue(ct, dbenv->set_cachesize(dbenv,
+ 0, 128 * 1048576, 1) == 0);
+ CuAssertTrue(ct, dbenv->open(dbenv, TEST_ENV,
+ DB_CREATE | DB_INIT_LOCK |DB_INIT_LOG |
+ DB_INIT_MPOOL | DB_INIT_TXN, 0666) == 0);
+
+ CuAssertTrue(ct, db_create(&dbp, dbenv, 0) == 0);
+ *dbpp = dbp;
+ dbp->set_errfile(dbp, errfp != NULL ? errfp : stdout);
+ dbp->set_errpfx(dbp, "TestPartition");
+
+ return (0);
+}
+
+static int
+close_db(dbenv, dbp, ct)
+ DB_ENV *dbenv;
+ DB *dbp;
+ CuTest *ct;
+{
+ if (dbp != NULL)
+ CuAssertTrue(ct, dbp->close(dbp, 0) == 0);
+ if (dbenv != NULL)
+ CuAssertTrue(ct, dbenv->close(dbenv, 0) == 0);
+ return (0);
+}
+
+static u_int32_t
+partitionCallback(dbp, key)
+ DB *dbp;
+ DBT *key;
+{
+ char *a, *b;
+ u_int32_t i, len;
+
+ a = (char *)key->data;
+ b = NULL;
+ len = nparts % strlen(content);
+
+ for (i = 0; i < len; i++) {
+ b = &content[(i + 1) * (strlen(content) / len)];
+ if ((*a - *b) < 0)
+ break;
+ }
+
+ return (i);
+}
+
+static int
+put_data(dbp)
+ DB *dbp;
+{
+ DBT key, data;
+ u_int32_t i;
+ int ret;
+
+ memset(&key, 0, sizeof(DBT));
+ memset(&data, 0, sizeof(DBT));
+
+ for (i = 0; i < strlen(content); i++) {
+ key.data = &content[i];
+ key.size = sizeof(char);
+
+ data.data = &content[i];
+ data.size = sizeof(char);
+
+ if ((ret = dbp->put(dbp, NULL, &key, &data, 0)) != 0) {
+ dbp->err(dbp, ret, "DB->put");
+ return (ret);
+ }
+ }
+ return (ret);
+}
+
diff --git a/test/c/suites/TestPreOpenSetterAndGetter.c b/test/c/suites/TestPreOpenSetterAndGetter.c
new file mode 100644
index 00000000..2005307a
--- /dev/null
+++ b/test/c/suites/TestPreOpenSetterAndGetter.c
@@ -0,0 +1,1178 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2012, 2015 Oracle and/or its affiliates. All rights reserved.
+ *
+ * $Id$
+ */
+
+/*
+ * Test setting and getting the configuration before handle open [#21552]
+ *
+ * It tests all the settings on the following handles:
+ * 1. DB_ENV
+ * 2. DB
+ * 3. DB_MPOOLFILE
+ * 4. DB_SEQUENCE
+ * These handles have separate steps for 'create' and 'open', so that
+ * we can do pre-open configuration.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db.h"
+#include "CuTest.h"
+#include "test_util.h"
+
+/*
+ * Test functions like DB_ENV->set_lk_max_lockers and
+ * and DB_ENV->get_lk_max_lockers, among which the setter function accepts a
+ * number as the second argument while the getter function accepts a pointer
+ * to number.
+ */
+#define CHECK_1_DIGIT_VALUE(handle, setter, getter, type, v) do { \
+ type vs, vg; \
+ vs = (type)(v); \
+ CuAssert(ct, #handle"->"#setter, \
+ (handle)->setter((handle), vs) == 0); \
+ CuAssert(ct, #handle"->"#getter, \
+ (handle)->getter((handle), &vg) == 0); \
+ CuAssert(ct, #getter"=="#setter, vs == vg); \
+} while(0)
+
+/*
+ * Test all possible values for functions like DB_ENV->set_lk_detect and
+ * DB_ENV->get_lk_detect. The values for these functions are in a small set.
+ */
+#define CHECK_1_DIGIT_VALUES(handle, setter, getter, type, values) do { \
+ size_t cnt, i; \
+ cnt = sizeof(values) / sizeof(values[0]); \
+ for (i = 0; i < cnt; i++) { \
+ CHECK_1_DIGIT_VALUE(handle, setter, getter, type, \
+ values[i]); \
+ } \
+} while(0)
+
+/*
+ * Test functions like DB_ENV->set_backup_config and DB_ENV->get_backup_config,
+ * among which both getter and setter functions accept an option as the second
+ * argument, and for the third argument the setter accepts a number while
+ * getter accepts a pointer to number.
+ */
+#define CHECK_1_DIGIT_CONFIG_VALUE(handle, setter, getter, opt, type, v)\
+ do { \
+ type vs, vg; \
+ vs = (type)(v); \
+ CuAssert(ct, #handle"->"#setter, \
+ (handle)->setter((handle), (opt), vs) == 0); \
+ CuAssert(ct, #handle"->"#getter, \
+ (handle)->getter((handle), (opt), &vg) == 0); \
+ CuAssert(ct, #getter"=="#setter, vs == vg); \
+} while(0)
+
+/*
+ * Test all the options for functions satisfying CHECK_1_DIGIT_CONFIG_VALUE.
+ * The configuration value has no specific limit.
+ */
+#define CHECK_1_DIGIT_CONFIG_VALUES(handle, setter, getter, configs, type)\
+ do { \
+ size_t cnt, i; \
+ cnt = sizeof(configs) / sizeof(configs[0]); \
+ for (i = 0; i < cnt; i++) { \
+ CHECK_1_DIGIT_CONFIG_VALUE(handle, setter, getter, \
+ configs[i], type, rand()); \
+ } \
+} while(0)
+
+/*
+ * Test turning on/off all the options for functions like DB_ENV->set_verbose
+ * and DB_ENV->get_verbose.
+ */
+#define CHECK_ONOFF(handle, setter, getter, options, opt_cnt, type) do {\
+ size_t i; \
+ for (i = 0; i < (opt_cnt); i++) { \
+ CHECK_1_DIGIT_CONFIG_VALUE(handle, setter, getter, \
+ (options)[i], type, 1); \
+ CHECK_1_DIGIT_CONFIG_VALUE(handle, setter, getter, \
+ (options)[i], type, 0); \
+ } \
+} while(0)
+
+/*
+ * Like CHECK_1_DIGIT_CONFIG_VALUE, but the number or pointer to number
+ * is the second argument while the option is the third argument.
+ */
+#define CHECK_1_DIGIT_CONFIG_VALUE2(handle, setter, getter, opt, type, v)\
+ do { \
+ type vs, vg; \
+ vs = (type)(v); \
+ CuAssert(ct, #handle"->"#setter, \
+ (handle)->setter((handle), vs, (opt)) == 0); \
+ CuAssert(ct, #handle"->"#getter, \
+ (handle)->getter((handle), &vg, (opt)) == 0); \
+ CuAssert(ct, #getter"=="#setter, vs == vg); \
+} while(0)
+
+/*
+ * Test all the options for functions satisfying CHECK_1_DIGIT_CONFIG_VALUE2.
+ * The configuration value has no specific limit.
+ */
+#define CHECK_1_DIGIT_CONFIG_VALUES2(handle, setter, getter, configs, type)\
+ do { \
+ size_t cnt, i; \
+ cnt = sizeof(configs) / sizeof(configs[0]); \
+ for (i = 0; i < cnt; i++) { \
+ CHECK_1_DIGIT_CONFIG_VALUE2(handle, setter, getter, \
+ configs[i], type, rand()); \
+ } \
+} while(0)
+
+/*
+ * Test functions like DB_ENV->set_create_dir and and DB_ENV->get_create_dir,
+ * among which the setter function accepts a string(const char *) as the
+ * second argument, and the getter function accepts a pointer to string.
+ */
+#define CHECK_1_STR_VALUE(handle, setter, getter, v) do { \
+ const char *vs, *vg; \
+ vs = (v); \
+ CuAssert(ct, #handle"->"#setter, \
+ (handle)->setter((handle), vs) == 0); \
+ CuAssert(ct, #handle"->"#getter, \
+ (handle)->getter((handle), &vg) == 0); \
+ CuAssert(ct, #getter"=="#setter, strcmp(vs, vg) == 0); \
+} while(0)
+
+/*
+ * Like CHECK_1_STR_VALUE, but both setter and getter functions do
+ * not return anything.
+ */
+#define CHECK_1_STR_VALUE_VOID(handle, setter, getter, v) do { \
+ const char *vs, *vg; \
+ vs = (v); \
+ (handle)->setter((handle), vs); \
+ (handle)->getter((handle), &vg); \
+ CuAssert(ct, #getter"=="#setter, strcmp(vs, vg) == 0); \
+} while(0)
+
+/*
+ * Test functions like DB_ENV->set_errfile and and DB_ENV->get_errfile,
+ * among which the setter function accepts a pointer as the second
+ * argument, and the getter function accepts a pointer to pointer.
+ */
+#define CHECK_1_PTR_VALUE(handle, setter, getter, type, v) do { \
+ type *vs, *vg; \
+ vs = (v); \
+ CuAssert(ct, #handle"->"#setter, \
+ (handle)->setter((handle), vs) == 0); \
+ CuAssert(ct, #handle"->"#getter, \
+ (handle)->getter((handle), &vg) == 0); \
+ CuAssert(ct, #getter"=="#setter, vs == vg); \
+} while(0)
+
+/*
+ * Like CHECK_1_PTR_VALUE, but both setter and getter functions do
+ * not return anything.
+ */
+#define CHECK_1_PTR_VALUE_VOID(handle, setter, getter, type, v) do { \
+ type *vs, *vg; \
+ vs = (v); \
+ (handle)->setter((handle), vs); \
+ (handle)->getter((handle), &vg); \
+ CuAssert(ct, #getter"=="#setter, vs == vg); \
+} while(0)
+
+/*
+ * Test functions like DB_ENV->set_memory_max and and DB_ENV->get_memory_max,
+ * among which the setter function accepts two numbers the second and third
+ * argument, while the getter function accepts two pointers to number.
+ */
+#define CHECK_2_DIGIT_VALUES(handle, setter, getter, type1, v1, type2, v2)\
+ do { \
+ type1 vs1, vg1; \
+ type2 vs2, vg2; \
+ vs1 = (type1)(v1); \
+ vs2 = (type2)(v2); \
+ CuAssert(ct, #handle"->"#setter, \
+ (handle)->setter((handle), vs1, vs2) == 0); \
+ CuAssert(ct, #handle"->"#getter, \
+ (handle)->getter((handle), &vg1, &vg2) == 0); \
+ CuAssert(ct, #getter"=="#setter, vs1 == vg1); \
+ CuAssert(ct, #getter"=="#setter, vs2 == vg2); \
+} while(0)
+
+/*
+ * Test functions like DB_ENV->set_cachesize and and DB_ENV->get_cachesize,
+ * among which the setter function accepts three numbers as the second and
+ * third and fourth argument, while the getter function accepts three pointers
+ * to number.
+ */
+#define CHECK_3_DIGIT_VALUES(handle, setter, getter, type1, v1, type2, \
+ v2, type3, v3) do { \
+ type1 vs1, vg1; \
+ type2 vs2, vg2; \
+ type3 vs3, vg3; \
+ vs1 = (type1)(v1); \
+ vs2 = (type2)(v2); \
+ vs3 = (type3)(v3); \
+ CuAssert(ct, #handle"->"#setter, \
+ (handle)->setter((handle), vs1, vs2, v3) == 0); \
+ CuAssert(ct, #handle"->"#getter, \
+ (handle)->getter((handle), &vg1, &vg2, &vg3) == 0); \
+ CuAssert(ct, #getter"=="#setter, vs1 == vg1); \
+ CuAssert(ct, #getter"=="#setter, vs2 == vg2); \
+ CuAssert(ct, #getter"=="#setter, vs3 == vg3); \
+} while(0)
+
+/*
+ * Test functions like DB->set_flags and DB->get_flags, among which the setter
+ * function accepts an inclusive'OR of some individual options while the getter
+ * accepts a pointer to store the options composition.
+ * In this case, the getter may not return the exact value set by setter.
+ */
+#define CHECK_FLAG_VALUE(handle, setter, getter, type, v) do { \
+ type vs, vg; \
+ vs = (type)(v); \
+ CuAssert(ct, #handle"->"#setter, \
+ (handle)->setter((handle), vs) == 0); \
+ CuAssert(ct, #handle"->"#getter, \
+ (handle)->getter((handle), &vg) == 0); \
+ CuAssert(ct, #getter"=="#setter, (vs & vg) == vs); \
+} while(0)
+
+/*
+ * Test functions like DB_ENV->set_flags and DB_ENV->get_flags, among which
+ * the setter function accepts an individual option and an on/off value(1/0)
+ * while the getter accepts a pointer to store the options composition.
+ */
+#define CHECK_FLAG_VALUE_ONOFF(handle, setter, getter, type, v, on) do {\
+ type vs, vg; \
+ vs = (type)(v); \
+ CuAssert(ct, #handle"->"#setter, \
+ (handle)->setter((handle), vs, on) == 0); \
+ CuAssert(ct, #handle"->"#getter, \
+ (handle)->getter((handle), &vg) == 0); \
+ if (on) { \
+ CuAssert(ct, #getter"=="#setter, (vs & vg) == vs); \
+ } else { \
+ CuAssert(ct, #getter"=="#setter, (vs & vg) == 0); \
+ } \
+} while(0)
+
+/*
+ * Test turning on/off all the options for DB_ENV->set_flags.
+ */
+#define CHECK_ENV_FLAGS(handle, values) do { \
+ size_t i, cnt; \
+ cnt = sizeof(values) / sizeof(values[0]); \
+ for (i = 0; i < cnt; i++) { \
+ /* We only set the direct I/O if the os supports it. */ \
+ if ((values[i] & DB_DIRECT_DB) != 0 && \
+ __os_support_direct_io() == 0) \
+ continue; \
+ CHECK_FLAG_VALUE_ONOFF(handle, set_flags, \
+ get_flags, u_int32_t, values[i], 1); \
+ CHECK_FLAG_VALUE_ONOFF(handle, set_flags, \
+ get_flags, u_int32_t, values[i], 0); \
+ } \
+} while(0)
+
+struct handlers {
+ DB_ENV *dbenvp;
+ DB *dbp;
+ DB_MPOOLFILE *mp;
+ DB_SEQUENCE *seqp;
+};
+static struct handlers info;
+static const char *data_dirs[] = {
+ "data_dir1",
+ "data_dir2",
+ "data_dir3",
+ "data_dir4",
+ NULL
+};
+const char *passwd = "passwd1";
+static FILE *errfile, *msgfile;
+
+static int add_dirs_to_dbenv(DB_ENV *dbenv, const char **dirs);
+static int close_db_handle(DB *dbp);
+static int close_dbenv_handle(DB_ENV *dbenvp);
+static int close_mp_handle(DB_MPOOLFILE *mp);
+static int close_seq_handle(DB_SEQUENCE *seqp);
+static int cmp_dirs(const char **dirs1, const char **dirs2);
+static int create_db_handle(DB **dbpp, DB_ENV *dbenv);
+static int create_dbenv_handle(DB_ENV **dbenvpp);
+static int create_mp_handle(DB_MPOOLFILE **mpp, DB_ENV *dbenv);
+static int create_seq_handle(DB_SEQUENCE **seqpp, DB *dbp);
+
+int TestPreOpenSetterAndGetterSuiteSetup(CuSuite *suite) {
+ srand((unsigned int)time(NULL));
+ return (0);
+}
+
+int TestPreOpenSetterAndGetterSuiteTeardown(CuSuite *suite) {
+ return (0);
+}
+
+int TestPreOpenSetterAndGetterTestSetup(CuTest *ct) {
+ char buf[DB_MAXPATHLEN];
+
+ setup_envdir(TEST_ENV, 1);
+ sprintf(buf, "%s/%s", TEST_ENV, "errfile");
+ errfile = fopen(buf, "w");
+ CuAssert(ct, "open errfile", errfile != NULL);
+ sprintf(buf, "%s/%s", TEST_ENV, "msgfile");
+ msgfile = fopen(buf, "w");
+ CuAssert(ct, "open msgfile", msgfile != NULL);
+
+ info.dbenvp = NULL;
+ info.dbp = NULL;
+ info.mp = NULL;
+ info.seqp = NULL;
+
+ return (0);
+}
+
+int TestPreOpenSetterAndGetterTestTeardown(CuTest *ct) {
+ CuAssert(ct, "close errfile", fclose(errfile) == 0);
+ CuAssert(ct, "close msgfile", fclose(msgfile) == 0);
+ /*
+ * Close the handle in case failure happens.
+ */
+ if (info.seqp != NULL)
+ CuAssert(ct, "seqp->close",
+ info.seqp->close(info.seqp, 0) == 0);
+ if (info.mp != NULL)
+ CuAssert(ct, "mp->close", info.mp->close(info.mp, 0) == 0);
+ if (info.dbp != NULL)
+ CuAssert(ct, "dbp->close",
+ info.dbp->close(info.dbp, 0) == 0);
+ if (info.dbenvp != NULL)
+ CuAssert(ct, "dbenvp->close",
+ info.dbenvp->close(info.dbenvp, 0) == 0);
+ return (0);
+}
+
+/*
+ * For most number arguments, if there is no special requirement, we use
+ * a random value, since most checks are done during open and we do not
+ * do handle open in all the following tests.
+ *
+ * If a configuration has many options, we will cover all options. If
+ * it accepts inclusive'OR of the options, we will test some OR's as well.
+ */
+
+int TestEnvPreOpenSetterAndGetter(CuTest *ct) {
+ DB_ENV *dbenv, *repmgr_dbenv;
+ const char **dirs;
+ const u_int8_t *lk_get_conflicts;
+ u_int8_t lk_set_conflicts[] = {1, 0, 0, 0};
+ DB_BACKUP_CONFIG backup_configs[] = {
+ /*
+ * DB_BACKUP_WRITE_DIRECT is not listed here, since the
+ * value(only 1/0) for this configuration is different
+ * from others. So we test it separately.
+ */
+ DB_BACKUP_READ_COUNT,
+ DB_BACKUP_READ_SLEEP,
+ DB_BACKUP_SIZE
+ };
+ u_int32_t env_flags[] = {
+ DB_CDB_ALLDB,
+ DB_AUTO_COMMIT | DB_MULTIVERSION | DB_REGION_INIT |
+ DB_TXN_SNAPSHOT,
+ DB_DSYNC_DB | DB_NOLOCKING | DB_NOMMAP | DB_NOPANIC,
+ DB_OVERWRITE | DB_TIME_NOTGRANTED | DB_TXN_NOSYNC |
+ DB_YIELDCPU,
+ DB_TXN_NOWAIT | DB_TXN_WRITE_NOSYNC,
+ DB_DIRECT_DB
+ };
+ u_int32_t env_timeouts[] = {
+ DB_SET_LOCK_TIMEOUT,
+ DB_SET_REG_TIMEOUT,
+ DB_SET_TXN_TIMEOUT
+ };
+ u_int32_t lk_detect_values[] = {
+ DB_LOCK_DEFAULT,
+ DB_LOCK_EXPIRE,
+ DB_LOCK_MAXLOCKS,
+ DB_LOCK_MAXWRITE,
+ DB_LOCK_MINLOCKS,
+ DB_LOCK_MINWRITE,
+ DB_LOCK_OLDEST,
+ DB_LOCK_RANDOM,
+ DB_LOCK_YOUNGEST
+ };
+ u_int32_t log_configs[] = {
+ DB_LOG_DIRECT,
+ DB_LOG_DSYNC,
+ DB_LOG_AUTO_REMOVE,
+ DB_LOG_IN_MEMORY,
+ DB_LOG_ZERO
+ };
+ DB_MEM_CONFIG mem_configs[] = {
+ DB_MEM_LOCK,
+ DB_MEM_LOCKOBJECT,
+ DB_MEM_LOCKER,
+ DB_MEM_LOGID,
+ DB_MEM_TRANSACTION,
+ DB_MEM_THREAD
+ };
+ u_int32_t rep_configs[] = {
+ DB_REP_CONF_AUTOINIT,
+ DB_REP_CONF_AUTOROLLBACK,
+ DB_REP_CONF_BULK,
+ DB_REP_CONF_DELAYCLIENT,
+ DB_REP_CONF_INMEM,
+ DB_REP_CONF_LEASE,
+ DB_REP_CONF_NOWAIT,
+ DB_REPMGR_CONF_ELECTIONS,
+ DB_REPMGR_CONF_2SITE_STRICT
+ };
+ u_int32_t rep_timeouts[] = {
+ DB_REP_CHECKPOINT_DELAY,
+ DB_REP_ELECTION_TIMEOUT,
+ DB_REP_FULL_ELECTION_TIMEOUT,
+ DB_REP_LEASE_TIMEOUT
+ };
+ u_int32_t repmgr_timeouts[] = {
+ DB_REP_ACK_TIMEOUT,
+ DB_REP_CONNECTION_RETRY,
+ DB_REP_ELECTION_RETRY,
+ DB_REP_HEARTBEAT_MONITOR,
+ DB_REP_HEARTBEAT_SEND
+ };
+ u_int32_t verbose_flags[] = {
+ DB_VERB_BACKUP,
+ DB_VERB_DEADLOCK,
+ DB_VERB_FILEOPS,
+ DB_VERB_FILEOPS_ALL,
+ DB_VERB_RECOVERY,
+ DB_VERB_REGISTER,
+ DB_VERB_REPLICATION,
+ DB_VERB_REP_ELECT,
+ DB_VERB_REP_LEASE,
+ DB_VERB_REP_MISC,
+ DB_VERB_REP_MSGS,
+ DB_VERB_REP_SYNC,
+ DB_VERB_REP_SYSTEM,
+ DB_VERB_REPMGR_CONNFAIL,
+ DB_VERB_REPMGR_MISC,
+ DB_VERB_WAITSFOR
+ };
+ u_int32_t encrypt_flags;
+ size_t log_configs_cnt, rep_configs_cnt, verbose_flags_cnt;
+ int lk_get_nmodes, lk_set_nmodes;
+ time_t tx_get_timestamp, tx_set_timestamp;
+
+ verbose_flags_cnt = sizeof(verbose_flags) / sizeof(verbose_flags[0]);
+ log_configs_cnt = sizeof(log_configs) / sizeof(log_configs[0]);
+ rep_configs_cnt = sizeof(rep_configs) / sizeof(rep_configs[0]);
+
+ CuAssert(ct, "db_env_create", create_dbenv_handle(&dbenv) == 0);
+
+ /* Test the DB_ENV->add_data_dir(), DB_ENV->get_data_dirs(). */
+ CuAssert(ct, "add_dirs_to_dbenv",
+ add_dirs_to_dbenv(dbenv, data_dirs) == 0);
+ CuAssert(ct, "dbenv->get_data_dirs",
+ dbenv->get_data_dirs(dbenv, &dirs) == 0);
+ CuAssert(ct, "cmp_dirs", cmp_dirs(data_dirs, dirs) == 0);
+
+ /* Test DB_ENV->set_backup_config(), DB_ENV->get_backup_config(). */
+ CHECK_1_DIGIT_CONFIG_VALUE(dbenv, set_backup_config,
+ get_backup_config, DB_BACKUP_WRITE_DIRECT, u_int32_t, 1);
+ CHECK_1_DIGIT_CONFIG_VALUE(dbenv, set_backup_config,
+ get_backup_config, DB_BACKUP_WRITE_DIRECT, u_int32_t, 0);
+ CHECK_1_DIGIT_CONFIG_VALUES(dbenv, set_backup_config, get_backup_config,
+ backup_configs, DB_BACKUP_CONFIG);
+
+ /* Test DB_ENV->set_create_dir(), DB_ENV->get_create_dir(). */
+ CHECK_1_STR_VALUE(dbenv, set_create_dir, get_create_dir, data_dirs[1]);
+
+ /* Test DB_ENV->set_encrypt(), DB_ENV->get_encrypt_flags(). */
+ CuAssert(ct, "dbenv->set_encrypt",
+ dbenv->set_encrypt(dbenv, passwd, DB_ENCRYPT_AES) == 0);
+ CuAssert(ct, "dbenv->get_encrypt_flags",
+ dbenv->get_encrypt_flags(dbenv, &encrypt_flags) == 0);
+ CuAssert(ct, "check encrypt flags", encrypt_flags == DB_ENCRYPT_AES);
+
+ /* Test DB_ENV->set_errfile(), DB_ENV->get_errfile(). */
+ CHECK_1_PTR_VALUE_VOID(dbenv, set_errfile, get_errfile, FILE, errfile);
+
+ /* Test DB_ENV->set_errpfx(), DB_ENV->get_errpfx(). */
+ CHECK_1_STR_VALUE_VOID(dbenv, set_errpfx, get_errpfx, "dbenv0");
+
+ /* Test DB_ENV->set_flags(), DB_ENV->get_flags(). */
+ CHECK_ENV_FLAGS(dbenv, env_flags);
+
+ /*
+ * Test DB_ENV->set_intermediate_dir_mode(),
+ * DB_ENV->get_intermediate_dir_mode().
+ */
+ CHECK_1_STR_VALUE(dbenv,
+ set_intermediate_dir_mode, get_intermediate_dir_mode, "rwxr-xr--");
+
+ /* Test DB_ENV->set_memory_init(), DB_ENV->get_memory_init(). */
+ CHECK_1_DIGIT_CONFIG_VALUES(dbenv, set_memory_init, get_memory_init,
+ mem_configs, u_int32_t);
+
+ /*
+ * Test DB_ENV->set_memory_max(), DB_ENV->get_memory_max().
+ * The code will adjust the values if necessary, and using
+ * random values can not guarantee the returned values
+ * are exactly what we set. So we will not use random values here.
+ */
+ CHECK_2_DIGIT_VALUES(dbenv, set_memory_max, get_memory_max,
+ u_int32_t, 2, u_int32_t, 1048576);
+
+ /* Test DB_ENV->set_metadata_dir(), DB_ENV->get_metadata_dir(). */
+ CHECK_1_STR_VALUE(dbenv,
+ set_metadata_dir, get_metadata_dir, data_dirs[2]);
+
+ /* Test DB_ENV->set_msgfile(), DB_ENV->get_msgfile(). */
+ CHECK_1_PTR_VALUE_VOID(dbenv, set_msgfile, get_msgfile, FILE, msgfile);
+
+ /* Test DB_ENV->set_shm_key(), DB_ENV->get_shm_key(). */
+ CHECK_1_DIGIT_VALUE(dbenv, set_shm_key, get_shm_key, long, rand());
+
+ /* Test DB_ENV->set_timeout(), DB_ENV->get_timeout(). */
+ CHECK_1_DIGIT_CONFIG_VALUES2(dbenv, set_timeout, get_timeout,
+ env_timeouts, db_timeout_t);
+
+ /* Test DB_ENV->set_tmp_dir(), DB_ENV->get_tmp_dir(). */
+ CHECK_1_STR_VALUE(dbenv, set_tmp_dir, get_tmp_dir, "/temp");
+
+ /* Test DB_ENV->set_verbose(), DB_ENV->get_verbose(). */
+ CHECK_ONOFF(dbenv, set_verbose, get_verbose, verbose_flags,
+ verbose_flags_cnt, int);
+
+ /* ==================== Lock Configuration ===================== */
+
+ /* Test DB_ENV->set_lk_conflicts(), DB_ENV->get_lk_conflicts(). */
+ lk_set_nmodes = 2;
+ CuAssert(ct, "dbenv->set_lk_conflicts", dbenv->set_lk_conflicts(dbenv,
+ lk_set_conflicts, lk_set_nmodes) == 0);
+ CuAssert(ct, "dbenv->get_lk_conflicts", dbenv->get_lk_conflicts(dbenv,
+ &lk_get_conflicts, &lk_get_nmodes) == 0);
+ CuAssert(ct, "check lock conflicts", memcmp(lk_set_conflicts,
+ lk_get_conflicts, sizeof(lk_set_conflicts)) == 0);
+ CuAssert(ct, "check lock nomdes", lk_set_nmodes == lk_get_nmodes);
+
+ /* DB_ENV->set_lk_detect(), DB_ENV->get_lk_detect(). */
+ CHECK_1_DIGIT_VALUES(dbenv, set_lk_detect, get_lk_detect, u_int32_t,
+ lk_detect_values);
+
+ /* Test DB_ENV->set_lk_max_lockers(), DB_ENV->get_lk_max_lockers(). */
+ CHECK_1_DIGIT_VALUE(dbenv, set_lk_max_lockers, get_lk_max_lockers,
+ u_int32_t, rand());
+
+ /* Test DB_ENV->set_lk_max_locks(), DB_ENV->get_lk_max_locks(). */
+ CHECK_1_DIGIT_VALUE(dbenv, set_lk_max_locks, get_lk_max_locks,
+ u_int32_t, rand());
+
+ /* Test DB_ENV->set_lk_max_objects(), DB_ENV->get_lk_max_objects(). */
+ CHECK_1_DIGIT_VALUE(dbenv, set_lk_max_objects, get_lk_max_objects,
+ u_int32_t, rand());
+
+ /* Test DB_ENV->set_lk_partitions(), DB_ENV->get_lk_partitions(). */
+ CHECK_1_DIGIT_VALUE(dbenv, set_lk_partitions, get_lk_partitions,
+ u_int32_t, rand());
+
+ /* Test DB_ENV->set_lk_tablesize(), DB_ENV->get_lk_tablesize(). */
+ CHECK_1_DIGIT_VALUE(dbenv, set_lk_tablesize, get_lk_tablesize,
+ u_int32_t, rand());
+
+ /* ==================== Log Configuration ===================== */
+
+ /*
+ * Test DB_ENV->log_set_config(), DB_ENV->log_get_config().
+ * Direct I/O setting can only be performed if os supports it.
+ */
+ if (__os_support_direct_io()) {
+ CHECK_ONOFF(dbenv, log_set_config, log_get_config,
+ log_configs, log_configs_cnt, int);
+ } else {
+ CHECK_ONOFF(dbenv, log_set_config, log_get_config,
+ &log_configs[1], log_configs_cnt - 1, int);
+ }
+
+ /* Test DB_ENV->set_lg_bsize(), DB_ENV->get_lg_bsize(). */
+ CHECK_1_DIGIT_VALUE(dbenv, set_lg_bsize, get_lg_bsize,
+ u_int32_t, rand());
+
+ /* Test DB_ENV->set_lg_dir(), DB_ENV->get_lg_dir(). */
+ CHECK_1_STR_VALUE(dbenv, set_lg_dir, get_lg_dir, "/logdir");
+
+ /* Test DB_ENV->set_lg_filemode(), DB_ENV->get_lg_filemode(). */
+ CHECK_1_DIGIT_VALUE(dbenv, set_lg_filemode, get_lg_filemode,
+ int, 0640);
+
+ /* Test DB_ENV->set_lg_max(), DB_ENV->get_lg_max(). */
+ CHECK_1_DIGIT_VALUE(dbenv, set_lg_max, get_lg_max, u_int32_t, rand());
+
+ /*
+ * Test DB_ENV->set_lg_regionmax(), DB_ENV->get_lg_regionmax().
+ * The value must be bigger than LG_BASE_REGION_SIZE(130000).
+ */
+ CHECK_1_DIGIT_VALUE(dbenv, set_lg_regionmax, get_lg_regionmax,
+ u_int32_t, 12345678);
+
+ /* ==================== Mpool Configuration ===================== */
+
+ /*
+ * Test DB_ENV->set_cache_max(), DB_ENV->get_cache_max().
+ * The values could be ajusted, so we use specific values to avoid
+ * adjustment.
+ */
+ CHECK_2_DIGIT_VALUES(dbenv, set_cache_max, get_cache_max,
+ u_int32_t, 3, u_int32_t, 131072);
+
+ /*
+ * Test DB_ENV->set_cachesize() and DB_ENV->get_cachesize().
+ * The values could be ajusted, so we use specific values to avoid
+ * adjustment.
+ */
+ CHECK_3_DIGIT_VALUES(dbenv, set_cachesize, get_cachesize,
+ u_int32_t, 3, u_int32_t, 1048576, int, 5);
+
+ /* Test DB_ENV->set_mp_max_openfd(), DB_ENV->get_mp_max_openfd(). */
+ CHECK_1_DIGIT_VALUE(dbenv, set_mp_max_openfd, get_mp_max_openfd,
+ int, rand());
+
+ /* Test DB_ENV->set_mp_max_write(), DB_ENV->get_mp_max_write(). */
+ CHECK_2_DIGIT_VALUES(dbenv, set_mp_max_write, get_mp_max_write,
+ int, rand(), db_timeout_t , rand());
+
+ /* Test DB_ENV->set_mp_mmapsize(), DB_ENV->get_mp_mmapsize(). */
+ CHECK_1_DIGIT_VALUE(dbenv, set_mp_mmapsize, get_mp_mmapsize,
+ size_t, rand());
+
+ /* Test DB_ENV->set_mp_mtxcount(), DB_ENV->get_mp_mtxcount(). */
+ CHECK_1_DIGIT_VALUE(dbenv, set_mp_mtxcount, get_mp_mtxcount,
+ u_int32_t, rand());
+
+ /*
+ * Test DB_ENV->set_mp_pagesize(), DB_ENV->get_mp_pagesize().
+ * The pagesize should be between 512 and 65536 and be power of two.
+ */
+ CHECK_1_DIGIT_VALUE(dbenv, set_mp_pagesize, get_mp_pagesize,
+ u_int32_t, 65536);
+
+ /* Test DB_ENV->set_mp_tablesize(), DB_ENV->get_mp_tablesize(). */
+ CHECK_1_DIGIT_VALUE(dbenv, set_mp_tablesize, get_mp_tablesize,
+ u_int32_t, rand());
+
+ /* ==================== Mutex Configuration ===================== */
+
+ /*
+ * Test DB_ENV->mutex_set_align(), DB_ENV->mutex_get_align().
+ * The mutex align value should be power of two.
+ */
+ CHECK_1_DIGIT_VALUE(dbenv, mutex_set_align, mutex_get_align,
+ u_int32_t, 32);
+
+ /* Test DB_ENV->mutex_set_increment(), DB_ENV->mutex_get_increment(). */
+ CHECK_1_DIGIT_VALUE(dbenv, mutex_set_increment, mutex_get_increment,
+ u_int32_t, rand());
+
+ /*
+ * Test DB_ENV->mutex_set_init(), DB_ENV->mutex_get_init().
+ * We should make sure the init value is not bigger than max, otherwise,
+ * the returned max value will not be correct.
+ */
+ CHECK_1_DIGIT_VALUE(dbenv, mutex_set_init, mutex_get_init,
+ u_int32_t, 131072);
+
+ /* Test DB_ENV->mutex_set_max(), DB_ENV->mutex_get_max(). */
+ CHECK_1_DIGIT_VALUE(dbenv, mutex_set_max, mutex_get_max,
+ u_int32_t, 503276);
+
+ /*
+ * Test DB_ENV->mutex_set_tas_spins(), DB_ENV->mutex_get_tas_spins().
+ * The value should be between 1 and 1000000 .
+ */
+ CHECK_1_DIGIT_VALUE(dbenv, mutex_set_tas_spins, mutex_get_tas_spins,
+ u_int32_t, 1234);
+
+ /* =================== Replication Configuration ==================== */
+
+ /*
+ * Test DB_ENV->rep_set_clockskew(), DB_ENV->rep_get_clockskew().
+ * The fast_clock should be bigger than slow_clock.
+ */
+ CHECK_2_DIGIT_VALUES(dbenv, rep_set_clockskew, rep_get_clockskew,
+ u_int32_t, 12345, u_int32_t, 11111);
+
+ /* Test DB_ENV->rep_set_config(), DB_ENV->rep_get_config(). */
+ CHECK_ONOFF(dbenv, rep_set_config, rep_get_config, rep_configs,
+ rep_configs_cnt - 2, int);
+
+ /*
+ * Test DB_ENV->rep_set_limit(), DB_ENV->rep_get_limit().
+ * We use specific values to avoid adjustment.
+ */
+ CHECK_2_DIGIT_VALUES(dbenv, rep_set_limit, rep_get_limit,
+ u_int32_t, 2, u_int32_t, 2345678);
+
+ /* Test DB_ENV->rep_set_nsites(), DB_ENV->rep_get_nsites(). */
+ CHECK_1_DIGIT_VALUE(dbenv, rep_set_nsites, rep_get_nsites,
+ u_int32_t, rand());
+
+ /* Test DB_ENV->rep_set_priority(), DB_ENV->rep_get_priority(). */
+ CHECK_1_DIGIT_VALUE(dbenv, rep_set_priority, rep_get_priority,
+ u_int32_t, rand());
+
+ /*
+ * Test DB_ENV->rep_set_request(), DB_ENV->rep_get_request().
+ * The max should be bigger than min.
+ */
+ CHECK_2_DIGIT_VALUES(dbenv, rep_set_request, rep_get_request,
+ u_int32_t, 100001, u_int32_t, 1234567);
+
+ /* Test DB_ENV->rep_set_timeout(), DB_ENV->rep_get_timeout(). */
+ CHECK_1_DIGIT_CONFIG_VALUES(dbenv, rep_set_timeout, rep_get_timeout,
+ rep_timeouts, u_int32_t);
+
+ /* Test DB_ENV->set_tx_max(), DB_ENV->get_tx_max(). */
+ CHECK_1_DIGIT_VALUE(dbenv, set_tx_max, get_tx_max, u_int32_t, rand());
+
+ /*
+ * Test DB_ENV->set_tx_timestamp(), DB_ENV->get_tx_timestamp().
+ * We specify the timestamp to be one hour ago.
+ */
+ tx_set_timestamp = time(NULL);
+ tx_set_timestamp -= 3600;
+ CuAssert(ct, "dbenv->set_tx_timestamp",
+ dbenv->set_tx_timestamp(dbenv, &tx_set_timestamp) == 0);
+ CuAssert(ct, "dbenv->get_tx_timestamp",
+ dbenv->get_tx_timestamp(dbenv, &tx_get_timestamp) == 0);
+ CuAssert(ct, "check tx timestamp",
+ tx_set_timestamp == tx_get_timestamp);
+
+ CuAssert(ct, "dbenv->close", close_dbenv_handle(dbenv) == 0);
+
+ /*
+ * The follwoing configurations are only valid for environment
+ * using replication manager API.
+ */
+ CuAssert(ct, "db_env_create", create_dbenv_handle(&repmgr_dbenv) == 0);
+
+ /* Test DB_ENV->rep_set_config(), DB_ENV->rep_get_config() */
+ CHECK_ONOFF(repmgr_dbenv, rep_set_config, rep_get_config,
+ rep_configs + rep_configs_cnt - 3, 2, int);
+
+ /* Test DB_ENV->rep_set_timeout(), DB_ENV->rep_get_timeout() */
+ CHECK_1_DIGIT_CONFIG_VALUES(repmgr_dbenv, rep_set_timeout,
+ rep_get_timeout, repmgr_timeouts, u_int32_t);
+
+ CuAssert(ct, "repmgr_dbenv->close",
+ close_dbenv_handle(repmgr_dbenv) == 0);
+
+ return (0);
+}
+
+int TestDbPreOpenSetterAndGetter(CuTest *ct) {
+ DB_ENV *dbenv;
+ DB *db, *env_db, *hash_db, *heap_db, *queue_db, *recno_db;
+ const char **part_dirs;
+ u_int32_t encrypt_flags, heap_set_bytes, heap_set_gbytes,
+ heap_get_bytes, heap_get_gbytes;
+ int nowait, onoff;
+
+ /* ================ General and Btree Configuration =============== */
+
+ CuAssert(ct, "db_create", create_db_handle(&db, NULL) == 0);
+
+ /*
+ * Test DB->set_cachesize(), DB->get_cachesize().
+ * We use specific values to avoid adjustment.
+ */
+ CHECK_3_DIGIT_VALUES(db, set_cachesize, get_cachesize,
+ u_int32_t, 3, u_int32_t, 1048576, int, 5);
+
+ /* Test DB->set_encrypt(), DB->get_encrypt_flags(). */
+ CuAssert(ct, "db->set_encrypt",
+ db->set_encrypt(db, passwd, DB_ENCRYPT_AES) == 0);
+ CuAssert(ct, "db->get_encrypt_flags",
+ db->get_encrypt_flags(db, &encrypt_flags) == 0);
+ CuAssert(ct, "check encrypt flags", encrypt_flags == DB_ENCRYPT_AES);
+
+ /* Test DB->set_errfile(), DB->get_errfile(). */
+ CHECK_1_PTR_VALUE_VOID(db, set_errfile, get_errfile, FILE, errfile);
+
+ /* Test DB->set_errpfx(), DB->get_errpfx().*/
+ CHECK_1_STR_VALUE_VOID(db, set_errpfx, get_errpfx, "dbp1");
+
+ /* Test DB->set_flags(), DB->get_flags(). */
+ CHECK_FLAG_VALUE(db, set_flags, get_flags,
+ u_int32_t, DB_CHKSUM | DB_RECNUM | DB_REVSPLITOFF);
+
+ /* Test DB->set_lk_exclusive(), DB->get_lk_exclusive(). */
+ CuAssert(ct, "db->set_lk_exclusive", db->set_lk_exclusive(db, 1) == 0);
+ CuAssert(ct, "db->get_lk_exclusive",
+ db->get_lk_exclusive(db, &onoff, &nowait) == 0);
+ CuAssert(ct, "check lk_exclusive onoff", onoff == 1);
+ CuAssert(ct, "check lk_exclusive nowait", nowait == 1);
+
+ /*
+ * Test DB->set_lorder(), DB->get_lorder().
+ * The only acceptable values are 1234 and 4321.
+ */
+ CHECK_1_DIGIT_VALUE(db, set_lorder, get_lorder, int, 1234);
+ CHECK_1_DIGIT_VALUE(db, set_lorder, get_lorder, int, 4321);
+
+ /* Test DB->set_msgfile(), DB->get_msgfile(). */
+ CHECK_1_PTR_VALUE_VOID(db, set_msgfile, get_msgfile, FILE, msgfile);
+
+ /*
+ * Test DB->set_pagesize(), DB->get_pagesize().
+ * The pagesize should be 512-55536, and be power of two.
+ */
+ CHECK_1_DIGIT_VALUE(db, set_pagesize, get_pagesize, u_int32_t, 512);
+ CHECK_1_DIGIT_VALUE(db, set_pagesize, get_pagesize, u_int32_t, 65536);
+
+ /*
+ * Test DB->set_bt_minkey(), DB->get_bt_minkey().
+ * The minkey value should be 2 at least.
+ */
+ CHECK_1_DIGIT_VALUE(db, set_bt_minkey, get_bt_minkey, u_int32_t, 17);
+
+ CuAssert(ct, "db->close", close_db_handle(db) == 0);
+
+ /* =================== Recno-only Configuration ===================== */
+
+ CuAssert(ct, "db_create", create_db_handle(&recno_db, NULL) == 0);
+
+ /* Test DB->set_flags(), DB->get_flags(). */
+ CHECK_FLAG_VALUE(recno_db, set_flags, get_flags,
+ u_int32_t, DB_RENUMBER | DB_SNAPSHOT);
+
+ /* Test DB->set_re_delim(), DB->get_re_delim(). */
+ CHECK_1_DIGIT_VALUE(recno_db, set_re_delim, get_re_delim,
+ int, rand());
+
+ /* Test DB->set_re_len(), DB->get_re_len(). */
+ CHECK_1_DIGIT_VALUE(recno_db, set_re_len, get_re_len,
+ u_int32_t, rand());
+
+ /* Test DB->set_re_pad(), DB->get_re_pad(). */
+ CHECK_1_DIGIT_VALUE(recno_db, set_re_pad, get_re_pad, int, rand());
+
+ /* Test DB->set_re_source(), DB->get_re_source(). */
+ CHECK_1_STR_VALUE(recno_db, set_re_source, get_re_source, "re_source1");
+
+ CuAssert(ct, "recno_db->close", close_db_handle(recno_db) == 0);
+
+ /* ==================== Hash-only Configuration ===================== */
+
+ CuAssert(ct, "db_create", create_db_handle(&hash_db, NULL) == 0);
+
+ /* Test DB->set_flags(), DB->get_flags(). */
+ CHECK_FLAG_VALUE(hash_db, set_flags, get_flags,
+ u_int32_t, DB_DUP | DB_DUPSORT | DB_REVSPLITOFF);
+
+ /* Test DB->set_h_ffactor(), DB->get_h_ffactor(). */
+ CHECK_1_DIGIT_VALUE(hash_db, set_h_ffactor, get_h_ffactor,
+ u_int32_t, rand());
+
+ /* Test DB->set_h_nelem(), DB->get_h_nelem(). */
+ CHECK_1_DIGIT_VALUE(hash_db, set_h_nelem, get_h_nelem,
+ u_int32_t, rand());
+
+ CuAssert(ct, "hash_db->close", close_db_handle(hash_db) == 0);
+
+ /* =================== Queue-only Configuration ===================== */
+
+ CuAssert(ct, "db_create", create_db_handle(&queue_db, NULL) == 0);
+
+ /* Test DB->set_flags(), DB->get_flags(). */
+ CHECK_FLAG_VALUE(queue_db, set_flags, get_flags, u_int32_t, DB_INORDER);
+
+ /* Test DB->set_q_extentsize(), DB->get_q_extentsize(). */
+ CHECK_1_DIGIT_VALUE(queue_db, set_q_extentsize, get_q_extentsize,
+ u_int32_t, rand());
+
+ CuAssert(ct, "queue_db->close", close_db_handle(queue_db) == 0);
+
+ /* ==================== Heap-only Configuration ===================== */
+ CuAssert(ct, "db_create", create_db_handle(&heap_db, NULL) == 0);
+
+ /* Test DB->set_heapsize(), DB->get_heapsize(). */
+ heap_set_gbytes = 3;
+ heap_set_bytes = 1048576;
+ heap_get_gbytes = heap_get_bytes = 0;
+ CuAssert(ct, "DB->set_heapsize", heap_db->set_heapsize(heap_db,
+ heap_set_gbytes, heap_set_bytes, 0) == 0);
+ CuAssert(ct, "DB->get_heapsize", heap_db->get_heapsize(heap_db,
+ &heap_get_gbytes, &heap_get_bytes) == 0);
+ CuAssert(ct, "Check heap gbytes", heap_set_gbytes == heap_get_gbytes);
+ CuAssert(ct, "Check heap bytes", heap_set_bytes == heap_get_bytes);
+
+ /* Test DB->set_heap_regionsize(), DB->get_heap_regionsize(). */
+ CHECK_1_DIGIT_VALUE(heap_db, set_heap_regionsize, get_heap_regionsize,
+ u_int32_t, rand());
+
+ CuAssert(ct, "heap_db->close", close_db_handle(heap_db) == 0);
+
+ /*
+ * The following configurations require the database
+ * be opened in an environment.
+ */
+ CuAssert(ct, "db_env_create", create_dbenv_handle(&dbenv) == 0);
+ CuAssert(ct, "dbenv->set_flags(DB_ENCRYPT)", dbenv->set_encrypt(dbenv,
+ passwd, DB_ENCRYPT_AES) == 0);
+ CuAssert(ct, "add_dirs_to_dbenv",
+ add_dirs_to_dbenv(dbenv, data_dirs) == 0);
+ CuAssert(ct, "dbenv->open", dbenv->open(dbenv, TEST_ENV,
+ DB_CREATE | DB_INIT_MPOOL | DB_INIT_TXN, 0644) == 0);
+ CuAssert(ct, "db_create", create_db_handle(&env_db, dbenv) == 0);
+
+ /* Test DB->set_flags(), DB->get_flags(). */
+ CHECK_FLAG_VALUE(env_db, set_flags, get_flags,
+ u_int32_t, DB_ENCRYPT | DB_TXN_NOT_DURABLE);
+
+ /* Test DB->set_create_dir(), DB->get_create_dir(). */
+ CHECK_1_STR_VALUE(env_db, set_create_dir, get_create_dir, data_dirs[0]);
+
+ /* Test DB->set_partition_dirs(), DB->get_partition_dirs(). */
+ CuAssert(ct, "env_db->set_partition_dirs",
+ env_db->set_partition_dirs(env_db, &data_dirs[1]) == 0);
+ CuAssert(ct, "env_db->get_partition_dirs",
+ env_db->get_partition_dirs(env_db, &part_dirs) == 0);
+ CuAssert(ct, "cmp_dirs", cmp_dirs(&data_dirs[1], part_dirs) == 0);
+
+ CuAssert(ct, "env_db->close", close_db_handle(env_db) == 0);
+ CuAssert(ct, "dbenv->close", close_dbenv_handle(dbenv) == 0);
+
+ return (0);
+}
+
+int TestMpoolFilePreOpenSetterAndGetter(CuTest *ct) {
+ DB_ENV *dbenv;
+ DB_MPOOLFILE *mpf;
+ u_int8_t get_fileid[DB_FILE_ID_LEN], set_fileid[DB_FILE_ID_LEN];
+ DB_CACHE_PRIORITY cache_priorities[] = {
+ DB_PRIORITY_VERY_LOW,
+ DB_PRIORITY_LOW,
+ DB_PRIORITY_DEFAULT,
+ DB_PRIORITY_HIGH,
+ DB_PRIORITY_VERY_HIGH
+ };
+ u_int32_t mpool_flags;
+ size_t len;
+ DBT pgcookie_get, pgcookie_set;
+
+ CuAssert(ct, "db_env_create", create_dbenv_handle(&dbenv) == 0);
+ CuAssert(ct, "dbenv->open", dbenv->open(dbenv, TEST_ENV,
+ DB_CREATE | DB_INIT_MPOOL, 0644) == 0);
+ CuAssert(ct, "dbenv->memp_fcreate", create_mp_handle(&mpf, dbenv) == 0);
+
+ /* Test DB_MPOOLFILE->set_clear_len(), DB_MPOOLFILE->get_clear_len(). */
+ CHECK_1_DIGIT_VALUE(mpf, set_clear_len, get_clear_len,
+ u_int32_t, rand());
+
+ /* Test DB_MPOOLFILE->set_fileid(), DB_MPOOLFILE->get_fileid(). */
+ len = sizeof(DB_ENV) > DB_FILE_ID_LEN ? DB_FILE_ID_LEN : sizeof(DB_ENV);
+ memset(get_fileid, 0, DB_FILE_ID_LEN);
+ memcpy(set_fileid, dbenv, len);
+ CuAssert(ct, "mpf->set_fileid", mpf->set_fileid(mpf, set_fileid) == 0);
+ CuAssert(ct, "mpf->get_fileid", mpf->get_fileid(mpf, get_fileid) == 0);
+ CuAssert(ct, "check fileid", memcmp(set_fileid, get_fileid, len) == 0);
+
+ /* Test DB_MPOOLFILE->set_flags(), DB_MPOOLFILE->get_flags(). */
+ mpool_flags = 0;
+ CuAssert(ct, "mpf->set_flags",
+ mpf->set_flags(mpf, DB_MPOOL_NOFILE, 1) == 0);
+ CuAssert(ct, "mpf->set_flags",
+ mpf->set_flags(mpf, DB_MPOOL_UNLINK, 1) == 0);
+ CuAssert(ct, "mpf->get_flags",
+ mpf->get_flags(mpf, &mpool_flags) == 0);
+ CuAssert(ct, "check flags",
+ mpool_flags == (DB_MPOOL_NOFILE | DB_MPOOL_UNLINK));
+ CuAssert(ct, "mpf->set_flags",
+ mpf->set_flags(mpf, DB_MPOOL_NOFILE, 0) == 0);
+ CuAssert(ct, "mpf->set_flags",
+ mpf->set_flags(mpf, DB_MPOOL_UNLINK, 0) == 0);
+ CuAssert(ct, "mpf->get_flags", mpf->get_flags(mpf, &mpool_flags) == 0);
+ CuAssert(ct, "check flags", mpool_flags == 0);
+
+ /* Test DB_MPOOLFILE->set_ftype(), DB_MPOOLFILE->get_ftype(). */
+ CHECK_1_DIGIT_VALUE(mpf, set_ftype, get_ftype, int, rand());
+
+ /*
+ * Test DB_MPOOLFILE->set_lsn_offset(),
+ * DB_MPOOLFILE->get_lsn_offset().
+ */
+ CHECK_1_DIGIT_VALUE(mpf, set_lsn_offset, get_lsn_offset,
+ int32_t, rand());
+
+ /*
+ * Test DB_MPOOLFILE->set_maxsize(), DB_MPOOLFILE->get_maxsize().
+ * We use specific values to avoid adjustment.
+ */
+ CHECK_2_DIGIT_VALUES(mpf, set_maxsize, get_maxsize,
+ u_int32_t, 2, u_int32_t, 1048576);
+
+ /* Test DB_MPOOLFILE->set_pgcookie(), DB_MPOOLFILE->get_pgcookie(). */
+ memset(&pgcookie_set, 0, sizeof(DBT));
+ memset(&pgcookie_get, 0, sizeof(DBT));
+ pgcookie_set.data = set_fileid;
+ pgcookie_set.size = DB_FILE_ID_LEN;
+ CuAssert(ct, "mpf->set_pgcookie",
+ mpf->set_pgcookie(mpf, &pgcookie_set) == 0);
+ CuAssert(ct, "mpf->get_pgcookie",
+ mpf->get_pgcookie(mpf, &pgcookie_get) == 0);
+ CuAssert(ct, "check pgcookie size",
+ pgcookie_get.size == pgcookie_set.size);
+ CuAssert(ct, "check pgcookie data", memcmp(pgcookie_get.data,
+ pgcookie_set.data, pgcookie_set.size) == 0);
+
+ /* Test DB_MPOOLFILE->set_priority(), DB_MPOOLFILE->get_priority(). */
+ CHECK_1_DIGIT_VALUES(mpf, set_priority, get_priority, DB_CACHE_PRIORITY,
+ cache_priorities);
+
+ CuAssert(ct, "mpf->close", close_mp_handle(mpf) == 0);
+ CuAssert(ct, "dbenv->close", close_dbenv_handle(dbenv) == 0);
+ return (0);
+}
+
+int TestSequencePreOpenSetterAndGetter(CuTest *ct) {
+ DB_ENV *dbenv;
+ DB *dbp;
+ DB_SEQUENCE *seq;
+ u_int32_t seq_flags;
+
+ CuAssert(ct, "db_env_create", create_dbenv_handle(&dbenv) == 0);
+ CuAssert(ct, "dbenv->open", dbenv->open(dbenv,
+ TEST_ENV, DB_CREATE | DB_INIT_MPOOL, 0644) == 0);
+ CuAssert(ct, "db_create", create_db_handle(&dbp, dbenv) == 0);
+ CuAssert(ct, "dbp->open", dbp->open(dbp,
+ NULL, "seq.db", NULL, DB_BTREE, DB_CREATE, 0644) == 0);
+ CuAssert(ct, "db_sequence_create",
+ create_seq_handle(&seq, dbp) == 0);
+
+ /* Test DB_SEQUENCE->set_cachesize(), DB_SEQUENCE->get_cachesize(). */
+ CHECK_1_DIGIT_VALUE(seq, set_cachesize, get_cachesize,
+ u_int32_t, rand());
+
+ /* Test DB_SEQUENCE->set_flags(), DB_SEQUENCE->get_flags(). */
+ seq_flags = 0;
+ CHECK_1_DIGIT_VALUE(seq, set_flags, get_flags,
+ u_int32_t, DB_SEQ_DEC | DB_SEQ_WRAP);
+ /* We make sure the DB_SEQ_DEC is cleared if we set DB_SEQ_INC. */
+ CuAssert(ct, "seq->set_flags", seq->set_flags(seq, DB_SEQ_INC) == 0);
+ CuAssert(ct, "seq->get_flags", seq->get_flags(seq, &seq_flags) == 0);
+ CuAssert(ct, "check seq flags",
+ seq_flags == (DB_SEQ_INC | DB_SEQ_WRAP));
+
+ /*
+ * Test DB_SEQUENCE->set_range(), DB_SEQUENCE->get_range().
+ * The max should be bigger than min.
+ */
+ CHECK_2_DIGIT_VALUES(seq, set_range, get_range,
+ db_seq_t, 2, db_seq_t, 1048576);
+
+ CuAssert(ct, "seq->close", close_seq_handle(seq) == 0);
+ CuAssert(ct, "dbp->close", close_db_handle(dbp) == 0);
+ CuAssert(ct, "dbenv->close", close_dbenv_handle(dbenv) == 0);
+
+ return (0);
+}
+
+static int create_dbenv_handle(DB_ENV **dbenvpp) {
+ int ret;
+ if ((ret = db_env_create(dbenvpp, 0)) == 0)
+ info.dbenvp = *dbenvpp;
+ return ret;
+}
+
+static int close_dbenv_handle(DB_ENV *dbenvp) {
+ info.dbenvp = NULL;
+ return dbenvp->close(dbenvp, 0);
+}
+
+static int create_db_handle(DB **dbpp, DB_ENV *dbenvp) {
+ int ret;
+ if ((ret = db_create(dbpp, dbenvp, 0)) == 0)
+ info.dbp = *dbpp;
+ return ret;
+}
+
+static int close_db_handle(DB *dbp) {
+ info.dbp = NULL;
+ return dbp->close(dbp, 0);
+}
+
+static int create_mp_handle(DB_MPOOLFILE **mpp, DB_ENV *dbenv) {
+ int ret;
+ if ((ret = dbenv->memp_fcreate(dbenv, mpp, 0)) == 0)
+ info.mp = *mpp;
+ return ret;
+}
+
+static int close_mp_handle(DB_MPOOLFILE *mp) {
+ info.mp = NULL;
+ return mp->close(mp, 0);
+}
+
+static int create_seq_handle(DB_SEQUENCE **seqpp, DB *dbp) {
+ int ret;
+ if ((ret = db_sequence_create(seqpp, dbp, 0)) == 0)
+ info.seqp = *seqpp;
+ return ret;
+}
+
+static int close_seq_handle(DB_SEQUENCE *seqp) {
+ info.seqp = NULL;
+ return seqp->close(seqp, 0);
+}
+
+static int add_dirs_to_dbenv(DB_ENV *dbenv, const char **dirs) {
+ int ret;
+ const char *dir;
+
+ if (dirs == NULL)
+ return (0);
+
+ ret = 0;
+ while (ret == 0 && (dir = *dirs++) != NULL)
+ ret = dbenv->add_data_dir(dbenv, dir);
+ return ret;
+}
+
+/*
+ * Compare the directory list reprensented by dirs1 and dirs2.
+ * Both dirs1 and dirs2 use NULL pointer as terminator.
+ */
+static int cmp_dirs(const char **dirs1, const char **dirs2) {
+ int ret;
+ const char *dir1, *dir2;
+
+ if (dirs1 == NULL || *dirs1 == NULL) {
+ if (dirs2 == NULL || *dirs2 == NULL)
+ return (0);
+ else
+ return (-1);
+ } else if (dirs2 == NULL || *dirs2 == NULL)
+ return (1);
+
+ ret = 0;
+ while (ret == 0) {
+ dir1 = *dirs1++;
+ dir2 = *dirs2++;
+ if (dir1 == NULL || dir2 == NULL)
+ break;
+ ret = strcmp(dir1, dir2);
+ }
+ if (ret == 0) {
+ if (dir1 != NULL)
+ ret = 1;
+ else if (dir2 != NULL)
+ ret = -1;
+ }
+
+ return ret;
+}
+
diff --git a/test/c/suites/TestQueue.c b/test/c/suites/TestQueue.c
index 70f0209b..7343d751 100644
--- a/test/c/suites/TestQueue.c
+++ b/test/c/suites/TestQueue.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2002, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2015 Oracle and/or its affiliates. All rights reserved.
*
* A C test for the queue access method.
* TODO: Make this more consistent with the CuTest harness.
@@ -778,7 +778,8 @@ int TestQueue(CuTest *ct) {
}
if (!strcmp("sh_tailq", qfns[t].name)) {
result =
- sh_t_verify_TAILQ_LAST(list, ops[i].init);
+ sh_t_verify_TAILQ_LAST(
+ (struct sh_tq *)list, ops[i].init);
}
#ifdef VERBOSE
printf("\ncase %d %s in %s init: \"%s\" desired: \"%s\" elem: \"%s\" insert: \"%s\"\n",
@@ -814,8 +815,8 @@ int TestQueue(CuTest *ct) {
break;
}
if (!strcmp("sh_tailq", op_names[ops[i].op])) {
- result = sh_t_verify_TAILQ_LAST(list,
- ops[i].final);
+ result = sh_t_verify_TAILQ_LAST(
+ (struct sh_tq *)list, ops[i].final);
}
if (result == 0)
result = qfns[t].f_verify(list, ops[i].final);
diff --git a/test/c/test_api_methods.c b/test/c/test_api_methods.c
index 5998f556..8de7903e 100644
--- a/test/c/test_api_methods.c
+++ b/test/c/test_api_methods.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2002, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2015 Oracle and/or its affiliates. All rights reserved.
*/
#include <sys/types.h>
diff --git a/test/c/test_db185.c b/test/c/test_db185.c
index 8670028b..accf0b89 100644
--- a/test/c/test_db185.c
+++ b/test/c/test_db185.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2002, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2015 Oracle and/or its affiliates. All rights reserved.
*/
#include <sys/types.h>
diff --git a/test/c/test_failchk.c b/test/c/test_failchk.c
new file mode 100644
index 00000000..45f03e03
--- /dev/null
+++ b/test/c/test_failchk.c
@@ -0,0 +1,1078 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2014, 2015 Oracle and/or its affiliates. All rights reserved.
+ *
+ * $Id$
+ */
+
+#include <db_config.h>
+#include <db.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef _WIN32
+extern int getopt(int, char * const *, const char *);
+#else
+#include <unistd.h>
+#endif
+
+/* This BDB internal routine calls gettimeofday() or clock_gettime() or ... */
+void __os_gettime __P((const ENV *, struct timespec *, int));
+
+/* This exit status says "stop, look at the last run. something didn't work." */
+#define EXIT_TEST_ABORTED 101
+
+/*
+ * "Shut that bloody compiler up!"
+ *
+ * Unused, or not-used-yet variable. We need to write and then read the
+ * variable, some compilers are too bloody clever by half.
+ */
+#define COMPQUIET(n, v) do { \
+ (n) = (v); \
+ (n) = (n); \
+} while (0)
+#define UTIL_ANNOTATE_STRLEN 64 /* Length of argument to util_annotate(). */
+
+/*
+ * NB: This application is written using POSIX 1003.1b-1993 pthreads
+ * interfaces, which may not be portable to your system.
+ */
+extern int sched_yield __P((void)); /* Pthread yield function. */
+
+extern pthread_key_t TxnCommitMutex;
+
+int db_init __P((DB_ENV **, u_int32_t));
+void *deadlock __P((void *));
+void fatal __P((const char *, int));
+void onint __P((int));
+int main __P((int, char *[]));
+void notice_event __P((DB_ENV *, u_int32_t, void *));
+int reader __P((int));
+void stats __P((void));
+void *failchk __P((void *));
+int say_is_alive __P((DB_ENV *, pid_t, db_threadid_t, unsigned));
+void *trickle __P((void *));
+void *tstart __P((void *));
+int usage __P((const char *));
+const char *util_annotate __P((const DB_ENV *, char *, size_t));
+void util_errcall __P((const DB_ENV *, const char *, const char *));
+void util_msgcall __P((const DB_ENV *, const char *));
+void word __P((void));
+int writer __P((int));
+
+struct _statistics {
+ int aborted; /* Write. */
+ int aborts; /* Read/write. */
+ int adds; /* Write. */
+ int deletes; /* Write. */
+ int txns; /* Write. */
+ int found; /* Read. */
+ int notfound; /* Read. */
+} *perf;
+
+const char *Progname = "test_failchk"; /* Program name. */
+
+#define DATABASE "access.db" /* Database name. */
+#define WORDLIST "../test/tcl/wordlist" /* Dictionary. */
+
+/*
+ * We can seriously increase the number of collisions and transaction
+ * aborts by yielding the scheduler after every DB call. Specify the
+ * -p option to do this.
+ */
+time_t EndTime;
+int Duration = 60; /* -d <#seconds to run> */
+char *Home = "TESTDIR"; /* -h */
+int Punish; /* -p */
+int Nlist = 1000; /* -n */
+int Nreaders = 4; /* -r */
+int StatsInterval = 60; /* -s #seconds between printout of statistics */
+int TxnInterval = 1000; /* -t #txns between printout of txn progress */
+int Verbose; /* -v */
+int Nwriters = 4; /* -w */
+
+
+int ActiveThreads = 0;
+DB *Dbp; /* Database handle. */
+DB_ENV *DbEnv; /* Database environment. */
+int EnvOpenFlags = DB_CREATE | DB_THREAD | DB_REGISTER;
+int Failchk = 0; /* Failchk found a dead process. */
+char **List; /* Word list. */
+int MutexDied = 0; /* #threads that tripped on a dead mutex */
+int Nthreads; /* Total number of non-failchk threads. */
+int Quit = 0; /* Interrupt handling flag. */
+int PrintStats = 0; /* -S print all stats before exit. */
+
+/*
+ * test_failchk --
+ * Test failchk in a simple threaded application of some numbers of readers
+ * and writers competing to read and update a set of words.
+ * A typical test scenario runs this programs several times concurrently,
+ * with different options:
+ * first with the -I option to clear out any home directory
+ * one or more instances with -f to activate the failchk thread
+ * one or more instance with neither -I nor -f, as minimally
+ * involved workers.
+ *
+ *
+ *
+ *
+ * Example UNIX shell script to run this program:
+ * test_failchk -I & # recreates the home TESTDIR directory
+ * test_failchk & # read & write in testdir, expecting w
+ * test_failchk -f & # read & write & call faichk to notice crashes
+ * randomly kill a process, leaving at least one other to discover the crash
+ * with a DB_ENV->failchk() call, which then allows the other processes
+ */
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int errno, optind;
+ DB_TXN *txnp;
+ pthread_t *tids;
+ sig_t sig;
+ int ch, do_failchk, i, init, pid, ret;
+ char syscmd[100];
+ void *retp;
+
+ setlinebuf(stdout);
+ setlinebuf(stderr);
+ txnp = NULL;
+ do_failchk = init = 0;
+ pid = getpid();
+ while ((ch = getopt(argc, argv, "d:fh:Ipn:Rr:Ss:t:vw:x")) != EOF)
+ switch (ch) {
+ case 'd':
+ if ((Duration = atoi(optarg)) <= 0)
+ return (usage("-d <duration> must be >= 0"));
+ break;
+ case 'f':
+ do_failchk = 1;
+ break;
+ case 'h':
+ Home = optarg;
+ break;
+ case 'I':
+ init = 1;
+ break;
+ case 'n':
+ Nlist = atoi(optarg);
+ break;
+ case 'p':
+ Punish = 1;
+ break;
+ case 'R':
+ EnvOpenFlags &= ~DB_REGISTER;
+ break;
+ case 'r':
+ if ((Nreaders = atoi(optarg)) < 0)
+ return (usage("-r <readers> may not be <0"));
+ break;
+ case 'S':
+ PrintStats = 1;
+ break;
+ case 's':
+ if ((StatsInterval = atoi(optarg)) <= 0)
+ return (usage("-s <seconds> must be positive"));
+ break;
+ case 't':
+ if ((TxnInterval = atoi(optarg)) <= 0)
+ return (usage("-t <#txn> must be positive"));
+ break;
+ case 'v':
+ Verbose = 1;
+ break;
+ case 'w':
+ if ((Nwriters = atoi(optarg)) < 0)
+ return (usage("-r <writers> may not be <0"));
+ break;
+ case 'x':
+ EnvOpenFlags |= DB_RECOVER;
+ break;
+ case '?':
+ default:
+ return (usage("unknown option"));
+ }
+ printf("Running %d: %s ", pid, argv[0]);
+ for (i = 1; i != argc; i++)
+ printf("%s ", argv[i]);
+ printf("\n");
+ argc -= optind;
+ argv += optind;
+
+ if (init) {
+ /* Prevent accidentally rm -rf of a full path, etc. */
+ if (Home[0] == '/' || Home[0] == '.')
+ return (usage("-I accepts only local path names (prevents rm -r /...)"));
+ snprintf(syscmd, sizeof(syscmd),
+ "rm -rf %s ; mkdir %s", Home, Home);
+ printf("Clearing out env with \"%s\"\n", syscmd);
+ if ((ret = system(syscmd)) != 0) {
+ fatal(syscmd, errno);
+ /* NOTREACHED */
+ return (EXIT_TEST_ABORTED);
+ }
+ }
+ if (Nreaders + Nwriters == 0 && !do_failchk)
+ usage("Nothing specified to do?");
+
+ srand(pid | time(NULL));
+
+ /*
+ * Close down the env cleanly on an interrupt, except when running in
+ * the background. Catch SIGTERM to exit with a distinctive status.
+ */
+ if ((sig = signal(SIGINT, onint)) != SIG_DFL)
+ (void)signal(SIGINT, sig);
+ (void)signal(SIGTERM, onint);
+
+ /* Build the key list. */
+ word();
+
+ /* Set when this run will end, if not interrupted. */
+ if (StatsInterval > Duration)
+ StatsInterval = Duration;
+ time(&EndTime);
+ EndTime += Duration;
+
+ /* Initialize the database environment. */
+ if ((ret = db_init(&DbEnv, EnvOpenFlags)) != 0)
+ return (ret);
+ EnvOpenFlags &= ~DB_RECOVER;
+
+ /*
+ * Create thread ID structures. It starts with the readers and writers,
+ * then the trickle, deadlock and possibly failchk threads.
+ */
+ Nthreads = Nreaders + Nwriters + 2;
+ if ((tids = malloc((Nthreads + do_failchk) * sizeof(pthread_t))) == NULL)
+ fatal("malloc threads", errno);
+
+ /*
+ * Create failchk thread first; it might be needed during db_create.
+ * Put it at the end of the threads array, so that in doesn't get in
+ * the way of the worker threads.
+ */
+ if (do_failchk &&
+ (ret = pthread_create(&tids[Nthreads], NULL, failchk, &i)) != 0)
+ fatal("pthread_create failchk", errno);
+
+ /* Initialize the database. */
+ if ((ret = db_create(&Dbp, DbEnv, 0)) != 0) {
+ DbEnv->err(DbEnv, ret, "db_create");
+ (void)DbEnv->close(DbEnv, 0);
+ return (EXIT_TEST_ABORTED);
+ }
+ if ((ret = Dbp->set_pagesize(Dbp, 1024)) != 0) {
+ Dbp->err(Dbp, ret, "set_pagesize");
+ goto err;
+ }
+
+ if ((ret = DbEnv->txn_begin(DbEnv, NULL, &txnp, 0)) != 0)
+ fatal("txn_begin", ret);
+ if ((ret = Dbp->open(Dbp, txnp,
+ DATABASE, NULL, DB_BTREE, DB_CREATE | DB_THREAD, 0664)) != 0) {
+ Dbp->err(Dbp, ret, "%s: open", DATABASE);
+ goto err;
+ } else {
+ ret = txnp->commit(txnp, 0);
+ txnp = NULL;
+ if (ret != 0)
+ goto err;
+ }
+
+ ActiveThreads = Nthreads;
+
+ /* Create statistics structures, offset by 1. */
+ if ((perf = calloc(Nreaders + Nwriters + 1, sizeof(*perf))) == NULL)
+ fatal("calloc statistics", errno);
+
+ /* Create reader/writer threads. */
+ for (i = 0; i < Nreaders + Nwriters; ++i)
+ if ((ret = pthread_create(
+ &tids[i], NULL, tstart, (void *)(uintptr_t)i)) != 0)
+ fatal("pthread_create", ret > 0 ? ret : errno);
+
+ /* Create buffer pool trickle thread. */
+ if (pthread_create(&tids[i], NULL, trickle, &i))
+ fatal("pthread_create trickle thread", errno);
+ ++i;
+
+ /* Create deadlock detector thread. */
+ if (pthread_create(&tids[i], NULL, deadlock, &i))
+ fatal("pthread_create deadlock thread", errno);
+ ++i;
+
+ /* Wait for the worker, trickle and deadlock threads. */
+ for (i = 0; i < Nthreads; ++i) {
+ printf("joining thread %d...\n", i);
+ if ((ret = pthread_join(tids[i], &retp)) != 0)
+ fatal("pthread_join", ret);
+ ActiveThreads--;
+ printf("join thread %d done, %d left\n", i, ActiveThreads);
+ }
+
+ printf("Exiting\n");
+ stats();
+
+ if (!Failchk) {
+err: if (txnp != NULL)
+ ret = txnp->abort(txnp);
+ if (ret == 0 && Dbp != NULL)
+ ret = Dbp->close(Dbp, 0);
+ if (PrintStats)
+ DbEnv->stat_print(DbEnv,
+ DB_STAT_SUBSYSTEM | DB_STAT_ALL);
+ if (ret == 0 && DbEnv != NULL)
+ ret = DbEnv->close(DbEnv, 0);
+ }
+
+ return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+int
+reader(id)
+ int id;
+{
+ DBT key, data;
+ int n, ret;
+ char buf[100];
+
+ /*
+ * DBT's must use local memory or malloc'd memory if the DB handle
+ * is accessed in a threaded fashion.
+ */
+ memset(&key, 0, sizeof(DBT));
+ memset(&data, 0, sizeof(DBT));
+ data.flags = DB_DBT_MALLOC;
+
+ /*
+ * Read-only threads do not require transaction protection, unless
+ * there's a need for repeatable reads.
+ */
+ while (!Quit) {
+ /* Pick a key at random, and look it up. */
+ n = rand() % Nlist;
+ key.data = List[n];
+ key.size = strlen(key.data);
+
+ if (Verbose)
+ DbEnv->errx(DbEnv, "reader: %d: list entry %d", id, n);
+
+ switch (ret = Dbp->get(Dbp, NULL, &key, &data, 0)) {
+ case DB_LOCK_DEADLOCK: /* Deadlock. */
+ ++perf[id].aborts;
+ break;
+ case 0: /* Success. */
+ ++perf[id].found;
+ free(data.data);
+ break;
+ case DB_NOTFOUND: /* Not found. */
+ ++perf[id].notfound;
+ break;
+ default:
+ sprintf(buf, "reader %d: dbp->get of %s",
+ id, (char *)key.data);
+ fatal(buf, ret);
+ }
+ }
+ return (0);
+}
+
+int
+writer(id)
+ int id;
+{
+ DBT key, data;
+ DB_TXN *tid;
+ int n, ret;
+ char buf[100], dbuf[10000];
+
+
+ /*
+ * DBT's must use local memory or malloc'd memory if the DB handle
+ * is accessed in a threaded fashion.
+ */
+ memset(&key, 0, sizeof(DBT));
+ memset(&data, 0, sizeof(DBT));
+ data.data = dbuf;
+ data.ulen = sizeof(dbuf);
+ data.flags = DB_DBT_USERMEM;
+
+ while (!Quit) {
+ /* Pick a random key. */
+ n = rand() % Nlist;
+ key.data = List[n];
+ key.size = strlen(key.data);
+
+ if (Verbose)
+ DbEnv->errx(DbEnv, "writer: %d: list entry %d", id, n);
+
+ /* Abort and retry. */
+ if (0) {
+retry: if ((ret = tid->abort(tid)) != 0)
+ fatal("DB_TXN->abort", ret);
+ ++perf[id].aborts;
+ ++perf[id].aborted;
+ }
+
+ /* Begin the transaction. */
+ if ((ret = DbEnv->txn_begin(DbEnv, NULL, &tid, 0)) != 0)
+ fatal("txn_begin", ret);
+
+ /*
+ * Get the key. If it doesn't exist, add it. If it does
+ * exist, delete it.
+ */
+ switch (ret = Dbp->get(Dbp, tid, &key, &data, 0)) {
+ case DB_LOCK_DEADLOCK:
+ goto retry;
+ case 0:
+ goto delete;
+ case DB_NOTFOUND:
+ goto add;
+ default:
+ snprintf(buf, sizeof(buf),
+ "writer %d: put %s", id, (char *)key.data);
+ fatal(buf, ret);
+ /* NOTREACHED */
+ }
+
+delete: /* Delete the key. */
+ switch (ret = Dbp->del(Dbp, tid, &key, 0)) {
+ case DB_LOCK_DEADLOCK:
+ goto retry;
+ case 0:
+ ++perf[id].deletes;
+ goto commit;
+ }
+
+ snprintf(buf, sizeof(buf), "writer: %d: dbp->del", id);
+ fatal(buf, ret);
+ /* NOTREACHED */
+
+add: /* Add the key. 1 data item in 30 is an overflow item. */
+ data.size = 20 + rand() % 128;
+ if (rand() % 30 == 0)
+ data.size += 8192;
+
+ switch (ret = Dbp->put(Dbp, tid, &key, &data, 0)) {
+ case DB_LOCK_DEADLOCK:
+ goto retry;
+ case 0:
+ ++perf[id].adds;
+ goto commit;
+ default:
+ snprintf(buf, sizeof(buf), "writer: %d: dbp->put", id);
+ fatal(buf, ret);
+ }
+
+commit: /* The transaction finished, commit it. */
+ if ((ret = tid->commit(tid, 0)) != 0)
+ fatal("DB_TXN->commit", ret);
+
+ /*
+ * Every time the thread completes many transactions, show
+ * our progress.
+ */
+ if (++perf[id].txns % TxnInterval == 0) {
+ DbEnv->errx(DbEnv,
+"writer: %2d: adds: %4d: deletes: %4d: aborts: %4d: txns: %4d",
+ id, perf[id].adds, perf[id].deletes,
+ perf[id].aborts, perf[id].txns);
+ }
+
+ /*
+ * If this thread was aborted more than 5 times before
+ * the transaction finished, complain.
+ */
+ if (perf[id].aborted > 5) {
+ DbEnv->errx(DbEnv,
+"writer: %2d: adds: %4d: deletes: %4d: aborts: %4d: txns: %4d: ABORTED: %2d",
+ id, perf[id].adds, perf[id].deletes,
+ perf[id].aborts, perf[id].txns, perf[id].aborted);
+ }
+ perf[id].aborted = 0;
+ }
+ return (0);
+}
+
+/*
+ * stats --
+ * Display reader/writer thread statistics. To display the statistics
+ * for the mpool trickle or deadlock threads, use db_stat(1).
+ */
+void
+stats()
+{
+ int id;
+ char *p, buf[8192];
+
+ p = buf + sprintf(buf, "-------------\n");
+ for (id = 0; id < Nreaders + Nwriters;)
+ if (id++ < Nwriters)
+ p += sprintf(p,
+ "writer: %2d: adds: %4d: deletes: %4d: aborts: %4d: txns: %4d\n",
+ id, perf[id].adds,
+ perf[id].deletes, perf[id].aborts, perf[id].txns);
+ else
+ p += sprintf(p,
+ "reader: %2d: found: %5d: notfound: %5d: aborts: %4d\n",
+ id, perf[id].found,
+ perf[id].notfound, perf[id].aborts);
+ p += sprintf(p, "-------------\n");
+
+ printf("%s", buf);
+}
+
+/*
+ * util_annotate -
+ * Obtain timestamp, thread id, etc; prepend to messages.
+ */
+const char *
+util_annotate(dbenv, header, header_size)
+ const DB_ENV *dbenv;
+ char *header;
+ size_t header_size;
+{
+ struct timespec now;
+ db_threadid_t tid;
+ pid_t pid;
+#ifdef HAVE_STRFTIME
+ struct tm *tm_p;
+#ifdef HAVE_LOCALTIME_R
+ struct tm tm;
+#endif
+#endif
+ char idstr[DB_THREADID_STRLEN], tmstr[20];
+
+ if (dbenv == NULL) {
+ snprintf(idstr, sizeof(idstr),
+ "Pid/tid %d:%p", getpid(), (void *)pthread_self());
+ }
+ else {
+ dbenv->thread_id((DB_ENV *)dbenv, &pid, &tid);
+ (void)dbenv->thread_id_string((DB_ENV *)dbenv, pid, tid, idstr);
+ }
+
+ __os_gettime(dbenv == NULL ? NULL : dbenv->env, &now, 0);
+ /* Print the time readably if possible; else print seconds. */
+#ifdef HAVE_STRFTIME
+#ifdef HAVE_LOCALTIME_R
+ tm_p = localtime_r(&now.tv_sec, &tm);
+#else
+ tm_p = localtime(&now.tv_sec);
+#endif
+ if (tm_p != NULL)
+ (void)strftime(tmstr, sizeof(tmstr), "%H:%M:%S", tm_p);
+ else
+#endif
+ (void)snprintf(tmstr, sizeof(tmstr), "%lu", (u_long)now.tv_sec);
+ (void)snprintf(header, header_size, "%s.%06lu[%s]: ",
+ tmstr, (u_long)(now.tv_nsec / 1000), idstr);
+
+ return (header);
+}
+
+/*
+ * util_errcall -
+ * Annotate error messages with timestamp and thread id, + ???
+ */
+void
+util_errcall(dbenv, errpfx, msg)
+ const DB_ENV *dbenv;
+ const char *errpfx;
+ const char *msg;
+{
+ char header[UTIL_ANNOTATE_STRLEN];
+
+ util_annotate(dbenv, header, sizeof(header));
+ if (errpfx == NULL)
+ errpfx = "";
+ fprintf(stderr, "%s%s%s\n", header, errpfx, msg);
+ fflush(stderr);
+}
+
+/*
+ * util_msgcall -
+ * Annotate messages with timestamp and thread id, + ???
+ */
+void
+util_msgcall(dbenv, msg)
+ const DB_ENV *dbenv;
+ const char *msg;
+{
+ char header[UTIL_ANNOTATE_STRLEN];
+
+ util_annotate(dbenv, header, sizeof(header));
+ fprintf(stderr, "%s%s\n", header, msg);
+ fflush(stderr);
+}
+
+/*
+ * db_init --
+ * Initialize a TDS environment with failchk, running recovery if needed.
+ * The caller specifies additional flags such as:
+ * DB_THREAD | DB_CREATE | DB_REGISTER
+ */
+int
+db_init(dbenvp, flags)
+ DB_ENV **dbenvp;
+ u_int32_t flags;
+{
+ DB_ENV *dbenv;
+ int ret;
+
+ dbenv = *dbenvp;
+retry:
+ if (dbenv != NULL) {
+ dbenv->errx(dbenv, "Closing existing environment");
+ *dbenvp = NULL;
+ (void)dbenv->close(dbenv, 0);
+ }
+ if ((ret = db_env_create(&dbenv, 0)) != 0) {
+ fprintf(stderr,
+ "%s: db_env_create: %s\n", Progname, db_strerror(ret));
+ return (EXIT_TEST_ABORTED);
+ }
+ (void)dbenv->set_event_notify(dbenv, notice_event);
+ if (Punish)
+ (void)dbenv->set_flags(dbenv, DB_YIELDCPU, 1);
+
+ /* Use errcall and msgcall functions to include threadid, timestamp. */
+ (void)dbenv->set_errcall(dbenv, util_errcall);
+ (void)dbenv->set_msgcall(dbenv, util_msgcall);
+
+ /* Set a tiny cache. */
+ (void)dbenv->set_cachesize(dbenv, 0, 100 * 1024, 0);
+ (void)dbenv->set_lg_max(dbenv, 200000);
+ (void)dbenv->set_verbose(dbenv, DB_VERB_RECOVERY, 1);
+ (void)dbenv->set_verbose(dbenv, DB_VERB_REGISTER, 1);
+ (void)dbenv->set_verbose(dbenv, DB_VERB_FILEOPS, 1);
+ (void)dbenv->set_verbose(dbenv, DB_VERB_FILEOPS_ALL, 1);
+ (void)dbenv->set_isalive(dbenv, say_is_alive);
+ (void)dbenv->set_thread_count(dbenv, 100);
+
+ flags |= DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN |
+ DB_FAILCHK;
+ if ((ret = dbenv->open(dbenv, Home, flags, 0)) == DB_RUNRECOVERY &&
+ !(flags & DB_RECOVER)) {
+ dbenv->errx(dbenv, "About to run recovery in %s", Home);
+ flags |= DB_RECOVER;
+ goto retry;
+ }
+ if (ret != 0) {
+ dbenv->err(dbenv, ret, "Could not open environment in %s", Home);
+ *dbenvp = NULL;
+ (void)dbenv->close(dbenv, 0);
+ return (EXIT_TEST_ABORTED);
+ }
+ if (flags & DB_RECOVER && !(flags & DB_REGISTER)) {
+ DB_TXN_STAT *txn_stat;
+ if ((ret = dbenv->txn_stat(dbenv, &txn_stat, 0)) != 0)
+ fatal("txn_stat after recovery failed", ret);
+ if (txn_stat->st_nbegins != 0)
+ fatal("txn_stat found txns, did recovery run?", 0);
+ free(txn_stat);
+ }
+ *dbenvp = dbenv;
+ dbenv->errx(dbenv, "Opened environment in %s", Home);
+ if (!Verbose) {
+ (void)dbenv->set_verbose(dbenv, DB_VERB_RECOVERY, 0);
+ (void)dbenv->set_verbose(dbenv, DB_VERB_REGISTER, 0);
+ (void)dbenv->set_verbose(dbenv, DB_VERB_FILEOPS, 0);
+ (void)dbenv->set_verbose(dbenv, DB_VERB_FILEOPS_ALL, 0);
+ }
+ return (0);
+}
+
+/*
+ * tstart --
+ * Thread start function for readers and writers.
+ */
+void *
+tstart(arg)
+ void *arg;
+{
+ pthread_t tid;
+ u_int id;
+
+ id = (uintptr_t)arg + 1;
+
+ tid = pthread_self();
+
+ if (id <= (u_int)Nwriters) {
+ printf("write thread %d starting: tid: %lx\n", id, (u_long)tid);
+ fflush(stdout);
+ writer(id);
+ } else {
+ printf("read thread %d starting: tid: %lx\n", id, (u_long)tid);
+ fflush(stdout);
+ reader(id);
+ }
+
+ /* NOTREACHED */
+ return (NULL);
+}
+
+/*
+ * deadlock --
+ * Thread start function for DB_ENV->lock_detect.
+ */
+void *
+deadlock(arg)
+ void *arg;
+{
+ struct timeval t;
+ pthread_t tid;
+ int err;
+
+ tid = pthread_self();
+
+ printf("deadlock thread starting: tid: %lx\n", (u_long)tid);
+ fflush(stdout);
+
+ t.tv_sec = 0;
+ t.tv_usec = 100000;
+ while (!Quit) {
+ err = DbEnv->lock_detect(DbEnv, 0, DB_LOCK_YOUNGEST, NULL);
+ if (err != 0) {
+ DbEnv->err(DbEnv, err, "lock_detect failed");
+ break;
+ }
+
+ /* Check every 100ms. */
+ (void)select(0, NULL, NULL, NULL, &t);
+ }
+
+ printf("%d deadlock thread exiting\n", getpid());
+ COMPQUIET(arg, NULL);
+ return (NULL);
+}
+
+/*
+ * trickle --
+ * Thread start function for memp_trickle.
+ */
+void *
+trickle(arg)
+ void *arg;
+{
+ pthread_t tid;
+ time_t now, then;
+ int err, wrote;
+
+ time(&now);
+ then = now;
+ tid = pthread_self();
+
+ printf("trickle thread starting: tid: %lx\n", (u_long)tid);
+ fflush(stdout);
+
+ while (!Quit) {
+ err = DbEnv->memp_trickle(DbEnv, 10, &wrote);
+ if (err != 0) {
+ DbEnv->err(DbEnv, err, "trickle failed");
+ break;
+ }
+ if (Verbose)
+ fprintf(stderr, "trickle: wrote %d\n", wrote);
+
+ /*
+ * The trickle thread prints statistics every few seconds.
+ * It also checks whether it is time to quit.
+ */
+ time(&now);
+ if (now - then >= StatsInterval) {
+ stats();
+ then = now;
+ if (now > EndTime) {
+ printf("trickle: ending time reached @ %s",
+ ctime(&now));
+ Quit = 1;
+ }
+ }
+ if (wrote == 0) {
+ sleep(1);
+ sched_yield();
+ }
+ }
+ printf("%d trickle thread exiting\n", getpid());
+
+ COMPQUIET(arg, NULL);
+ return (NULL);
+}
+
+/*
+ * failchk --
+ * Thread start function for failchk.
+ */
+void *
+failchk(arg)
+ void *arg;
+{
+ DB_ENV *failenv;
+ pthread_t tid;
+ time_t now;
+ int err;
+
+ tid = pthread_self();
+ failenv = NULL;
+
+ if (db_init(&failenv, 0) != 0) {
+ fprintf(stderr, "failchk: environment open failed!\n");
+ exit(EXIT_TEST_ABORTED);
+ }
+ (void)failenv->set_errpfx(failenv, "(failchk) ");
+
+ failenv->errx(failenv, "starting tid: %lx\n", (u_long)tid);
+
+ while (!Quit) {
+ if ((err = failenv->failchk(failenv, 0)) != 0) {
+ Failchk = 1;
+ failenv->err(failenv, err, "failchk() returned");
+ system("db_stat -Neh TESTDIR|egrep 'Creation|Failure'");
+ /*
+ * Tell all threads to quit, then check that
+ * the environment can be reopened.
+ */
+ Quit = 1;
+ if (0) {
+ do {
+ sleep(10);
+ if ((err = failenv->failchk(failenv, 0)) != 0)
+ failenv->err(failenv, err,
+ "redo failchk with %d left returns",
+ ActiveThreads);
+ } while (ActiveThreads > 0);
+ fprintf(stderr,
+ "failchk: reopening %s with recovery\n", Home);
+ (void)db_init(&failenv, DB_RECOVER);
+ fprintf(stderr, "failchk: reopened %s\n", Home);
+ }
+ system("db_stat -eh TESTDIR | egrep 'Creat|Failure'");
+ fprintf(stderr, "failchk thread exiting\n");
+ exit(0);
+ }
+ sleep(1);
+ }
+
+ (void)failenv->close(failenv, 0);
+ now = time(NULL);
+ printf("failchk() thread returning @ %s", ctime(&now));
+
+ COMPQUIET(arg, NULL);
+ return (NULL);
+}
+
+/*
+ * word --
+ * Build the dictionary word list
+ */
+void
+word()
+{
+ FILE *fp;
+ int cnt;
+ char buf[256], *nl;
+
+ if ((fp = fopen(WORDLIST, "r")) == NULL)
+ fatal(WORDLIST, errno);
+
+ if ((List = malloc(Nlist * sizeof(char *))) == NULL)
+ fatal("malloc word list", errno);
+
+ for (cnt = 0; cnt < Nlist; ++cnt) {
+ if (fgets(buf, sizeof(buf), fp) == NULL)
+ break;
+ /* Newlines in the data make for confusing messages. */
+ if ((nl = strrchr(buf, '\n')) != NULL)
+ *nl = '\0';
+ if ((List[cnt] = strdup(buf)) == NULL)
+ fatal("strdup word", errno);
+ }
+ Nlist = cnt; /* In case nlist was larger than the word list. */
+}
+
+/*
+ * fatal --
+ * Report a fatal error and quit.
+ */
+void
+fatal(msg, err)
+ const char *msg;
+ int err;
+{
+ char buf[1000];
+ char header[UTIL_ANNOTATE_STRLEN];
+ int ret;
+
+ snprintf(buf, sizeof(buf), "pid %d %s: %s", getpid(), Progname, msg);
+ if (err != 0)
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ": %s%s",
+ db_strerror(err), MutexDied > 0 ?
+ " after seeing DB_EVENT_MUTEX_DIED" :
+ (Failchk > 0 ? "after seeing a failchk panic" : ""));
+ /* fatal errors are 'ok' if a failchk-detected panic has occurred. */
+ ret = (Failchk == 0 && MutexDied == 0 ? EXIT_TEST_ABORTED : EXIT_FAILURE);
+ util_annotate(NULL, header, sizeof(header));
+ fprintf(stderr, "%s%s\n", header, buf);
+
+ exit(ret);
+
+ /* NOTREACHED */
+}
+
+/*
+ * usage --
+ * Usage message.
+ */
+int
+usage(msg)
+ const char *msg;
+{
+ (void)fprintf(stderr,
+ "usage: %s "
+ "[-p<Punish>] [-v<Verbose>] [-R<avoid DB_REGISTER>] [-f<run a failchk thread>] [-I <initialize>] [-x <always recover>]\n\t"
+ "[-d <duration(%d seconds)]\n\t"
+ "[-h <home(%s)>]\n\t"
+ "[-n <words(%d)>]\n\t"
+ "[-r <#readers %d>]\n\t"
+ "[-s <statistics interval>]\n\t"
+ "[-t <txn progress interval>]\n\t"
+ "[-w <#writers %d>]\n\t%s\n",
+ Progname, Duration, Home, Nlist, Nreaders, Nwriters, msg);
+ return (EXIT_TEST_ABORTED);
+}
+
+/*
+ * onint --
+ * Interrupt signal handler.
+ */
+void
+onint(signo)
+ int signo;
+{
+ Quit = 1;
+ fflush(stdout);
+ printf("pid %d sees signal %d\n", getpid(), signo);
+ if (signo == SIGTERM) {
+ printf("pid %d exiting due to SIGTERM\n", getpid());
+ exit(EXIT_FAILURE + 1);
+ }
+}
+
+/*
+ * notice_event --
+ * Display the details of events.
+ */
+void notice_event(dbenv, event, info)
+ DB_ENV *dbenv;
+ u_int32_t event;
+ void *info;
+{
+#ifdef DB_EVENT_MUTEX_DIED
+ DB_EVENT_MUTEX_DIED_INFO *mtxdied;
+#endif
+#ifdef DB_EVENT_FAILCHK_PANIC
+ DB_EVENT_FAILCHK_INFO *crashed;
+#endif
+ switch (event) {
+ case DB_EVENT_PANIC:
+ dbenv->err(dbenv, *(int *)info, "Notification: panic");
+ break;
+ case DB_EVENT_REG_ALIVE:
+ dbenv->errx(dbenv, "DB_EVENT_REG_ALIVE pid %lu is still alive.",
+ (u_long)(*(pid_t *)info));
+ break;
+ case DB_EVENT_REG_PANIC:
+ dbenv->err(dbenv, *(int *)info, "Notification: register panic");
+ break;
+#ifdef DB_EVENT_MUTEX_DIED
+ case DB_EVENT_MUTEX_DIED:
+ mtxdied = info;
+ dbenv->errx(dbenv, "Notification: dead mutex: %.*s",
+ sizeof(mtxdied->desc), mtxdied->desc);
+ MutexDied++;
+ break;
+#endif
+#ifdef DB_EVENT_FAILCHK_PANIC
+ case DB_EVENT_FAILCHK_PANIC:
+ crashed = info;
+ dbenv->errx(dbenv, "Notification: panic \"%s\" after: %s",
+ db_strerror(crashed->error), crashed->symptom);
+ Failchk++;
+ break;
+#endif
+ default:
+ dbenv->errx(dbenv, "Event %u info %p", event, info);
+ break;
+ }
+}
+
+/*
+ * say_is_alive - failchk is_alive function
+ *
+ * Return 1 if the pid is alive, else 0 (dead).
+ *
+ * We are alive, so is our parent and any other process to which we can
+ * send a null signal (*IX) or get info about (Win32). Posix doesn't provide
+ * a true way to detect whether another process' threads are active.
+ */
+int
+say_is_alive(dbenv, pid, tid, flags)
+ DB_ENV *dbenv;
+ pid_t pid;
+ db_threadid_t tid;
+ u_int32_t flags;
+{
+#ifdef DB_WIN32
+ HANDLE proc;
+ LONG exitCode;
+ int still_active;
+#else
+ int ret;
+#endif
+
+#ifdef DB_WIN32
+ /* OpenProcess() may return a handle to a dead process, so check
+ * whether the process exists as well as whether it has just
+ * recently exited. This fails to detect processes that
+ * explicitly return STILL_ACTIVE as its exit status.
+ */
+ if ((proc = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid)) != 0) {
+ still_active = GetExitCodeProcess(proc, &exitCode) != 0 &&
+ exitCode == STILL_ACTIVE;
+ CloseHandle(proc);
+ if (still_active)
+ return (1);
+ }
+#else
+ /* Self, parent, and processes findable by kill are alive. */
+ if (pid == getpid() || pid == getppid() ||
+ kill(pid, 0) == 0 || (ret = errno) != ESRCH)
+ return (1);
+ ret = errno;
+#endif
+ dbenv->err(dbenv, ret, "is-alive probe for pid %d", pid);
+ COMPQUIET(dbenv, NULL);
+ COMPQUIET(tid, 0);
+ COMPQUIET(flags, 0);
+
+ return (0);
+}
+
diff --git a/test/c/test_log_verify.c b/test/c/test_log_verify.c
index 2fac4ee5..e9338d42 100644
--- a/test/c/test_log_verify.c
+++ b/test/c/test_log_verify.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2009, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*/