summaryrefslogtreecommitdiff
path: root/qpid/cpp/src/tests/legacystore/jrnl
diff options
context:
space:
mode:
authorRobert Gemmell <robbie@apache.org>2015-06-25 10:22:51 +0000
committerRobert Gemmell <robbie@apache.org>2015-06-25 10:22:51 +0000
commit32ae758bc2e8fd962b66a4ab6341b14009f1907e (patch)
tree2f4d8174813284a6ea58bb6b7f6520aa92287476 /qpid/cpp/src/tests/legacystore/jrnl
parent116d91ad7825a98af36a869fc751206fbce0c59f (diff)
parentf7e896076143de4572b4f1f67ef0765125f2498d (diff)
downloadqpid-python-32ae758bc2e8fd962b66a4ab6341b14009f1907e.tar.gz
NO-JIRA: create branch for qpid-cpp 0.34 RC process
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/qpid-cpp-0.34-rc@1687469 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/cpp/src/tests/legacystore/jrnl')
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/_st_auto_expand.cpp140
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/_st_basic.cpp558
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/_st_basic_txn.cpp239
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/_st_helper_fns.h882
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/_st_read.cpp460
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/_st_read_txn.cpp353
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/_ut_enq_map.cpp320
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/_ut_jdir.cpp416
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/_ut_jerrno.cpp47
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/_ut_jexception.cpp346
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/_ut_jinf.cpp402
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/_ut_lpmgr.cpp886
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/_ut_rec_hdr.cpp438
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/_ut_time_ns.cpp163
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/_ut_txn_map.cpp106
-rwxr-xr-xqpid/cpp/src/tests/legacystore/jrnl/chk_jdata32
-rwxr-xr-xqpid/cpp/src/tests/legacystore/jrnl/cp_rtest_jrnl59
-rwxr-xr-xqpid/cpp/src/tests/legacystore/jrnl/jhexdump41
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_data_src.cpp207
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_jrnl_init_params.cpp100
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_jrnl_instance.cpp178
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_read_arg.cpp146
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case.cpp113
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case_result.cpp206
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case_result_agregation.cpp178
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case_set.cpp147
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case_set.csv74
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/args.cpp226
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/args.h66
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/data_src.cpp87
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/data_src.h66
-rwxr-xr-xqpid/cpp/src/tests/legacystore/jrnl/jtt/jfile_chk.py838
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/jrnl_init_params.cpp77
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/jrnl_init_params.h80
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/jrnl_instance.cpp439
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/jrnl_instance.h121
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/jtt.csv234
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/main.cpp57
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/read_arg.cpp93
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/read_arg.h62
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case.cpp179
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case.h110
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_result.cpp201
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_result.h100
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_result_agregation.cpp185
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_result_agregation.h81
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_set.cpp169
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_set.h99
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/test_mgr.cpp218
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/jtt/test_mgr.h68
-rwxr-xr-xqpid/cpp/src/tests/legacystore/jrnl/prof32
-rwxr-xr-xqpid/cpp/src/tests/legacystore/jrnl/run-journal-tests47
-rw-r--r--qpid/cpp/src/tests/legacystore/jrnl/tests.odsbin0 -> 91064 bytes
53 files changed, 11172 insertions, 0 deletions
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/_st_auto_expand.cpp b/qpid/cpp/src/tests/legacystore/jrnl/_st_auto_expand.cpp
new file mode 100644
index 0000000000..fb5c1f1742
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/_st_auto_expand.cpp
@@ -0,0 +1,140 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../unit_test.h"
+#include <cmath>
+#include <iostream>
+#include "qpid/legacystore/jrnl/jcntl.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(journal_auto_expand)
+
+const string test_filename("_st_auto_expand");
+
+#include "_st_helper_fns.h"
+
+// === Test suite ===
+
+QPID_AUTO_TEST_CASE(no_ae_threshold)
+{
+ string test_name = get_test_name(test_filename, "no_ae_threshold");
+ try
+ {
+ string msg;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_DEFAULT_JFILES, false, 0, DEFAULT_JFSIZE_SBLKS);
+ unsigned m;
+
+ // Fill journal to just below threshold
+ u_int32_t t = num_msgs_to_threshold(NUM_DEFAULT_JFILES,
+ DEFAULT_JFSIZE_SBLKS * JRNL_SBLK_SIZE, LARGE_MSG_REC_SIZE_DBLKS);
+ for (m=0; m<t; m++)
+ enq_msg(jc, m, create_msg(msg, m, LARGE_MSG_SIZE), false);
+ // This enqueue should exceed the threshold
+ BOOST_CHECK_EQUAL(jc.get_enq_cnt(), t);
+ enq_msg(jc, m, create_msg(msg, m, LARGE_MSG_SIZE), false, RHM_IORES_ENQCAPTHRESH);
+ BOOST_CHECK_EQUAL(jc.get_enq_cnt(), t);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(no_ae_threshold_dequeue_some)
+{
+ string test_name = get_test_name(test_filename, "no_ae_threshold_dequeue_some");
+ try
+ {
+ string msg;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_DEFAULT_JFILES, false, 0, DEFAULT_JFSIZE_SBLKS);
+ unsigned m;
+
+ // Fill journal to just below threshold
+ u_int32_t t = num_msgs_to_threshold(NUM_DEFAULT_JFILES,
+ DEFAULT_JFSIZE_SBLKS * JRNL_SBLK_SIZE, LARGE_MSG_REC_SIZE_DBLKS);
+ for (m=0; m<t; m++)
+ enq_msg(jc, m, create_msg(msg, m, LARGE_MSG_SIZE), false);
+ // This enqueue should exceed the threshold
+ BOOST_CHECK_EQUAL(jc.get_enq_cnt(), t);
+ enq_msg(jc, m, create_msg(msg, m, LARGE_MSG_SIZE), false, RHM_IORES_ENQCAPTHRESH);
+ BOOST_CHECK_EQUAL(jc.get_enq_cnt(), t);
+
+ // Dequeue 25 msgs
+ #define NUM_MSGS_DEQ 25
+ for (m=0; m<NUM_MSGS_DEQ; m++)
+ deq_msg(jc, m, m+t);
+ BOOST_CHECK_EQUAL(jc.get_enq_cnt(), u_int32_t(t-NUM_MSGS_DEQ));
+
+ // Check we can still enqueue and dequeue
+ for (m=t+NUM_MSGS_DEQ; m<t+NUM_MSGS_DEQ+NUM_MSGS; m++)
+ enq_msg(jc, m, create_msg(msg, m, LARGE_MSG_SIZE), false);
+ for (m=t+NUM_MSGS_DEQ; m<t+NUM_MSGS_DEQ+NUM_MSGS; m++)
+ deq_msg(jc, m, m+NUM_MSGS_DEQ+NUM_MSGS);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(no_ae_threshold_dequeue_all)
+{
+ string test_name = get_test_name(test_filename, "no_ae_threshold_dequeue_all");
+ try
+ {
+ string msg;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_DEFAULT_JFILES, false, 0, DEFAULT_JFSIZE_SBLKS);
+ unsigned m;
+
+ // Fill journal to just below threshold
+ u_int32_t t = num_msgs_to_threshold(NUM_DEFAULT_JFILES,
+ DEFAULT_JFSIZE_SBLKS * JRNL_SBLK_SIZE, LARGE_MSG_REC_SIZE_DBLKS);
+ for (m=0; m<t; m++)
+ enq_msg(jc, m, create_msg(msg, m, LARGE_MSG_SIZE), false);
+ // This enqueue should exceed the threshold
+ BOOST_CHECK_EQUAL(jc.get_enq_cnt(), t);
+ enq_msg(jc, m, create_msg(msg, m, LARGE_MSG_SIZE), false, RHM_IORES_ENQCAPTHRESH);
+ BOOST_CHECK_EQUAL(jc.get_enq_cnt(), t);
+
+ // Dequeue all msgs
+ for (m=0; m<t; m++)
+ deq_msg(jc, m, m+t);
+ BOOST_CHECK_EQUAL(jc.get_enq_cnt(), u_int32_t(0));
+
+ // Check we can still enqueue and dequeue
+ for (m=2*t; m<2*t + NUM_MSGS; m++)
+ enq_msg(jc, m, create_msg(msg, m, LARGE_MSG_SIZE), false);
+ for (m=2*t; m<2*t + NUM_MSGS; m++)
+ deq_msg(jc, m, m+2*t+NUM_MSGS);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/_st_basic.cpp b/qpid/cpp/src/tests/legacystore/jrnl/_st_basic.cpp
new file mode 100644
index 0000000000..4aa6d2e29f
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/_st_basic.cpp
@@ -0,0 +1,558 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../unit_test.h"
+#include <cmath>
+#include <iostream>
+#include "qpid/legacystore/jrnl/jcntl.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(journal_basic)
+
+const string test_filename("_st_basic");
+
+#include "_st_helper_fns.h"
+
+// === Test suite ===
+
+#ifndef LONG_TEST
+/*
+ * ==============================================
+ * NORMAL TESTS
+ * This section contains normal "make check" tests
+ * for building/packaging. These are built when
+ * LONG_TEST is _not_ defined.
+ * ==============================================
+ */
+
+QPID_AUTO_TEST_CASE(instantiation)
+{
+ string test_name = get_test_name(test_filename, "instantiation");
+ try
+ {
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ BOOST_CHECK_EQUAL(jc.is_ready(), false);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(initialization)
+{
+ string test_name = get_test_name(test_filename, "initialization");
+ try
+ {
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ BOOST_CHECK_EQUAL(jc.is_ready(), false);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ BOOST_CHECK_EQUAL(jc.is_ready(), true);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_dequeue_block)
+{
+ string test_name = get_test_name(test_filename, "enqueue_dequeue_block");
+ try
+ {
+ string msg;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<NUM_MSGS; m++)
+ BOOST_CHECK_EQUAL(enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false), u_int64_t(m));
+ for (int m=0; m<NUM_MSGS; m++)
+ deq_msg(jc, m, m+NUM_MSGS);
+
+ // Again...
+ for (int m=2*NUM_MSGS; m<3*NUM_MSGS; m++)
+ BOOST_CHECK_EQUAL(enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false), u_int64_t(m));
+ for (int m=2*NUM_MSGS; m<3*NUM_MSGS; m++)
+ deq_msg(jc, m, m+3*NUM_MSGS);
+
+ // Disjoint rids
+ for (int m=10*NUM_MSGS; m<11*NUM_MSGS; m++)
+ BOOST_CHECK_EQUAL(enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false), u_int64_t(m));
+ for (int m=10*NUM_MSGS; m<11*NUM_MSGS; m++)
+ deq_msg(jc, m, m+11*NUM_MSGS);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_dequeue_interleaved)
+{
+ string test_name = get_test_name(test_filename, "enqueue_dequeue_interleaved");
+ try
+ {
+ string msg;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<2*NUM_MSGS; m+=2)
+ {
+ BOOST_CHECK_EQUAL(enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false), u_int64_t(m));
+ deq_msg(jc, m, m+1);
+ }
+
+ // Again...
+ for (int m=2*NUM_MSGS; m<4*NUM_MSGS; m+=2)
+ {
+ BOOST_CHECK_EQUAL(enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false), u_int64_t(m));
+ deq_msg(jc, m, m+1);
+ }
+
+ // Disjoint rids
+ for (int m=10*NUM_MSGS; m<12*NUM_MSGS; m+=2)
+ {
+ BOOST_CHECK_EQUAL(enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false), u_int64_t(m));
+ deq_msg(jc, m, m+1);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_dequeue_interleaved_file_rollover)
+{
+ string test_name = get_test_name(test_filename, "enqueue_dequeue_interleaved_file_rollover");
+ try
+ {
+ string msg;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ unsigned n = num_msgs_to_full(NUM_TEST_JFILES, TEST_JFSIZE_SBLKS * JRNL_SBLK_SIZE,
+ 16*MSG_REC_SIZE_DBLKS, true);
+ for (unsigned m=0; m<3*2*n; m+=2) // overwrite files 3 times
+ {
+ enq_msg(jc, m, create_msg(msg, m, 16*MSG_SIZE), false);
+ deq_msg(jc, m, m+1);
+ }
+ jc.stop(true);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(empty_recover)
+{
+ string test_name = get_test_name(test_filename, "empty_recover");
+ try
+ {
+ {
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ BOOST_CHECK_EQUAL(jc.is_ready(), false);
+ BOOST_CHECK_EQUAL(jc.is_read_only(), false);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ BOOST_CHECK_EQUAL(jc.is_ready(), true);
+ BOOST_CHECK_EQUAL(jc.is_read_only(), false);
+ }
+ {
+ u_int64_t hrid;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ BOOST_CHECK_EQUAL(jc.is_ready(), false);
+ BOOST_CHECK_EQUAL(jc.is_read_only(), false);
+ jc.recover(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS, 0, hrid);
+ BOOST_CHECK_EQUAL(jc.is_ready(), true);
+ BOOST_CHECK_EQUAL(jc.is_read_only(), true);
+ BOOST_CHECK_EQUAL(hrid, u_int64_t(0));
+ }
+ {
+ u_int64_t hrid;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ BOOST_CHECK_EQUAL(jc.is_ready(), false);
+ BOOST_CHECK_EQUAL(jc.is_read_only(), false);
+ jc.recover(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS, 0, hrid);
+ BOOST_CHECK_EQUAL(jc.is_ready(), true);
+ BOOST_CHECK_EQUAL(jc.is_read_only(), true);
+ BOOST_CHECK_EQUAL(hrid, u_int64_t(0));
+ jc.recover_complete();
+ BOOST_CHECK_EQUAL(jc.is_ready(), true);
+ BOOST_CHECK_EQUAL(jc.is_read_only(), false);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_recover_dequeue_block)
+{
+ string test_name = get_test_name(test_filename, "enqueue_recover_dequeue_block");
+ try
+ {
+ {
+ string msg;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<NUM_MSGS; m++)
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false);
+ }
+ {
+ u_int64_t hrid;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.recover(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS, 0, hrid);
+ BOOST_CHECK_EQUAL(hrid, u_int64_t(NUM_MSGS - 1));
+ jc.recover_complete();
+ for (int m=0; m<NUM_MSGS; m++)
+ deq_msg(jc, m, m+NUM_MSGS);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_recover_dequeue_interleaved)
+{
+ string test_name = get_test_name(test_filename, "enqueue_recover_dequeue_interleaved");
+ try
+ {
+ string msg;
+ u_int64_t hrid;
+
+ for (int m=0; m<2*NUM_MSGS; m+=2)
+ {
+ {
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ if (m == 0)
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS); // First time only
+ else
+ {
+ jc.recover(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS, 0, hrid);
+ BOOST_CHECK_EQUAL(hrid, u_int64_t(m - 1));
+ jc.recover_complete();
+ }
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false);
+ }
+ {
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.recover(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS, 0, hrid);
+ BOOST_CHECK_EQUAL(hrid, u_int64_t(m));
+ jc.recover_complete();
+ deq_msg(jc, m, m+1);
+ }
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(header_flags)
+{
+ string test_name = get_test_name(test_filename, "header_flags");
+ try
+ {
+ {
+ string msg;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ // Transient msgs - should not recover
+ for (int m=0; m<NUM_MSGS; m++)
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), true);
+ // Persistent msgs
+ for (int m=NUM_MSGS; m<NUM_MSGS*2; m++)
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false);
+ // Transient extern msgs - should not recover
+ for (int m=NUM_MSGS*2; m<NUM_MSGS*3; m++)
+ enq_extern_msg(jc, m, MSG_SIZE, true);
+ // Persistnet extern msgs
+ for (int m=NUM_MSGS*3; m<NUM_MSGS*4; m++)
+ enq_extern_msg(jc, m, MSG_SIZE, false);
+ }
+ {
+ string msg;
+ u_int64_t hrid;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.recover(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS, 0, hrid);
+ // Recover non-transient msgs
+ for (int m=NUM_MSGS; m<NUM_MSGS*2; m++)
+ {
+ string rmsg;
+ string xid;
+ bool transientFlag;
+ bool externalFlag;
+
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag);
+ BOOST_CHECK_MESSAGE(transientFlag == false, "Transient message recovered.");
+ BOOST_CHECK_MESSAGE(externalFlag == false, "External flag incorrect.");
+ BOOST_CHECK_MESSAGE(create_msg(msg, m, MSG_SIZE).compare(rmsg) == 0,
+ "Non-transient message corrupt during recover.");
+ }
+ // Recover non-transient extern msgs
+ for (int m=NUM_MSGS*3; m<NUM_MSGS*4; m++)
+ {
+ string rmsg;
+ string xid;
+ bool transientFlag;
+ bool externalFlag;
+
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag);
+ BOOST_CHECK_MESSAGE(transientFlag == false, "Transient message recovered.");
+ BOOST_CHECK_MESSAGE(externalFlag == true, "External flag incorrect.");
+ BOOST_CHECK_MESSAGE(rmsg.size() == 0, "External message returned non-zero size.");
+ }
+ jc.recover_complete();
+ // Read recovered non-transient msgs
+ for (int m=NUM_MSGS; m<NUM_MSGS*2; m++)
+ {
+ string rmsg;
+ string xid;
+ bool transientFlag;
+ bool externalFlag;
+
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag);
+ BOOST_CHECK_MESSAGE(transientFlag == false, "Transient message recovered.");
+ BOOST_CHECK_MESSAGE(externalFlag == false, "External flag incorrect.");
+ BOOST_CHECK_MESSAGE(create_msg(msg, m, MSG_SIZE).compare(rmsg) == 0,
+ "Non-transient message corrupt during recover.");
+ }
+ // Read recovered non-transient extern msgs
+ for (int m=NUM_MSGS*3; m<NUM_MSGS*4; m++)
+ {
+ string rmsg;
+ string xid;
+ bool transientFlag;
+ bool externalFlag;
+
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag);
+ BOOST_CHECK_MESSAGE(transientFlag == false, "Transient message recovered.");
+ BOOST_CHECK_MESSAGE(externalFlag == true, "External flag incorrect.");
+ BOOST_CHECK_MESSAGE(rmsg.size() == 0, "External message returned non-zero size.");
+ }
+ // Dequeue recovered messages
+ for (int m=NUM_MSGS; m<NUM_MSGS*2; m++)
+ deq_msg(jc, m, m+3*NUM_MSGS);
+ for (int m=NUM_MSGS*3; m<NUM_MSGS*4; m++)
+ deq_msg(jc, m, m+2*NUM_MSGS);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(double_dequeue)
+{
+ string test_name = get_test_name(test_filename, "double_dequeue");
+ try
+ {
+ string msg;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ enq_msg(jc, 0, create_msg(msg, 0, MSG_SIZE), false);
+ deq_msg(jc, 0, 1);
+ try{ deq_msg(jc, 0, 2); BOOST_ERROR("Did not throw exception on second dequeue."); }
+ catch (const jexception& e){ BOOST_CHECK_EQUAL(e.err_code(), jerrno::JERR_WMGR_DEQRIDNOTENQ); }
+ enq_msg(jc, 2, create_msg(msg, 1, MSG_SIZE), false);
+ deq_msg(jc, 2, 3);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+#else
+/*
+ * ==============================================
+ * LONG TESTS
+ * This section contains long tests and soak tests,
+ * and are run using target check-long (ie "make
+ * check-long"). These are built when LONG_TEST is
+ * defined.
+ * ==============================================
+ */
+
+QPID_AUTO_TEST_CASE(journal_overflow)
+{
+ string test_name = get_test_name(test_filename, "journal_overflow");
+ try
+ {
+ string msg;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_DEFAULT_JFILES, false, 0, DEFAULT_JFSIZE_SBLKS);
+ unsigned m;
+
+ // Fill journal to just below threshold
+ u_int32_t t = num_msgs_to_threshold(NUM_DEFAULT_JFILES, DEFAULT_JFSIZE_SBLKS * JRNL_SBLK_SIZE,
+ MSG_REC_SIZE_DBLKS);
+ u_int32_t d = num_dequeues_rem(NUM_DEFAULT_JFILES, DEFAULT_JFSIZE_SBLKS * JRNL_SBLK_SIZE);
+ for (m=0; m<t; m++)
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false);
+ // This enqueue should exceed the threshold
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false, RHM_IORES_ENQCAPTHRESH);
+
+ // Dequeue as many msgs as possible except first
+ for (m=1; m<=d; m++)
+ deq_msg(jc, m, m+t);
+ deq_msg(jc, d+1, d+2, RHM_IORES_FULL);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(file_cycle_block)
+{
+ string test_name = get_test_name(test_filename, "file_cycle_block");
+ try
+ {
+ string msg;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_DEFAULT_JFILES, false, 0, DEFAULT_JFSIZE_SBLKS);
+
+ // 5 cycles of enqueue/dequeue blocks of half threshold exception size
+ u_int32_t t = num_msgs_to_threshold(NUM_DEFAULT_JFILES, DEFAULT_JFSIZE_SBLKS * JRNL_SBLK_SIZE,
+ LARGE_MSG_REC_SIZE_DBLKS)/2;
+ for (unsigned i=0; i<5; i++)
+ {
+ for (unsigned m=2*i*t; m<(2*i+1)*t; m++)
+ enq_msg(jc, m, create_msg(msg, m, LARGE_MSG_SIZE), false);
+ for (unsigned m=2*i*t; m<(2*i+1)*t; m++)
+ deq_msg(jc, m, m+t);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(file_cycle_interleaved)
+{
+ string test_name = get_test_name(test_filename, "file_cycle_interleaved");
+ try
+ {
+ string msg;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_DEFAULT_JFILES, false, 0, DEFAULT_JFSIZE_SBLKS);
+
+ // 5 cycles of enqueue/dequeue blocks of half threshold exception size
+ u_int32_t t = num_msgs_to_threshold(NUM_DEFAULT_JFILES, DEFAULT_JFSIZE_SBLKS * JRNL_SBLK_SIZE,
+ LARGE_MSG_REC_SIZE_DBLKS)/2;
+ for (unsigned m=0; m<5*2*t; m+=2)
+ {
+ enq_msg(jc, m, create_msg(msg, m, LARGE_MSG_SIZE), false);
+ deq_msg(jc, m, m+1);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(recover_file_cycle_block)
+{
+ string test_name = get_test_name(test_filename, "recover_file_cycle_block");
+ try
+ {
+ string msg;
+ u_int64_t hrid;
+
+ // 5 cycles of enqueue/dequeue blocks of half threshold exception size
+ u_int32_t t = num_msgs_to_threshold(NUM_DEFAULT_JFILES, DEFAULT_JFSIZE_SBLKS * JRNL_SBLK_SIZE,
+ LARGE_MSG_REC_SIZE_DBLKS)/2;
+ for (unsigned i=0; i<5; i++)
+ {
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ if (i)
+ {
+ jc.recover(NUM_DEFAULT_JFILES, false, 0, DEFAULT_JFSIZE_SBLKS, 0, hrid);
+ BOOST_CHECK_EQUAL(hrid, u_int64_t(2*i*t - 1));
+ jc.recover_complete();
+ }
+ else
+ jc.initialize(NUM_DEFAULT_JFILES, false, 0, DEFAULT_JFSIZE_SBLKS);
+
+ for (unsigned m=2*i*t; m<(2*i+1)*t; m++)
+ enq_msg(jc, m, create_msg(msg, m, LARGE_MSG_SIZE), false);
+ for (unsigned m=2*i*t; m<(2*i+1)*t; m++)
+ deq_msg(jc, m, m+t);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(recover_file_cycle_interleaved)
+{
+ string test_name = get_test_name(test_filename, "recover_file_cycle_interleaved");
+ try
+ {
+ string msg;
+ u_int64_t hrid;
+
+ // 5 cycles of enqueue/dequeue blocks of half threshold exception size
+ u_int32_t t = num_msgs_to_threshold(NUM_DEFAULT_JFILES, DEFAULT_JFSIZE_SBLKS * JRNL_SBLK_SIZE,
+ LARGE_MSG_REC_SIZE_DBLKS)/2;
+ for (unsigned i=0; i<5; i++)
+ {
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ if (i)
+ {
+ jc.recover(NUM_DEFAULT_JFILES, false, 0, DEFAULT_JFSIZE_SBLKS, 0, hrid);
+ BOOST_CHECK_EQUAL(hrid, u_int64_t(2*i*t - 1));
+ jc.recover_complete();
+ }
+ else
+ jc.initialize(NUM_DEFAULT_JFILES, false, 0, DEFAULT_JFSIZE_SBLKS);
+
+ for (unsigned m=2*i*t; m<2*(i+1)*t; m+=2)
+ {
+ enq_msg(jc, m, create_msg(msg, m, LARGE_MSG_SIZE), false);
+ deq_msg(jc, m, m+1);
+ }
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+#endif
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/_st_basic_txn.cpp b/qpid/cpp/src/tests/legacystore/jrnl/_st_basic_txn.cpp
new file mode 100644
index 0000000000..aa2d31c2ae
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/_st_basic_txn.cpp
@@ -0,0 +1,239 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../unit_test.h"
+#include <cmath>
+#include <iostream>
+#include "qpid/legacystore/jrnl/jcntl.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(journal_basic_txn)
+
+const string test_filename("_st_basic_txn");
+
+#include "_st_helper_fns.h"
+
+// === Test suite ===
+
+QPID_AUTO_TEST_CASE(enqueue_commit_dequeue_block)
+{
+ string test_name = get_test_name(test_filename, "enqueue_commit_dequeue_block");
+ try
+ {
+ string msg;
+ string xid;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ create_xid(xid, 0, XID_SIZE);
+ for (int m=0; m<NUM_MSGS; m++)
+ BOOST_CHECK_EQUAL(enq_txn_msg(jc, m, create_msg(msg, m, MSG_SIZE), xid, false), u_int64_t(m));
+ txn_commit(jc, NUM_MSGS, xid);
+ for (int m=0; m<NUM_MSGS; m++)
+ deq_msg(jc, m, m+NUM_MSGS+1);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_abort_dequeue_block)
+{
+ string test_name = get_test_name(test_filename, "enqueue_abort_dequeue_block");
+ try
+ {
+ string msg;
+ string xid;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ create_xid(xid, 0, XID_SIZE);
+ for (int m=0; m<NUM_MSGS; m++)
+ BOOST_CHECK_EQUAL(enq_txn_msg(jc, m, create_msg(msg, m, MSG_SIZE), xid, false), u_int64_t(m));
+ txn_abort(jc, NUM_MSGS, xid);
+ for (int m=0; m<NUM_MSGS; m++)
+ {
+ try
+ {
+ deq_msg(jc, m, m+NUM_MSGS+1);
+ BOOST_ERROR("Expected dequeue to fail with exception JERR_WMGR_DEQRIDNOTENQ.");
+ }
+ catch (const jexception& e) { if (e.err_code() != jerrno::JERR_WMGR_DEQRIDNOTENQ) throw; }
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_commit_dequeue_interleaved)
+{
+ string test_name = get_test_name(test_filename, "enqueue_commit_dequeue_interleaved");
+ try
+ {
+ string msg;
+ string xid;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<NUM_MSGS; m++)
+ {
+ create_xid(xid, m, XID_SIZE);
+ BOOST_CHECK_EQUAL(enq_txn_msg(jc, 3*m, create_msg(msg, m, MSG_SIZE), xid, false), u_int64_t(3*m));
+ txn_commit(jc, 3*m+1, xid);
+ deq_msg(jc, 3*m, 3*m+2);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_abort_dequeue_interleaved)
+{
+ string test_name = get_test_name(test_filename, "enqueue_abort_dequeue_interleaved");
+ try
+ {
+ string msg;
+ string xid;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<NUM_MSGS; m++)
+ {
+ create_xid(xid, m, XID_SIZE);
+ BOOST_CHECK_EQUAL(enq_txn_msg(jc, 3*m, create_msg(msg, m, MSG_SIZE), xid, false), u_int64_t(3*m));
+ txn_abort(jc, 3*m+1, xid);
+ try
+ {
+ deq_msg(jc, 2*m, 2*m+2);
+ BOOST_ERROR("Expected dequeue to fail with exception JERR_WMGR_DEQRIDNOTENQ.");
+ }
+ catch (const jexception& e) { if (e.err_code() != jerrno::JERR_WMGR_DEQRIDNOTENQ) throw; }
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_dequeue_commit_block)
+{
+ string test_name = get_test_name(test_filename, "enqueue_dequeue_commit_block");
+ try
+ {
+ string msg;
+ string xid;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ create_xid(xid, 0, XID_SIZE);
+ for (int m=0; m<NUM_MSGS; m++)
+ BOOST_CHECK_EQUAL(enq_txn_msg(jc, m, create_msg(msg, m, MSG_SIZE), xid, false), u_int64_t(m));
+ BOOST_CHECK_EQUAL(jc.get_enq_cnt(), u_int32_t(0));
+ for (int m=0; m<NUM_MSGS; m++)
+ deq_txn_msg(jc, m, m+NUM_MSGS, xid);
+ BOOST_CHECK_EQUAL(jc.get_enq_cnt(), u_int32_t(0));
+ txn_commit(jc, 2*NUM_MSGS, xid);
+ BOOST_CHECK_EQUAL(jc.get_enq_cnt(), u_int32_t(0));
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_dequeue_abort_block)
+{
+ string test_name = get_test_name(test_filename, "enqueue_dequeue_abort_block");
+ try
+ {
+ string msg;
+ string xid;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ create_xid(xid, 0, XID_SIZE);
+ for (int m=0; m<NUM_MSGS; m++)
+ BOOST_CHECK_EQUAL(enq_txn_msg(jc, m, create_msg(msg, m, MSG_SIZE), xid, false), u_int64_t(m));
+ BOOST_CHECK_EQUAL(jc.get_enq_cnt(), u_int32_t(0));
+ for (int m=0; m<NUM_MSGS; m++)
+ deq_txn_msg(jc, m, m+NUM_MSGS, xid);
+ BOOST_CHECK_EQUAL(jc.get_enq_cnt(), u_int32_t(0));
+ txn_abort(jc, 2*NUM_MSGS, xid);
+ BOOST_CHECK_EQUAL(jc.get_enq_cnt(), u_int32_t(0));
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_dequeue_commit_interleaved)
+{
+ string test_name = get_test_name(test_filename, "enqueue_dequeue_commit_interleaved");
+ try
+ {
+ string msg;
+ string xid;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<NUM_MSGS; m++)
+ {
+ create_xid(xid, m, XID_SIZE);
+ BOOST_CHECK_EQUAL(enq_txn_msg(jc, 3*m, create_msg(msg, m, MSG_SIZE), xid, false), u_int64_t(3*m));
+ deq_txn_msg(jc, 3*m, 3*m+1, xid);
+ txn_commit(jc, 3*m+2, xid);
+ BOOST_CHECK_EQUAL(jc.get_enq_cnt(), u_int32_t(0));
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_dequeue_abort_interleaved)
+{
+ string test_name = get_test_name(test_filename, "enqueue_dequeue_abort_interleaved");
+ try
+ {
+ string msg;
+ string xid;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<NUM_MSGS; m++)
+ {
+ create_xid(xid, m, XID_SIZE);
+ BOOST_CHECK_EQUAL(enq_txn_msg(jc, 3*m, create_msg(msg, m, MSG_SIZE), xid, false), u_int64_t(3*m));
+ deq_txn_msg(jc, 3*m, 3*m+1, xid);
+ txn_abort(jc, 3*m+2, xid);
+ BOOST_CHECK_EQUAL(jc.get_enq_cnt(), u_int32_t(0));
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/_st_helper_fns.h b/qpid/cpp/src/tests/legacystore/jrnl/_st_helper_fns.h
new file mode 100644
index 0000000000..923065dd11
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/_st_helper_fns.h
@@ -0,0 +1,882 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// NOTE: This file is included in _st_*.cpp files inside the QPID_AUTO_TEST_SUITE()
+// definition.
+
+#define MAX_AIO_SLEEPS 500
+#define AIO_SLEEP_TIME 1000
+#define NUM_TEST_JFILES 4
+#define NUM_DEFAULT_JFILES 8
+#define JRNL_DEFAULT_FSIZE 24 // Multiples of JRNL_RMGR_PAGE_SIZE
+#define TEST_JFSIZE_SBLKS 128
+#define DEFAULT_JFSIZE_SBLKS (JRNL_DEFAULT_FSIZE * JRNL_RMGR_PAGE_SIZE)
+#define NUM_MSGS 5
+#define MSG_REC_SIZE_DBLKS 2
+#define MSG_SIZE (MSG_REC_SIZE_DBLKS * JRNL_DBLK_SIZE) - sizeof(enq_hdr) - sizeof(rec_tail)
+#define LARGE_MSG_REC_SIZE_DBLKS (JRNL_SBLK_SIZE * JRNL_RMGR_PAGE_SIZE)
+#define LARGE_MSG_SIZE (LARGE_MSG_REC_SIZE_DBLKS * JRNL_DBLK_SIZE) - sizeof(enq_hdr) - sizeof(rec_tail)
+#define XID_SIZE 64
+
+#define XLARGE_MSG_RATIO (1.0 * LARGE_MSG_REC_SIZE / JRNL_DBLK_SIZE / JRNL_SBLK_SIZE / JRNL_RMGR_PAGE_SIZE)
+#define XLARGE_MSG_THRESHOLD (int)(JRNL_DEFAULT_FSIZE * NUM_DEFAULT_JFILES * JRNL_ENQ_THRESHOLD / 100 / LARGE_MSG_RATIO)
+
+#define NUM_JFILES 4
+#define JFSIZE_SBLKS 128
+
+const char* tdp = getenv("TMP_DATA_DIR");
+const string test_dir(tdp && strlen(tdp) > 0 ? string(tdp) + "/" + test_filename : "/var/tmp/jrnl_test");
+
+class test_dtok : public data_tok
+{
+private:
+ bool flag;
+public:
+ test_dtok() : data_tok(), flag(false) {}
+ virtual ~test_dtok() {}
+ bool done() { if (flag || _wstate == NONE) return true; else { flag = true; return false; } }
+};
+
+class test_jrnl_cb : public aio_callback {
+ virtual void wr_aio_cb(std::vector<data_tok*>& dtokl)
+ {
+ for (std::vector<data_tok*>::const_iterator i=dtokl.begin(); i!=dtokl.end(); i++)
+ {
+ test_dtok* dtp = static_cast<test_dtok*>(*i);
+ if (dtp->done())
+ delete dtp;
+ }
+ }
+ virtual void rd_aio_cb(std::vector<u_int16_t>& /*pil*/) {}
+};
+
+class test_jrnl : public jcntl
+{
+test_jrnl_cb* cb;
+
+public:
+ test_jrnl(const std::string& jid, const std::string& jdir, const std::string& base_filename, test_jrnl_cb& cb0) :
+ jcntl(jid, jdir, base_filename),
+ cb(&cb0) {}
+ virtual ~test_jrnl() {}
+ void initialize(const u_int16_t num_jfiles, const bool ae, const u_int16_t ae_max_jfiles,
+ const u_int32_t jfsize_sblks)
+ {
+ jcntl::initialize(num_jfiles, ae, ae_max_jfiles, jfsize_sblks, JRNL_WMGR_DEF_PAGES, JRNL_WMGR_DEF_PAGE_SIZE,
+ cb);
+ _jdir.create_dir();
+ }
+ void recover(const u_int16_t num_jfiles, const bool ae, const u_int16_t ae_max_jfiles, const u_int32_t jfsize_sblks,
+ vector<string>* txn_list, u_int64_t& highest_rid)
+ { jcntl::recover(num_jfiles, ae, ae_max_jfiles, jfsize_sblks, JRNL_WMGR_DEF_PAGES, JRNL_WMGR_DEF_PAGE_SIZE, cb,
+ txn_list, highest_rid); }
+};
+
+/*
+* This class is for testing recover functionality by maintaining an internal lfid-pfid map, then creating physical
+* journal file stubs (just the fhdr section of the journal) and jinf file. This allows the recover functionality (which
+* analyzes these components to determine recover order).
+*
+* First set up a map or "blueprint" of what the journal should look like for recovery, then have the class create the
+* physical files. The jinf object under test then reads and analyzes the created journal, and it's analysis is checked
+* against what is expected.
+*
+* General usage pattern:
+* 1. Create instance of lfid_pfid_map.
+* 2. Call lfid_pfid_map::journal_create() to simulate initial journal creation.
+* 3. (optional) Call lfid_pfid_map::journal_insert() one or more times to simulate the addition of journal files.
+* 4. Call lfid_pfid_map::write_journal() to create dummy journal files (files containing only file headers)
+* 5. Create and initialize the jinf object under test
+* 6. Call jinf::analyze() to determine the pfid order - and thus also first and last lids
+* 7. Call lfid_pfid_map::check_analysis() to check the conclusions of the analysis
+* 8. Call lfid_pfid_map::destroy_journal() to delete the journal files and reset the lfid_pfid_map object.
+* 9. (optional) Back to step 2 for more tests
+*
+* See the individual methods below for more details.
+*/
+class lfid_pfid_map
+{
+ public:
+ typedef pair<u_int16_t, file_hdr> lppair; // Used for loading the map
+ typedef multimap<u_int16_t, file_hdr> lpmap; // Stores the journal "plan" before it is created on-disk
+ typedef lpmap::const_iterator lpmap_citr; // General purpose iterator
+ typedef pair<lpmap_citr, lpmap_citr> lpmap_range; // Range of values returned by multimap's equal_range() fn
+
+ private:
+ string _jid; // Journal id
+ string _base_filename; // Base filename
+ lpmap _map; // Stores the journal "blueprint" before it is created on-disk
+ u_int16_t _num_used_files; // number of files which contain jorunals
+ u_int16_t _oldest_lfid; // lfid where owi flips; always 0 if !_full
+ u_int16_t _last_pfid; // last pfid (ie last file added)
+
+ public:
+ lfid_pfid_map(const string& jid, const string& base_filename) :
+ _jid(jid), _base_filename(base_filename), _num_used_files(0), _oldest_lfid(0), _last_pfid(0)
+ {}
+ virtual ~lfid_pfid_map() {}
+
+ // Mainly used for debugging
+ void print()
+ {
+ int cnt = 0;
+ for (lpmap_citr i=_map.begin(); i!=_map.end(); i++, cnt++)
+ {
+ const file_hdr fh = i->second;
+ cout << " " << cnt << ": owi=" << (fh.get_owi()?"t":"f") << hex << " frid=0x" << fh._rid;
+ cout << " pfid=0x" << fh._pfid << " lfid=0x" << fh._lfid << " fro=0x" << fh._fro << dec << endl;
+ }
+ }
+
+ std::size_t size()
+ {
+ return _map.size();
+ }
+
+ /*
+ * Method journal_create(): Used to simulate the initial creation of a journal before file insertions
+ * take place.
+ *
+ * num_jfiles: The initial journal file count.
+ * num_used_jfiles: If this number is less than num_jfiles, it indicates a clean journal that has not yet
+ * completed its first rotation, and some files are empty (ie all null). The first
+ * num_used_jfiles will contain file headers, the remainder will be blank.
+ * oldest_lfid: The lfid (==pfid, see note 1 below) at which the owi flag flips. During normal operation,
+ * each time the journal rotates back to file 0, a flag (called the overwrite indicator or owi)
+ * is flipped. This flag is saved in the file header. During recovery, if scanning from logical
+ * file 0 upwards, the file at which this flag reverses from its value in file 0 is the file
+ * that was to have been overwritten next, and is thus the "oldest" file. Recovery analysis must
+ * start with this file. oldest_lfid sets the file at which this flag will flip value for the
+ * simulated recovery analysis. Note that this will be ignored if num_used_jfiles < num_jfiles,
+ * as it is not possible for an overwrite to have occurred if not all the files have been used.
+ * first_owi: Sets the value of the owi flag in file 0. If set to false, then the flip will be found with
+ * a true flag (and visa versa).
+ *
+ * NOTES:
+ * 1. By definition, the lfids and pfids coincide for a journal containing no inserted files. Thus pfid == lfid
+ * for all journals created after using initial_journal_create() alone.
+ * 2. By definition, if a journal is not full (num_used_jfiles < num_jfiles), then all owi flags for those files
+ * that are used must be the same. It is not possible for an overwrite situation to arise if a journal is not
+ * full.
+ * 3. This function acts on map _map only, and does not create any test files. Call write_journal() to do that.
+ * 4. This function must be called on a clean test object or on one where the previous test data has been
+ * cleared by calling journal_destroy(). Running this function more than once on existing data will
+ * result in invalid journals which cannot be recovered.
+ */
+ void journal_create(const u_int16_t num_jfiles, // Total number of files
+ const u_int16_t num_used_jfiles, // Number of used files, rest empty at end
+ const u_int16_t oldest_lfid = 0, // Fid where owi reverses
+ const u_int16_t bad_lfid = 0, // Fid where owi reverses again (must be > oldest_lifd),
+ // used for testing bad owi detection
+ const bool first_owi = false) // Value of first owi flag (ie pfid=0)
+ {
+ const bool full = num_used_jfiles == num_jfiles;
+ bool owi = first_owi;
+ _oldest_lfid = full ? oldest_lfid : 0;
+ for (u_int16_t lfid = 0; lfid < num_jfiles; lfid++)
+ {
+ const u_int16_t pfid = lfid;
+ file_hdr fh;
+ if (pfid < num_used_jfiles)
+ {
+ _num_used_files = num_used_jfiles;
+ /*
+ * Invert the owi flag from its current value (initially given by first_owi param) only if:
+ * 1. The journal is full (ie all files are used)
+ * AND
+ * 2. oldest_lfid param is non-zero (this is default, but lfid 0 being inverted is logically
+ * inconsistent with first_owi parameter being present)
+ * AND
+ * 3. Either:
+ * * current lfid == oldest_lfid (ie we are preparing the oldest lfid)
+ * OR
+ * * current lfid == bad_lfid AND bad_lfid > oldest (ie we are past the oldest and preparing the
+ * bad lfid)
+ */
+ if (full && oldest_lfid > 0 &&
+ (lfid == oldest_lfid || (bad_lfid > oldest_lfid && lfid == bad_lfid)))
+ owi = !owi;
+ const u_int64_t frid = u_int64_t(random());
+ init_fhdr(fh, frid, pfid, lfid, owi);
+ }
+ _map.insert(lppair(lfid, fh));
+ }
+ }
+
+ /*
+ * Method journal_insert(): Used to simulate the insertion of journal files into an existing journal.
+ *
+ * after_lfid: The logical file id (lfid) after which the new file is to be inserted.
+ * num_files: The number of files to be inserted.
+ * adjust_lids: Flag indicating that the lids of files _following_ the inserted files are to be adjusted upwards
+ * by the number of inserted files. Not doing so simulates a recovery immediately after insertion
+ * but before the following files are overwritten with their new lids. If this is set false, then:
+ * a) after_lfid MUST be the most recent file (_oldest_lfid-1 ie last lfid before owi changes).
+ * b) This call must be the last insert call.
+ *
+ * NOTES:
+ * 1. It is not possible to insert before lfid/pfid 0; thus these are always coincidental. This operation is
+ * logically equivalent to inserting after the last lfid, which is possible.
+ * 2. It is not possible to insert into a journal that is not full. Doing so will result in an unrecoverable
+ * journal (one that is logically inconsistent that can never occur in reality).
+ * 3. If a journal is stopped/interrupted immediately after a file insertion, there could be duplicate lids in
+ * play at recovery, as the following file lids in their headers are only overwritten when the file is
+ * eventually written to during normal operation. The owi flags, however, are used to determine which of the
+ * ambiguous lids are the inserted files.
+ * 4. This function acts on map _map only, and does not create any test files. Call write_journal() to do that.
+ */
+ void journal_insert(const u_int16_t after_lfid, // Insert files after this lfid
+ const u_int16_t num_files = 1, // Number of files to insert
+ const bool adjust_lids = true) // Adjust lids following inserted files
+ {
+ if (num_files == 0) return;
+ _num_used_files += num_files;
+ const u_int16_t num_jfiles_before_append = _map.size();
+ lpmap_citr i = _map.find(after_lfid);
+ if (i == _map.end()) BOOST_FAIL("Unable to find lfid=" << after_lfid << " in map.");
+ const file_hdr fh_before = (*i).second;
+
+ // Move overlapping lids (if req'd)
+ if (adjust_lids && after_lfid < num_jfiles_before_append - 1)
+ {
+ for (u_int16_t lfid = num_jfiles_before_append - 1; lfid > after_lfid; lfid--)
+ {
+ lpmap_citr itr = _map.find(lfid);
+ if (itr == _map.end()) BOOST_FAIL("Unable to find lfid=" << after_lfid << " in map.");
+ file_hdr fh = itr->second;
+ _map.erase(lfid);
+ fh._lfid += num_files;
+ if (lfid == _oldest_lfid)
+ _oldest_lfid += num_files;
+ _map.insert(lppair(fh._lfid, fh));
+ }
+ }
+
+ // Add new file headers
+ u_int16_t pfid = num_jfiles_before_append;
+ u_int16_t lfid = after_lfid + 1;
+ while (pfid < num_jfiles_before_append + num_files)
+ {
+ const u_int64_t frid = u_int64_t(random());
+ const size_t fro = 0x200;
+ const file_hdr fh(RHM_JDAT_FILE_MAGIC, RHM_JDAT_VERSION, frid, pfid, lfid, fro, fh_before.get_owi(),
+ true);
+ _map.insert(lppair(lfid, fh));
+ _last_pfid = pfid;
+ pfid++;
+ lfid++;
+ }
+ }
+
+ /*
+ * Get the list of pfids in the map in order of lfid. The pfids are appended to the supplied vector. Only
+ * as many headers as are in the map are appended.
+ * NOTE: will clear any contents from supplied vector before appending pfid list.
+ */
+ void get_pfid_list(vector<u_int16_t>& pfid_list)
+ {
+ pfid_list.clear();
+ for (lpmap_citr i = _map.begin(); i != _map.end(); i++)
+ pfid_list.push_back(i->second._pfid);
+ }
+
+ /*
+ * Get the list of lfids in the map. The lfids are appended to the supplied vector in the order they appear
+ * in the map (which is not necessarily the natural or sorted order).
+ * NOTE: will clear any contents from supplied vector before appending lfid list.
+ */
+ void get_lfid_list(vector<u_int16_t>& lfid_list)
+ {
+ lfid_list.clear();
+ lfid_list.assign(_map.size(), 0);
+ for (lpmap_citr i = _map.begin(); i != _map.end(); i++)
+ lfid_list[i->second._pfid] = i->first;
+ }
+
+ /*
+ * Method check_analysis(): Used to check the result of the test jinf object analysis by comparing the pfid order
+ * array it produces against the internal map.
+ *
+ * ji: A ref to the jinf object under test.
+ */
+ void check_analysis(jinf& ji) // jinf object under test after analyze() has been called
+ {
+ BOOST_CHECK_EQUAL(ji.get_first_pfid(), get_first_pfid());
+ BOOST_CHECK_EQUAL(ji.get_last_pfid(), get_last_pfid());
+
+ jinf::pfid_list& pfidl = ji.get_pfid_list();
+ const u_int16_t num_jfiles = _map.size();
+ const bool all_used = _num_used_files == num_jfiles;
+ BOOST_CHECK_EQUAL(pfidl.size(), _num_used_files);
+
+ const u_int16_t lfid_start = all_used ? _oldest_lfid : 0;
+ // Because a simulated failure would leave lfid dups in map and last_fid would not exist in map in this
+ // case, we must find lfid_stop via pfid instead. Search for pfid == num_files.
+ lpmap_citr itr = _map.begin();
+ while (itr != _map.end() && itr->second._pfid != _num_used_files - 1) itr++;
+ if (itr == _map.end())
+ BOOST_FAIL("check(): Unable to find pfid=" << (_num_used_files - 1) << " in map.");
+ const u_int16_t lfid_stop = itr->second._lfid;
+
+ std::size_t fidl_index = 0;
+ for (u_int16_t lfid_cnt = lfid_start; lfid_cnt < lfid_stop; lfid_cnt++, fidl_index++)
+ {
+ const u_int16_t lfid = lfid_cnt % num_jfiles;
+ lpmap_citr itr = _map.find(lfid);
+ if (itr == _map.end())
+ BOOST_FAIL("check(): Unable to find lfid=" << lfid << " in map.");
+ BOOST_CHECK_EQUAL(itr->second._pfid, pfidl[fidl_index]);
+ }
+ }
+
+ /*
+ * Method get_pfid(): Look up a pfid from a known lfid.
+ */
+ u_int16_t get_pfid(const u_int16_t lfid, const bool initial_owi = false)
+ {
+ switch (_map.count(lfid))
+ {
+ case 1:
+ return _map.find(lfid)->second._pfid;
+ case 2:
+ for (lpmap_citr itr = _map.lower_bound(lfid); itr != _map.upper_bound(lfid); itr++)
+ {
+ if (itr->second.get_owi() != initial_owi)
+ return itr->second._pfid;
+ }
+ default:;
+ }
+ BOOST_FAIL("get_pfid(): lfid=" << lfid << " not found in map.");
+ return 0xffff;
+ }
+
+ /*
+ * Method get_first_pfid(): Look up the first (oldest, or next-to-be-overwritten) pfid in the analysis sequence.
+ */
+ u_int16_t get_first_pfid()
+ {
+ return get_pfid(_oldest_lfid);
+ }
+
+ /*
+ * Method get_last_pfid(): Look up the last (newest, or most recently written) pfid in the analysis sequence.
+ */
+ u_int16_t get_last_pfid()
+ {
+ u_int16_t flfid = 0;
+ if (_num_used_files == _map.size()) // journal full?
+ {
+ if (_oldest_lfid)
+ {
+ // if failed insert, cycle past duplicate lids
+ while (_map.count(_oldest_lfid) == 2)
+ _oldest_lfid++;
+ while (_map.find(_oldest_lfid) != _map.end() && _map.find(_oldest_lfid)->second.get_owi() == false)
+ _oldest_lfid++;
+ flfid = _oldest_lfid - 1;
+ }
+ else
+ flfid = _map.size() - 1;
+ }
+ else
+ flfid = _num_used_files - 1;
+ return get_pfid(flfid, true);
+ }
+
+ /*
+ * Method write_journal(): Used to create the dummy journal files from the built-up map created by calling
+ * initial_journal_create() and optionally journal_append() one or more times. Since the jinf object reads the
+ * jinf file and the file headers only, the create object creates a dummy journal file containing only a file
+ * header (512 bytes each) and a single jinf file which contains the journal metadata required for recovery
+ * analysis.
+ */
+ void write_journal(const bool ae, const u_int16_t ae_max_jfiles, const u_int32_t fsize_sblks = JFSIZE_SBLKS)
+ {
+ create_jinf(ae, ae_max_jfiles);
+ u_int16_t pfid = 0;
+ for (lpmap_citr itr = _map.begin(); itr != _map.end(); itr++, pfid++)
+ {
+ if (itr->second._pfid == 0 && itr->second._magic == 0) // empty header, use pfid counter instead
+ create_journal_file(pfid, itr->second, _base_filename, fsize_sblks);
+ else
+ create_journal_file(itr->second._pfid, itr->second, _base_filename, fsize_sblks);
+ }
+ }
+
+ /*
+ * Method destroy_journal(): Destroy the files created by create_journal() and reset the lfid_pfid_map test
+ * object. A new test may be started using the same lfid_pfid_map test object once this call has been made.
+ */
+ void destroy_journal()
+ {
+ for (u_int16_t pfid = 0; pfid < _map.size(); pfid++)
+ {
+ string fn = create_journal_filename(pfid, _base_filename);
+ BOOST_WARN_MESSAGE(::unlink(fn.c_str()) == 0, "destroy_journal(): Failed to remove file " << fn);
+ }
+ clean_journal_info_file(_base_filename);
+ _map.clear();
+ _num_used_files = 0;
+ _oldest_lfid = 0;
+ _last_pfid = 0;
+ }
+
+ /*
+ * Method create_new_jinf(): This static call creates a default jinf file only. This is used to test the read
+ * constructor of a jinf test object which reads a jinf file at instantiation.
+ */
+ static void create_new_jinf(const string jid, const string base_filename, const bool ae)
+ {
+ if (jdir::exists(test_dir))
+ jdir::delete_dir(test_dir);
+ create_jinf(NUM_JFILES, ae, (ae ? 5 * NUM_JFILES : 0), jid, base_filename);
+ }
+
+ /*
+ * Method clean_journal_info_file(): This static method deletes only a jinf file without harming any other
+ * journal file or its directory. This is used to clear those tests which rely only on the existence of a
+ * jinf file.
+ */
+ static void clean_journal_info_file(const string base_filename)
+ {
+ stringstream fn;
+ fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+ BOOST_WARN_MESSAGE(::unlink(fn.str().c_str()) == 0, "clean_journal_info_file(): Failed to remove file " <<
+ fn.str());
+ }
+
+ static string create_journal_filename(const u_int16_t pfid, const string base_filename)
+ {
+ stringstream fn;
+ fn << test_dir << "/" << base_filename << ".";
+ fn << setfill('0') << hex << setw(4) << pfid << "." << JRNL_DATA_EXTENSION;
+ return fn.str();
+ }
+
+ private:
+ static void init_fhdr(file_hdr& fh,
+ const u_int64_t frid,
+ const u_int16_t pfid,
+ const u_int16_t lfid,
+ const bool owi,
+ const bool no_enq = false)
+ {
+ fh._magic = RHM_JDAT_FILE_MAGIC;
+ fh._version = RHM_JDAT_VERSION;
+#if defined(JRNL_BIG_ENDIAN)
+ fh._eflag = RHM_BENDIAN_FLAG;
+#else
+ fh._eflag = RHM_LENDIAN_FLAG;
+#endif
+ fh._uflag = owi ? rec_hdr::HDR_OVERWRITE_INDICATOR_MASK : 0;
+ fh._rid = frid;
+ fh._pfid = pfid;
+ fh._lfid = lfid;
+ fh._fro = no_enq ? 0 : 0x200;
+ timespec ts;
+ ::clock_gettime(CLOCK_REALTIME, &ts);
+ fh._ts_sec = ts.tv_sec;
+ fh._ts_nsec = ts.tv_nsec;
+ }
+
+ void create_jinf(const bool ae, const u_int16_t ae_max_jfiles)
+ {
+ if (jdir::exists(test_dir))
+ jdir::delete_dir(test_dir);
+ create_jinf(_map.size(), ae, ae_max_jfiles, _jid, _base_filename);
+ }
+
+ static void create_jinf(u_int16_t num_files, const bool ae, const u_int16_t ae_max_jfiles, const string jid,
+ const string base_filename)
+ {
+ jdir::create_dir(test_dir); // Check test dir exists; create it if not
+ timespec ts;
+ ::clock_gettime(CLOCK_REALTIME, &ts);
+ jinf ji(jid, test_dir, base_filename, num_files, ae, ae_max_jfiles, JFSIZE_SBLKS, JRNL_WMGR_DEF_PAGE_SIZE,
+ JRNL_WMGR_DEF_PAGES, ts);
+ ji.write();
+ }
+
+ static void create_journal_file(const u_int16_t pfid,
+ const file_hdr& fh,
+ const string base_filename,
+ const u_int32_t fsize_sblks = JFSIZE_SBLKS,
+ const char fill_char = 0)
+ {
+ const std::string filename = create_journal_filename(pfid, base_filename);
+ ofstream of(filename.c_str(), ofstream::out | ofstream::trunc);
+ if (!of.good())
+ BOOST_FAIL("Unable to open test journal file \"" << filename << "\" for writing.");
+
+ write_file_header(filename, of, fh, fill_char);
+ write_file_body(of, fsize_sblks, fill_char);
+
+ of.close();
+ if (of.fail() || of.bad())
+ BOOST_FAIL("Error closing test journal file \"" << filename << "\".");
+ }
+
+ static void write_file_header(const std::string& filename,
+ ofstream& of,
+ const file_hdr& fh,
+ const char fill_char)
+ {
+ // write file header
+ u_int32_t cnt = sizeof(file_hdr);
+ of.write((const char*)&fh, cnt);
+ if (of.fail() || of.bad())
+ BOOST_FAIL("Error writing file header to test journal file \"" << filename << "\".");
+
+ // fill remaining sblk with fill char
+ while (cnt++ < JRNL_DBLK_SIZE * JRNL_SBLK_SIZE)
+ {
+ of.put(fill_char);
+ if (of.fail() || of.bad())
+ BOOST_FAIL("Error writing filler to test journal file \"" << filename << "\".");
+ }
+ }
+
+ static void write_file_body(ofstream& of, const u_int32_t fsize_sblks, const char fill_char)
+ {
+ if (fsize_sblks > 1)
+ {
+ std::vector<char> sblk_buffer(JRNL_DBLK_SIZE * JRNL_SBLK_SIZE, fill_char);
+ u_int32_t fwritten_sblks = 0; // hdr
+ while (fwritten_sblks++ < fsize_sblks)
+ of.write(&sblk_buffer[0], JRNL_DBLK_SIZE * JRNL_SBLK_SIZE);
+ }
+ }
+};
+
+const string
+get_test_name(const string& file, const string& test_name)
+{
+ cout << test_filename << "." << test_name << ": " << flush;
+ return file + "." + test_name;
+}
+
+bool
+check_iores(const string& ctxt, const iores ret, const iores exp_ret, test_dtok* dtp)
+{
+ if (ret != exp_ret)
+ {
+ delete dtp;
+ BOOST_FAIL(ctxt << ": Expected " << iores_str(exp_ret) << "; got " << iores_str(ret));
+ }
+ return false;
+}
+
+bool
+handle_jcntl_response(const iores res, jcntl& jc, unsigned& aio_sleep_cnt, const std::string& ctxt, const iores exp_ret,
+ test_dtok* dtp)
+{
+ if (res == RHM_IORES_PAGE_AIOWAIT)
+ {
+ if (++aio_sleep_cnt <= MAX_AIO_SLEEPS)
+ {
+ jc.get_wr_events(0); // *** GEV2
+ usleep(AIO_SLEEP_TIME);
+ }
+ else
+ return check_iores(ctxt, res, exp_ret, dtp);
+ }
+ else
+ return check_iores(ctxt, res, exp_ret, dtp);
+ return true;
+}
+
+u_int64_t
+enq_msg(jcntl& jc,
+ const u_int64_t rid,
+ const string& msg,
+ const bool transient,
+ const iores exp_ret = RHM_IORES_SUCCESS)
+{
+ ostringstream ctxt;
+ ctxt << "enq_msg(" << rid << ")";
+ test_dtok* dtp = new test_dtok;
+ BOOST_CHECK_MESSAGE(dtp != 0, "Data token allocation failed (dtp == 0).");
+ dtp->set_rid(rid);
+ dtp->set_external_rid(true);
+ try
+ {
+ iores res = jc.enqueue_data_record(msg.c_str(), msg.size(), msg.size(), dtp, transient);
+ check_iores(ctxt.str(), res, exp_ret, dtp);
+ u_int64_t dtok_rid = dtp->rid();
+ if (dtp->done()) delete dtp;
+ return dtok_rid;
+ }
+ catch (exception& e) { delete dtp; throw; }
+}
+
+u_int64_t
+enq_extern_msg(jcntl& jc, const u_int64_t rid, const std::size_t msg_size, const bool transient,
+ const iores exp_ret = RHM_IORES_SUCCESS)
+{
+ ostringstream ctxt;
+ ctxt << "enq_extern_msg(" << rid << ")";
+ test_dtok* dtp = new test_dtok;
+ BOOST_CHECK_MESSAGE(dtp != 0, "Data token allocation failed (dtp == 0).");
+ dtp->set_rid(rid);
+ dtp->set_external_rid(true);
+ try
+ {
+ iores res = jc.enqueue_extern_data_record(msg_size, dtp, transient);
+ check_iores(ctxt.str(), res, exp_ret, dtp);
+ u_int64_t dtok_rid = dtp->rid();
+ if (dtp->done()) delete dtp;
+ return dtok_rid;
+ }
+ catch (exception& e) { delete dtp; throw; }
+}
+
+u_int64_t
+enq_txn_msg(jcntl& jc, const u_int64_t rid, const string& msg, const string& xid, const bool transient,
+ const iores exp_ret = RHM_IORES_SUCCESS)
+{
+ ostringstream ctxt;
+ ctxt << "enq_txn_msg(" << rid << ")";
+ test_dtok* dtp = new test_dtok;
+ BOOST_CHECK_MESSAGE(dtp != 0, "Data token allocation failed (dtp == 0).");
+ dtp->set_rid(rid);
+ dtp->set_external_rid(true);
+ try
+ {
+ iores res = jc.enqueue_txn_data_record(msg.c_str(), msg.size(), msg.size(), dtp, xid,
+ transient);
+ check_iores(ctxt.str(), res, exp_ret, dtp);
+ u_int64_t dtok_rid = dtp->rid();
+ if (dtp->done()) delete dtp;
+ return dtok_rid;
+ }
+ catch (exception& e) { delete dtp; throw; }
+}
+
+u_int64_t
+enq_extern_txn_msg(jcntl& jc, const u_int64_t rid, const std::size_t msg_size, const string& xid, const bool transient,
+ const iores exp_ret = RHM_IORES_SUCCESS)
+{
+ ostringstream ctxt;
+ ctxt << "enq_extern_txn_msg(" << rid << ")";
+ test_dtok* dtp = new test_dtok;
+ BOOST_CHECK_MESSAGE(dtp != 0, "Data token allocation failed (dtp == 0).");
+ dtp->set_rid(rid);
+ dtp->set_external_rid(true);
+ try
+ {
+ iores res = jc.enqueue_extern_txn_data_record(msg_size, dtp, xid, transient);
+ check_iores(ctxt.str(), res, exp_ret, dtp);
+ u_int64_t dtok_rid = dtp->rid();
+ if (dtp->done()) delete dtp;
+ return dtok_rid;
+ }
+ catch (exception& e) { delete dtp; throw; }
+}
+
+u_int64_t
+deq_msg(jcntl& jc, const u_int64_t drid, const u_int64_t rid, const iores exp_ret = RHM_IORES_SUCCESS)
+{
+ ostringstream ctxt;
+ ctxt << "deq_msg(" << drid << ")";
+ test_dtok* dtp = new test_dtok;
+ BOOST_CHECK_MESSAGE(dtp != 0, "Data token allocation failed (dtp == 0).");
+ dtp->set_rid(rid);
+ dtp->set_dequeue_rid(drid);
+ dtp->set_external_rid(true);
+ dtp->set_wstate(data_tok::ENQ);
+ try
+ {
+ iores res = jc.dequeue_data_record(dtp);
+ check_iores(ctxt.str(), res, exp_ret, dtp);
+ u_int64_t dtok_rid = dtp->rid();
+ if (dtp->done()) delete dtp;
+ return dtok_rid;
+ }
+ catch (exception& e) { delete dtp; throw; }
+}
+
+u_int64_t
+deq_txn_msg(jcntl& jc, const u_int64_t drid, const u_int64_t rid, const string& xid,
+ const iores exp_ret = RHM_IORES_SUCCESS)
+{
+ ostringstream ctxt;
+ ctxt << "deq_txn_msg(" << drid << ")";
+ test_dtok* dtp = new test_dtok;
+ BOOST_CHECK_MESSAGE(dtp != 0, "Data token allocation failed (dtp == 0).");
+ dtp->set_rid(rid);
+ dtp->set_dequeue_rid(drid);
+ dtp->set_external_rid(true);
+ dtp->set_wstate(data_tok::ENQ);
+ try
+ {
+ iores res = jc.dequeue_txn_data_record(dtp, xid);
+ check_iores(ctxt.str(), res, exp_ret, dtp);
+ u_int64_t dtok_rid = dtp->rid();
+ if (dtp->done()) delete dtp;
+ return dtok_rid;
+ }
+ catch (exception& e) { delete dtp; throw; }
+}
+
+u_int64_t
+txn_abort(jcntl& jc, const u_int64_t rid, const string& xid, const iores exp_ret = RHM_IORES_SUCCESS)
+{
+ test_dtok* dtp = new test_dtok;
+ BOOST_CHECK_MESSAGE(dtp != 0, "Data token allocation failed (dtp == 0).");
+ dtp->set_rid(rid);
+ dtp->set_external_rid(true);
+ try
+ {
+ iores res = jc.txn_abort(dtp, xid);
+ check_iores("txn_abort", res, exp_ret, dtp);
+ u_int64_t dtok_rid = dtp->rid();
+ if (dtp->done()) delete dtp;
+ return dtok_rid;
+ }
+ catch (exception& e) { delete dtp; throw; }
+}
+
+u_int64_t
+txn_commit(jcntl& jc, const u_int64_t rid, const string& xid, const iores exp_ret = RHM_IORES_SUCCESS)
+{
+ test_dtok* dtp = new test_dtok;
+ BOOST_CHECK_MESSAGE(dtp != 0, "Data token allocation failed (dtp == 0).");
+ dtp->set_rid(rid);
+ dtp->set_external_rid(true);
+ try
+ {
+ iores res = jc.txn_commit(dtp, xid);
+ check_iores("txn_commit", res, exp_ret, dtp);
+ u_int64_t dtok_rid = dtp->rid();
+ if (dtp->done()) delete dtp;
+ return dtok_rid;
+ }
+ catch (exception& e) { delete dtp; throw; }
+}
+
+void
+read_msg(jcntl& jc, string& msg, string& xid, bool& transient, bool& external, const iores exp_ret = RHM_IORES_SUCCESS)
+{
+ void* mp = 0;
+ std::size_t msize = 0;
+ void* xp = 0;
+ std::size_t xsize = 0;
+ test_dtok* dtp = new test_dtok;
+ BOOST_CHECK_MESSAGE(dtp != 0, "Data token allocation failed (dtp == 0).");
+ dtp->set_wstate(data_tok::ENQ);
+
+ unsigned aio_sleep_cnt = 0;
+ try
+ {
+ iores res = jc.read_data_record(&mp, msize, &xp, xsize, transient, external, dtp);
+ while (handle_jcntl_response(res, jc, aio_sleep_cnt, "read_msg", exp_ret, dtp))
+ res = jc.read_data_record(&mp, msize, &xp, xsize, transient, external, dtp);
+ }
+ catch (exception& e) { delete dtp; throw; }
+
+ if (mp)
+ msg.assign((char*)mp, msize);
+ if (xp)
+ {
+ xid.assign((char*)xp, xsize);
+ std::free(xp);
+ xp = 0;
+ }
+ else if (mp)
+ {
+ std::free(mp);
+ mp = 0;
+ }
+ delete dtp;
+}
+
+/*
+ * Returns the number of messages of size msg_rec_size_dblks that will fit into an empty journal with or without
+ * corresponding dequeues (controlled by include_deq) without a threshold - ie until the journal is full. Assumes
+ * that dequeue records fit into one dblk.
+ */
+u_int32_t
+num_msgs_to_full(const u_int16_t num_files, const u_int32_t file_size_dblks, const u_int32_t msg_rec_size_dblks,
+ bool include_deq)
+{
+ u_int32_t rec_size_dblks = msg_rec_size_dblks;
+ if (include_deq)
+ rec_size_dblks++;
+ return u_int32_t(::floor(1.0 * num_files * file_size_dblks / rec_size_dblks));
+}
+
+/*
+ * Returns the number of messages of size msg_rec_size_dblks that will fit into an empty journal before the enqueue
+ * threshold of JRNL_ENQ_THRESHOLD (%).
+ */
+u_int32_t
+num_msgs_to_threshold(const u_int16_t num_files, const u_int32_t file_size_dblks, const u_int32_t msg_rec_size_dblks)
+{
+ return u_int32_t(::floor(1.0 * num_files * file_size_dblks * JRNL_ENQ_THRESHOLD / msg_rec_size_dblks / 100));
+}
+
+/*
+ * Returns the amount of space reserved in dblks (== num dequeues assuming dequeue size of 1 dblk) for the enqueue
+ * threshold of JRNL_ENQ_THRESHOLD (%).
+ */
+u_int32_t
+num_dequeues_rem(const u_int16_t num_files, const u_int32_t file_size_dblks)
+{
+ /*
+ * Fraction of journal remaining after threshold is used --------------+
+ * Total no. dblks in journal ------+ |
+ * | |
+ * +------------+------------+ +-----------------+---------------------+
+ */
+ return u_int32_t(::ceil(num_files * file_size_dblks * (1.0 - (1.0 * JRNL_ENQ_THRESHOLD / 100))));
+}
+
+string&
+create_msg(string& s, const int msg_num, const int len)
+{
+ ostringstream oss;
+ oss << "MSG_" << setfill('0') << setw(6) << msg_num << "_";
+ for (int i=12; i<=len; i++)
+ oss << (char)('0' + i%10);
+ s.assign(oss.str());
+ return s;
+}
+
+string&
+create_xid(string& s, const int msg_num, const int len)
+{
+ ostringstream oss;
+ oss << "XID_" << setfill('0') << setw(6) << msg_num << "_";
+ for (int i=11; i<len; i++)
+ oss << (char)('a' + i%26);
+ s.assign(oss.str());
+ return s;
+}
+
+long
+get_seed()
+{
+ timespec ts;
+ if (::clock_gettime(CLOCK_REALTIME, &ts))
+ BOOST_FAIL("Unable to read clock to generate seed.");
+ long tenths = ts.tv_nsec / 100000000;
+ return long(10 * ts.tv_sec + tenths); // time in tenths of a second
+}
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/_st_read.cpp b/qpid/cpp/src/tests/legacystore/jrnl/_st_read.cpp
new file mode 100644
index 0000000000..ff2c39e14c
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/_st_read.cpp
@@ -0,0 +1,460 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../unit_test.h"
+#include <cmath>
+#include <iostream>
+#include "qpid/legacystore/jrnl/jcntl.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(journal_read)
+
+const string test_filename("_st_read");
+
+#include "_st_helper_fns.h"
+
+// === Test suite ===
+
+#ifndef LONG_TEST
+/*
+ * ==============================================
+ * NORMAL TESTS
+ * This section contains normal "make check" tests
+ * for building/packaging. These are built when
+ * LONG_TEST is _not_ defined.
+ * ==============================================
+ */
+
+QPID_AUTO_TEST_CASE(empty_read)
+{
+ string test_name = get_test_name(test_filename, "empty_read");
+ try
+ {
+ string msg;
+ string rmsg;
+ string xid;
+ bool transientFlag;
+ bool externalFlag;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_read_dequeue_block)
+{
+ string test_name = get_test_name(test_filename, "enqueue_read_dequeue_block");
+ try
+ {
+ string msg;
+ string rmsg;
+ string xid;
+ bool transientFlag;
+ bool externalFlag;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<NUM_MSGS; m++)
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false);
+ jc.flush();
+ for (int m=0; m<NUM_MSGS; m++)
+ {
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag);
+ BOOST_CHECK_EQUAL(create_msg(msg, m, MSG_SIZE), rmsg);
+ BOOST_CHECK_EQUAL(xid.size(), std::size_t(0));
+ BOOST_CHECK_EQUAL(transientFlag, false);
+ BOOST_CHECK_EQUAL(externalFlag, false);
+ }
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ for (int m=0; m<NUM_MSGS; m++)
+ deq_msg(jc, m, m+NUM_MSGS);
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_read_dequeue_interleaved)
+{
+ string test_name = get_test_name(test_filename, "enqueue_read_dequeue_interleaved");
+ try
+ {
+ string msg;
+ string rmsg;
+ string xid;
+ bool transientFlag;
+ bool externalFlag;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<500*NUM_MSGS; m+=2)
+ {
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false);
+ jc.flush();
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag);
+ BOOST_CHECK_EQUAL(create_msg(msg, m, MSG_SIZE), rmsg);
+ BOOST_CHECK_EQUAL(xid.size(), std::size_t(0));
+ BOOST_CHECK_EQUAL(transientFlag, false);
+ BOOST_CHECK_EQUAL(externalFlag, false);
+ deq_msg(jc, m, m+1);
+ jc.flush();
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_recovered_read_dequeue)
+{
+ string test_name = get_test_name(test_filename, "enqueue_recovered_read_dequeue");
+ try
+ {
+ {
+ string msg;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<NUM_MSGS; m++)
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false);
+ }
+ {
+ string msg;
+ u_int64_t hrid;
+ string rmsg;
+ string xid;
+ bool transientFlag;
+ bool externalFlag;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.recover(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS, 0, hrid);
+ BOOST_CHECK_EQUAL(hrid, u_int64_t(NUM_MSGS - 1));
+ jc.recover_complete();
+ for (int m=0; m<NUM_MSGS; m++)
+ {
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag);
+ BOOST_CHECK_EQUAL(create_msg(msg, m, MSG_SIZE), rmsg);
+ BOOST_CHECK_EQUAL(xid.size(), std::size_t(0));
+ BOOST_CHECK_EQUAL(transientFlag, false);
+ BOOST_CHECK_EQUAL(externalFlag, false);
+ }
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ for (int m=0; m<NUM_MSGS; m++)
+ deq_msg(jc, m, m+NUM_MSGS);
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(multi_page_enqueue_recovered_read_dequeue_block)
+{
+ string test_name = get_test_name(test_filename, "multi_page_enqueue_recovered_read_dequeue_block");
+ try
+ {
+ {
+ string msg;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(2*NUM_TEST_JFILES, false, 0, 10*TEST_JFSIZE_SBLKS);
+ for (int m=0; m<NUM_MSGS*125; m++)
+ enq_msg(jc, m, create_msg(msg, m, 16*MSG_SIZE), false);
+ }
+ {
+ string msg;
+ u_int64_t hrid;
+ string rmsg;
+ string xid;
+ bool transientFlag;
+ bool externalFlag;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.recover(2*NUM_TEST_JFILES, false, 0, 10*TEST_JFSIZE_SBLKS, 0, hrid);
+ BOOST_CHECK_EQUAL(hrid, u_int64_t(NUM_MSGS*125 - 1));
+ jc.recover_complete();
+ for (int m=0; m<NUM_MSGS*125; m++)
+ {
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag);
+ BOOST_CHECK_EQUAL(create_msg(msg, m, 16*MSG_SIZE), rmsg);
+ BOOST_CHECK_EQUAL(xid.size(), std::size_t(0));
+ BOOST_CHECK_EQUAL(transientFlag, false);
+ BOOST_CHECK_EQUAL(externalFlag, false);
+ }
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ for (int m=0; m<NUM_MSGS*125; m++)
+ deq_msg(jc, m, m+NUM_MSGS*125);
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_recover_read_recovered_read_dequeue_block)
+{
+ string test_name = get_test_name(test_filename, "enqueue_recover_read_recovered_read_dequeue_block");
+ try
+ {
+ {
+ string msg;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<NUM_MSGS; m++)
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false);
+ }
+ {
+ string msg;
+ u_int64_t hrid;
+ string rmsg;
+ string xid;
+ bool transientFlag;
+ bool externalFlag;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.recover(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS, 0, hrid);
+ BOOST_CHECK_EQUAL(hrid, u_int64_t(NUM_MSGS - 1));
+ for (int m=0; m<NUM_MSGS; m++)
+ {
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag);
+ BOOST_CHECK_EQUAL(create_msg(msg, m, MSG_SIZE), rmsg);
+ BOOST_CHECK_EQUAL(xid.size(), std::size_t(0));
+ BOOST_CHECK_EQUAL(transientFlag, false);
+ BOOST_CHECK_EQUAL(externalFlag, false);
+ }
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ }
+ {
+ string msg;
+ u_int64_t hrid;
+ string rmsg;
+ string xid;
+ bool transientFlag;
+ bool externalFlag;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.recover(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS, 0, hrid);
+ BOOST_CHECK_EQUAL(hrid, u_int64_t(NUM_MSGS - 1));
+ for (int m=0; m<NUM_MSGS; m++)
+ {
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag);
+ BOOST_CHECK_EQUAL(create_msg(msg, m, MSG_SIZE), rmsg);
+ BOOST_CHECK_EQUAL(xid.size(), std::size_t(0));
+ BOOST_CHECK_EQUAL(transientFlag, false);
+ BOOST_CHECK_EQUAL(externalFlag, false);
+ }
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ jc.recover_complete();
+ for (int m=0; m<NUM_MSGS; m++)
+ {
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag);
+ BOOST_CHECK_EQUAL(create_msg(msg, m, MSG_SIZE), rmsg);
+ BOOST_CHECK_EQUAL(xid.size(), std::size_t(0));
+ BOOST_CHECK_EQUAL(transientFlag, false);
+ BOOST_CHECK_EQUAL(externalFlag, false);
+ }
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ for (int m=0; m<NUM_MSGS; m++)
+ deq_msg(jc, m, m+NUM_MSGS);
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(delayed_read)
+{
+ string test_name = get_test_name(test_filename, "delayed_read");
+ try
+ {
+ string msg;
+ string rmsg;
+ string xid;
+ bool transientFlag;
+ bool externalFlag;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ unsigned m;
+ for (m=0; m<2*NUM_MSGS; m+=2)
+ {
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false);
+ deq_msg(jc, m, m+1);
+ }
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false);
+ jc.flush();
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag);
+ BOOST_CHECK_EQUAL(msg, rmsg);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(cache_cycled_delayed_read)
+{
+ string test_name = get_test_name(test_filename, "cache_cycled_delayed_read");
+ try
+ {
+ string msg;
+ string rmsg;
+ string xid;
+ bool transientFlag;
+ bool externalFlag;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ unsigned m;
+ unsigned read_buffer_size_dblks = JRNL_RMGR_PAGES * JRNL_RMGR_PAGE_SIZE * JRNL_SBLK_SIZE;
+ unsigned n = num_msgs_to_full(1, read_buffer_size_dblks, 16*MSG_REC_SIZE_DBLKS, true);
+ for (m=0; m<2*2*n + 20; m+=2) // fill read buffer twice + 10 msgs
+ {
+ enq_msg(jc, m, create_msg(msg, m, 16*MSG_SIZE), false);
+ deq_msg(jc, m, m+1);
+ }
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false);
+ jc.flush();
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag);
+ BOOST_CHECK_EQUAL(msg, rmsg);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+#else
+/*
+ * ==============================================
+ * LONG TESTS
+ * This section contains long tests and soak tests,
+ * and are run using target check-long (ie "make
+ * check-long"). These are built when LONG_TEST is
+ * defined.
+ * ==============================================
+ */
+
+QPID_AUTO_TEST_CASE(multi_page_enqueue_read_dequeue_block)
+{
+ string test_name = get_test_name(test_filename, "multi_page_enqueue_read_dequeue_block");
+ try
+ {
+ string msg;
+ string rmsg;
+ string xid;
+ bool transientFlag;
+ bool externalFlag;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(2*NUM_TEST_JFILES, false, 0, 10*TEST_JFSIZE_SBLKS);
+ for (int i=0; i<10; i++)
+ {
+ for (int m=0; m<NUM_MSGS*125; m++)
+ enq_msg(jc, m, create_msg(msg, m, 16*MSG_SIZE), false);
+ jc.flush();
+ for (int m=0; m<NUM_MSGS*125; m++)
+ {
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag);
+ BOOST_CHECK_EQUAL(create_msg(msg, m, 16*MSG_SIZE), rmsg);
+ BOOST_CHECK_EQUAL(xid.size(), std::size_t(0));
+ BOOST_CHECK_EQUAL(transientFlag, false);
+ BOOST_CHECK_EQUAL(externalFlag, false);
+ }
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ for (int m=0; m<NUM_MSGS*125; m++)
+ deq_msg(jc, m, m+NUM_MSGS*125);
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(increasing_interval_delayed_read)
+{
+ string test_name = get_test_name(test_filename, "increasing_interval_delayed_read");
+ try
+ {
+ string msg;
+ string rmsg;
+ string xid;
+ bool transientFlag;
+ bool externalFlag;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ unsigned read_buffer_size_dblks = JRNL_RMGR_PAGES * JRNL_RMGR_PAGE_SIZE * JRNL_SBLK_SIZE;
+ unsigned n = num_msgs_to_full(1, read_buffer_size_dblks, MSG_REC_SIZE_DBLKS, true);
+ unsigned m = 0;
+
+ // Validate read pipeline
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false);
+ jc.flush();
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag);
+ deq_msg(jc, m, m+1);
+ m += 2;
+
+ // repeat the following multiple times...
+ for (int i=0; i<10; i++)
+ {
+ // Invalidate read pipeline with large write
+ unsigned t = m + (i*n) + 25;
+ for (; m<t; m+=2)
+ {
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false);
+ deq_msg(jc, m, m+1);
+ }
+
+ // Revalidate read pipeline
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false);
+ jc.flush();
+ read_msg(jc, rmsg, xid, transientFlag, externalFlag);
+ BOOST_CHECK_EQUAL(msg, rmsg);
+ deq_msg(jc, m, m+1);
+ m += 2;
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+#endif
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/_st_read_txn.cpp b/qpid/cpp/src/tests/legacystore/jrnl/_st_read_txn.cpp
new file mode 100644
index 0000000000..621777d8d3
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/_st_read_txn.cpp
@@ -0,0 +1,353 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../unit_test.h"
+#include <cmath>
+#include <iostream>
+#include "qpid/legacystore/jrnl/jcntl.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(journal_read_txn)
+
+const string test_filename("_st_read_txn");
+
+#include "_st_helper_fns.h"
+
+// === Test suite ===
+
+QPID_AUTO_TEST_CASE(tx_enqueue_commit_block)
+{
+ string test_name = get_test_name(test_filename, "tx_enqueue_commit_block");
+ try
+ {
+ string msg;
+ string xid;
+ string rmsg;
+ string rxid;
+ bool transientFlag;
+ bool externalFlag;
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ create_xid(xid, 0, XID_SIZE);
+ for (int m=0; m<NUM_MSGS; m++)
+ enq_txn_msg(jc, m, create_msg(msg, m, MSG_SIZE), xid, false);
+ jc.flush();
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag, RHM_IORES_TXPENDING);
+ txn_commit(jc, NUM_MSGS, xid);
+ jc.flush();
+ for (int m=0; m<NUM_MSGS; m++)
+ {
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag);
+ BOOST_CHECK_EQUAL(create_msg(msg, m, MSG_SIZE), rmsg);
+ BOOST_CHECK_EQUAL(rxid, xid);
+ BOOST_CHECK_EQUAL(transientFlag, false);
+ BOOST_CHECK_EQUAL(externalFlag, false);
+ }
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(tx_enqueue_commit_interleaved)
+{
+ string test_name = get_test_name(test_filename, "tx_enqueue_commit_interleaved");
+ try
+ {
+ string msg;
+ string xid;
+ string rmsg;
+ string rxid;
+ bool transientFlag;
+ bool externalFlag;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<NUM_MSGS; m++)
+ {
+ create_xid(xid, 2*m, XID_SIZE);
+ enq_txn_msg(jc, 2*m, create_msg(msg, 2*m, MSG_SIZE), xid, false);
+ jc.flush();
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag, RHM_IORES_TXPENDING);
+ txn_commit(jc, 2*m+1, xid);
+ jc.flush();
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag);
+ BOOST_CHECK_EQUAL(create_msg(msg, 2*m, MSG_SIZE), rmsg);
+ BOOST_CHECK_EQUAL(rxid, xid);
+ BOOST_CHECK_EQUAL(transientFlag, false);
+ BOOST_CHECK_EQUAL(externalFlag, false);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(tx_enqueue_abort_block)
+{
+ string test_name = get_test_name(test_filename, "tx_enqueue_abort_block");
+ try
+ {
+ string msg;
+ string xid;
+ string rmsg;
+ string rxid;
+ bool transientFlag;
+ bool externalFlag;
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ create_xid(xid, 1, XID_SIZE);
+ for (int m=0; m<NUM_MSGS; m++)
+ enq_txn_msg(jc, m, create_msg(msg, m, MSG_SIZE), xid, false);
+ jc.flush();
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag, RHM_IORES_TXPENDING);
+ txn_abort(jc, NUM_MSGS, xid);
+ jc.flush();
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(tx_enqueue_abort_interleaved)
+{
+ string test_name = get_test_name(test_filename, "tx_enqueue_abort_interleaved");
+ try
+ {
+ string msg;
+ string xid;
+ string rmsg;
+ string rxid;
+ bool transientFlag;
+ bool externalFlag;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<NUM_MSGS; m++)
+ {
+ create_xid(xid, 2*m, XID_SIZE);
+ enq_txn_msg(jc, 2*m, create_msg(msg, 2*m, MSG_SIZE), xid, false);
+ jc.flush();
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag, RHM_IORES_TXPENDING);
+ txn_abort(jc, 2*m+1, xid);
+ jc.flush();
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(tx_enqueue_commit_dequeue_block)
+{
+ string test_name = get_test_name(test_filename, "tx_enqueue_commit_dequeue_block");
+ try
+ {
+ string msg;
+ string xid;
+ string rmsg;
+ string rxid;
+ bool transientFlag;
+ bool externalFlag;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ create_xid(xid, 2, XID_SIZE);
+ for (int m=0; m<NUM_MSGS; m++)
+ enq_txn_msg(jc, m, create_msg(msg, m, MSG_SIZE), xid, false);
+ txn_commit(jc, NUM_MSGS, xid);
+ for (int m=0; m<NUM_MSGS; m++)
+ deq_msg(jc, m, m+NUM_MSGS+1);
+ jc.flush();
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(tx_enqueue_commit_dequeue_interleaved)
+{
+ string test_name = get_test_name(test_filename, "tx_enqueue_commit_dequeue_interleaved");
+ try
+ {
+ string msg;
+ string xid;
+ string rmsg;
+ string rxid;
+ bool transientFlag;
+ bool externalFlag;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<NUM_MSGS; m++)
+ {
+ create_xid(xid, 3*m, XID_SIZE);
+ enq_txn_msg(jc, 3*m, create_msg(msg, m, MSG_SIZE), xid, false);
+ txn_commit(jc, 3*m+1, xid);
+ deq_msg(jc, 3*m, 3*m+2);
+ jc.flush();
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_tx_dequeue_commit_block)
+{
+ string test_name = get_test_name(test_filename, "enqueue_tx_dequeue_commit_block");
+ try
+ {
+ string msg;
+ string xid;
+ string rmsg;
+ string rxid;
+ bool transientFlag;
+ bool externalFlag;
+
+ create_xid(xid, 3, XID_SIZE);
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<NUM_MSGS; m++)
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false);
+ for (int m=0; m<NUM_MSGS; m++)
+ deq_txn_msg(jc, m, m+NUM_MSGS, xid);
+ jc.flush();
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag, RHM_IORES_TXPENDING);
+ txn_commit(jc, 2*NUM_MSGS, xid);
+ jc.flush();
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_tx_dequeue_commit_interleaved)
+{
+ string test_name = get_test_name(test_filename, "enqueue_tx_dequeue_commit_interleaved");
+ try
+ {
+ string msg;
+ string xid;
+ string rmsg;
+ string rxid;
+ bool transientFlag;
+ bool externalFlag;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<NUM_MSGS; m++)
+ {
+ enq_msg(jc, 3*m, create_msg(msg, 3*m, MSG_SIZE), false);
+ create_xid(xid, 3*m, XID_SIZE);
+ deq_txn_msg(jc, 3*m, 3*m+1, xid);
+ jc.flush();
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag, RHM_IORES_TXPENDING);
+ txn_commit(jc, 3*m+2, xid);
+ jc.flush();
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_tx_dequeue_abort_block)
+{
+ string test_name = get_test_name(test_filename, "enqueue_tx_dequeue_abort_block");
+ try
+ {
+ string msg;
+ string xid;
+ string rmsg;
+ string rxid;
+ bool transientFlag;
+ bool externalFlag;
+
+ create_xid(xid, 4, XID_SIZE);
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<NUM_MSGS; m++)
+ enq_msg(jc, m, create_msg(msg, m, MSG_SIZE), false);
+ for (int m=0; m<NUM_MSGS; m++)
+ deq_txn_msg(jc, m, m+NUM_MSGS, xid);
+ jc.flush();
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag, RHM_IORES_TXPENDING);
+ txn_abort(jc, 2*NUM_MSGS, xid);
+ jc.flush();
+ for (int m=0; m<NUM_MSGS; m++)
+ {
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag);
+ BOOST_CHECK_EQUAL(create_msg(msg, m, MSG_SIZE), rmsg);
+ BOOST_CHECK_EQUAL(rxid.length(), std::size_t(0));
+ BOOST_CHECK_EQUAL(transientFlag, false);
+ BOOST_CHECK_EQUAL(externalFlag, false);
+ }
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enqueue_tx_dequeue_abort_interleaved)
+{
+ string test_name = get_test_name(test_filename, "enqueue_tx_dequeue_abort_interleaved");
+ try
+ {
+ string msg;
+ string xid;
+ string rmsg;
+ string rxid;
+ bool transientFlag;
+ bool externalFlag;
+
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ jc.initialize(NUM_TEST_JFILES, false, 0, TEST_JFSIZE_SBLKS);
+ for (int m=0; m<NUM_MSGS; m++)
+ {
+ enq_msg(jc, 3*m, create_msg(msg, 3*m, MSG_SIZE), false);
+ create_xid(xid, 3*m, XID_SIZE);
+ deq_txn_msg(jc, 3*m, 3*m+1, xid);
+ jc.flush();
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag, RHM_IORES_TXPENDING);
+ txn_abort(jc, 3*m+2, xid);
+ jc.flush();
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag);
+ read_msg(jc, rmsg, rxid, transientFlag, externalFlag, RHM_IORES_EMPTY);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/_ut_enq_map.cpp b/qpid/cpp/src/tests/legacystore/jrnl/_ut_enq_map.cpp
new file mode 100644
index 0000000000..f05dcb824c
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/_ut_enq_map.cpp
@@ -0,0 +1,320 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../unit_test.h"
+
+#include <iostream>
+#include "qpid/legacystore/jrnl/enq_map.h"
+#include "qpid/legacystore/jrnl/jerrno.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(enq_map_suite)
+
+const string test_filename("_ut_enq_map");
+
+QPID_AUTO_TEST_CASE(constructor)
+{
+ cout << test_filename << ".constructor: " << flush;
+ enq_map e1;
+ BOOST_CHECK(e1.empty());
+ BOOST_CHECK_EQUAL(e1.size(), u_int32_t(0));
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(insert_get)
+{
+ cout << test_filename << ".insert_get: " << flush;
+ u_int16_t pfid;
+ u_int64_t rid;
+ u_int16_t pfid_start = 0x2000U;
+ u_int64_t rid_begin = 0xffffffff00000000ULL;
+ u_int64_t rid_end = 0xffffffff00000200ULL;
+
+ // insert with no dups
+ u_int64_t rid_incr_1 = 4ULL;
+ enq_map e2;
+ e2.set_num_jfiles(pfid_start + (rid_end - rid_begin)/rid_incr_1);
+ for (rid = rid_begin, pfid = pfid_start; rid < rid_end; rid += rid_incr_1, pfid++)
+ BOOST_CHECK_EQUAL(e2.insert_pfid(rid, pfid), enq_map::EMAP_OK);
+ BOOST_CHECK(!e2.empty());
+ BOOST_CHECK_EQUAL(e2.size(), u_int32_t(128));
+
+ // get
+ u_int64_t rid_incr_2 = 6ULL;
+ for (u_int64_t rid = rid_begin; rid < rid_end; rid += rid_incr_2)
+ {
+ BOOST_CHECK_EQUAL(e2.is_enqueued(rid), (rid%rid_incr_1 ? false : true));
+ u_int16_t exp_pfid = pfid_start + (u_int16_t)((rid - rid_begin)/rid_incr_1);
+ int16_t ret_fid = e2.get_pfid(rid);
+ if (ret_fid < enq_map::EMAP_OK) // fail
+ {
+ BOOST_CHECK_EQUAL(ret_fid, enq_map::EMAP_RID_NOT_FOUND);
+ BOOST_CHECK(rid%rid_incr_1);
+ }
+ else
+ {
+ BOOST_CHECK_EQUAL(ret_fid, exp_pfid);
+ BOOST_CHECK(rid%rid_incr_1 == 0);
+ }
+ if ((rid + rid_incr_2)%(8 * rid_incr_2) == 0)
+ pfid++;
+ }
+
+ // insert with dups
+ for (rid = rid_begin, pfid = pfid_start; rid < rid_end; rid += rid_incr_2, pfid++)
+ {
+ int16_t res = e2.insert_pfid(rid, pfid);
+ if (res < enq_map::EMAP_OK) // fail
+ {
+ BOOST_CHECK_EQUAL(res, enq_map::EMAP_DUP_RID);
+ BOOST_CHECK(rid%rid_incr_1 == 0);
+ }
+ else
+ BOOST_CHECK(rid%rid_incr_1);
+ }
+ BOOST_CHECK_EQUAL(e2.size(), u_int32_t(171));
+ e2.clear();
+ BOOST_CHECK(e2.empty());
+ BOOST_CHECK_EQUAL(e2.size(), u_int32_t(0));
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(get_remove)
+{
+ cout << test_filename << ".get_remove: " << flush;
+ u_int16_t pfid;
+ u_int64_t rid;
+ u_int16_t pfid_start = 0x3000U;
+ u_int64_t rid_begin = 0xeeeeeeee00000000ULL;
+ u_int64_t rid_end = 0xeeeeeeee00000200ULL;
+
+ u_int64_t rid_incr_1 = 4ULL;
+ u_int64_t num_incr_1 = (rid_end - rid_begin)/rid_incr_1;
+ enq_map e3;
+ e3.set_num_jfiles(pfid_start + (rid_end - rid_begin)/rid_incr_1);
+ for (rid = rid_begin, pfid = pfid_start; rid < rid_end; rid += rid_incr_1, pfid++)
+ BOOST_CHECK_EQUAL(e3.insert_pfid(rid, pfid), enq_map::EMAP_OK);
+ BOOST_CHECK_EQUAL(e3.size(), num_incr_1);
+
+ u_int64_t rid_incr_2 = 6ULL;
+ for (rid = rid_begin, pfid = pfid_start; rid < rid_end; rid += rid_incr_2, pfid++)
+ {
+ u_int16_t exp_pfid = pfid_start + (u_int16_t)((rid - rid_begin)/rid_incr_1);
+ int16_t ret_fid = e3.get_remove_pfid(rid);
+ if (ret_fid < enq_map::EMAP_OK) // fail
+ {
+ BOOST_CHECK_EQUAL(ret_fid, enq_map::EMAP_RID_NOT_FOUND);
+ BOOST_CHECK(rid%rid_incr_1);
+ }
+ else
+ {
+ BOOST_CHECK_EQUAL(ret_fid, exp_pfid);
+ BOOST_CHECK(rid%rid_incr_1 == 0);
+ }
+ }
+ BOOST_CHECK_EQUAL(e3.size(), u_int32_t(85));
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(lock)
+{
+ cout << test_filename << ".lock: " << flush;
+ u_int16_t pfid;
+ u_int64_t rid;
+ u_int16_t pfid_start = 0x4000U;
+ u_int64_t rid_begin = 0xdddddddd00000000ULL;
+ u_int64_t rid_end = 0xdddddddd00000200ULL;
+
+ // insert, every second entry is locked
+ u_int64_t rid_incr_1 = 4ULL;
+ u_int64_t num_incr_1 = (rid_end - rid_begin)/rid_incr_1;
+ bool locked = false;
+ enq_map e4;
+ e4.set_num_jfiles(pfid_start + (rid_end - rid_begin)/rid_incr_1);
+ for (rid = rid_begin, pfid = pfid_start; rid < rid_end; rid += rid_incr_1, pfid++)
+ {
+ BOOST_CHECK_EQUAL(e4.insert_pfid(rid, pfid, locked), enq_map::EMAP_OK);
+ locked = !locked;
+ }
+ BOOST_CHECK_EQUAL(e4.size(), num_incr_1);
+
+ // unlock and lock non-existent rids
+ int16_t res = e4.lock(1ULL);
+ if (res < enq_map::EMAP_OK)
+ BOOST_CHECK_EQUAL(res, enq_map::EMAP_RID_NOT_FOUND);
+ else
+ BOOST_ERROR("Failed to detect locking non-existent rid.");
+ res = e4.unlock(2ULL);
+ if (res < enq_map::EMAP_OK)
+ BOOST_CHECK_EQUAL(res, enq_map::EMAP_RID_NOT_FOUND);
+ else
+ BOOST_ERROR("Failed to detect unlocking non-existent rid.");
+
+ // get / unlock
+ for (u_int64_t rid = rid_begin; rid < rid_end; rid += rid_incr_1)
+ {
+ int16_t fid = e4.get_pfid(rid);
+ if (fid < enq_map::EMAP_OK) // fail
+ {
+ BOOST_CHECK_EQUAL(fid, enq_map::EMAP_LOCKED);
+ BOOST_CHECK(rid%(2*rid_incr_1));
+ // unlock, read, then relock
+ BOOST_CHECK_EQUAL(e4.unlock(rid), enq_map::EMAP_OK);
+ BOOST_CHECK(e4.get_pfid(rid) >= enq_map::EMAP_OK);
+ BOOST_CHECK_EQUAL(e4.lock(rid), enq_map::EMAP_OK);
+ fid = e4.get_pfid(rid);
+ if (fid < enq_map::EMAP_OK) // fail
+ BOOST_CHECK_EQUAL(fid, enq_map::EMAP_LOCKED);
+ else
+ BOOST_ERROR("Failed to prevent getting locked record");
+ }
+ }
+
+ // remove all; if locked, use with txn_flag true; should ignore all locked records
+ for (u_int64_t rid = rid_begin; rid < rid_end; rid += rid_incr_1)
+ BOOST_CHECK(e4.get_remove_pfid(rid, true) >= enq_map::EMAP_OK);
+ BOOST_CHECK(e4.empty());
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(lists)
+{
+ cout << test_filename << ".lists: " << flush;
+ u_int16_t pfid;
+ u_int64_t rid;
+ u_int16_t pfid_start = 0x5000UL;
+ u_int64_t rid_begin = 0xdddddddd00000000ULL;
+ u_int64_t rid_end = 0xdddddddd00000200ULL;
+
+ // insert, every second entry is locked
+ u_int64_t rid_incr_1 = 4ULL;
+ u_int64_t num_incr_1 = (rid_end - rid_begin)/rid_incr_1;
+ vector<u_int64_t> rid_list;
+ vector<u_int16_t> pfid_list;
+ enq_map e5;
+ e5.set_num_jfiles(pfid_start + (rid_end - rid_begin)/rid_incr_1);
+ for (rid = rid_begin, pfid = pfid_start; rid < rid_end; rid += rid_incr_1, pfid++)
+ {
+ BOOST_CHECK_EQUAL(e5.insert_pfid(rid, pfid), enq_map::EMAP_OK);
+ rid_list.push_back(rid);
+ pfid_list.push_back(pfid);
+ }
+ BOOST_CHECK_EQUAL(e5.size(), num_incr_1);
+ BOOST_CHECK_EQUAL(rid_list.size(), num_incr_1);
+ BOOST_CHECK_EQUAL(pfid_list.size(), num_incr_1);
+
+ vector<u_int64_t> ret_rid_list;
+ e5.rid_list(ret_rid_list);
+ BOOST_CHECK_EQUAL(ret_rid_list.size(), num_incr_1);
+ for (unsigned i=0; i<ret_rid_list.size(); i++)
+ BOOST_CHECK_EQUAL(rid_list[i], ret_rid_list[i]);
+
+ vector<u_int16_t> ret_pfid_list;
+ e5.pfid_list(ret_pfid_list);
+ BOOST_CHECK_EQUAL(ret_pfid_list.size(), num_incr_1);
+ for (unsigned i=0; i<ret_pfid_list.size(); i++)
+ BOOST_CHECK_EQUAL(pfid_list[i], ret_pfid_list[i]);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enq_count)
+{
+ cout << test_filename << ".enq_count: " << flush;
+
+ enq_map e6;
+
+ // Check the allocation and cleanup as the file size is set both up and down
+ e6.set_num_jfiles(24);
+ e6.set_num_jfiles(0);
+ e6.set_num_jfiles(100);
+ e6.set_num_jfiles(4);
+
+ // Add 100 enqueues to file 1, check that the counts match
+ for (u_int16_t pfid=0; pfid<4; pfid++)
+ BOOST_CHECK_EQUAL(e6.get_enq_cnt(pfid), u_int32_t(0));
+ for (u_int64_t rid=0; rid<100; rid++)
+ BOOST_CHECK_EQUAL(e6.insert_pfid(rid, 1), enq_map::EMAP_OK);
+ for (u_int16_t pfid=0; pfid<4; pfid++)
+ {
+ if (pfid == 1)
+ BOOST_CHECK_EQUAL(e6.get_enq_cnt(pfid), u_int32_t(100));
+ else
+ BOOST_CHECK_EQUAL(e6.get_enq_cnt(pfid), u_int32_t(0));
+ }
+
+ // Now remove 10 from file 1, check that the counts match
+ for (u_int64_t rid=0; rid<100; rid+=10)
+ //e6.Xget_remove_pfid(rid);
+ BOOST_CHECK(e6.get_remove_pfid(rid) >= enq_map::EMAP_OK);
+ for (u_int16_t pfid=0; pfid<4; pfid++)
+ {
+ if (pfid == 1)
+ BOOST_CHECK_EQUAL(e6.get_enq_cnt(pfid), u_int32_t(90));
+ else
+ BOOST_CHECK_EQUAL(e6.get_enq_cnt(pfid), u_int32_t(0));
+ }
+
+ // Now resize the file up and make sure the count in file 1 still exists
+ e6.set_num_jfiles(8);
+ for (u_int16_t pfid=0; pfid<8; pfid++)
+ {
+ if (pfid == 1)
+ BOOST_CHECK_EQUAL(e6.get_enq_cnt(pfid), u_int32_t(90));
+ else
+ BOOST_CHECK_EQUAL(e6.get_enq_cnt(pfid), u_int32_t(0));
+ }
+
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(stress)
+{
+ cout << test_filename << ".stress: " << flush;
+ u_int64_t rid;
+ u_int64_t rid_cnt;
+ u_int64_t rid_begin = 0xffffffff00000000ULL;
+ u_int64_t num_rid = 10;
+
+ enq_map e7;
+ e7.set_num_jfiles(rid_begin + num_rid);
+
+ // insert even rids with no dups
+ for (rid = rid_begin, rid_cnt = u_int64_t(0); rid_cnt < num_rid; rid += 2ULL, rid_cnt++)
+ BOOST_CHECK_EQUAL(e7.insert_pfid(rid, u_int16_t(0)), enq_map::EMAP_OK);
+ BOOST_CHECK_EQUAL(e7.size(), num_rid);
+
+ // insert odd rids with no dups
+ for (rid = rid_begin + 1, rid_cnt = u_int64_t(0); rid_cnt < num_rid; rid += 2ULL, rid_cnt++)
+ BOOST_CHECK_EQUAL(e7.insert_pfid(rid, u_int16_t(0)), enq_map::EMAP_OK);
+ BOOST_CHECK_EQUAL(e7.size(), num_rid * 2);
+
+ // remove even rids
+ for (rid = rid_begin, rid_cnt = u_int64_t(0); rid_cnt < num_rid; rid += 2ULL, rid_cnt++)
+ BOOST_CHECK(e7.get_remove_pfid(rid) >= enq_map::EMAP_OK);
+ BOOST_CHECK_EQUAL(e7.size(), num_rid);
+
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/_ut_jdir.cpp b/qpid/cpp/src/tests/legacystore/jrnl/_ut_jdir.cpp
new file mode 100644
index 0000000000..b55d5ff8ef
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/_ut_jdir.cpp
@@ -0,0 +1,416 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../unit_test.h"
+
+#include <cerrno>
+#include <cstring>
+#include <dirent.h>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include "qpid/legacystore/jrnl/file_hdr.h"
+#include "qpid/legacystore/jrnl/jcfg.h"
+#include "qpid/legacystore/jrnl/jdir.h"
+#include "qpid/legacystore/jrnl/jerrno.h"
+#include "qpid/legacystore/jrnl/jexception.h"
+#include <sys/stat.h>
+
+#define NUM_JFILES 4
+#define JFSIZE_SBLKS 128
+
+#define ERRORSTR(e) std::strerror(e) << " (" << e << ")"
+#define NUM_CLEAR_OPS 20
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(jdir_suite)
+
+const string test_filename("_ut_jdir");
+const char* tdp = getenv("TMP_DATA_DIR");
+const string test_dir(tdp && strlen(tdp) > 0 ? string(tdp) + "/_ut_jdir" : "/var/tmp/_ut_jdir");
+
+// === Helper functions ===
+
+void create_file(const char* filename, mode_t fmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
+{
+ ofstream of(filename, ofstream::out | ofstream::trunc);
+ if (!of.good())
+ BOOST_FAIL("Unable to open file " << filename << " for writing.");
+ of.write(filename, std::strlen(filename));
+ of.close();
+ ::chmod(filename, fmode);
+}
+
+void create_file(const string filename, mode_t fmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
+{
+ create_file(filename.c_str(), fmode);
+}
+
+void create_jdat_file(const char* dirname, const char* base_filename, u_int32_t fid,
+ u_int64_t first_rid)
+{
+ stringstream fn;
+ fn << dirname << "/" << base_filename << ".";
+ fn << setfill('0') << hex << setw(4) << fid << ".jdat";
+ file_hdr fh(RHM_JDAT_FILE_MAGIC, RHM_JDAT_VERSION, 0, first_rid, fid, 0x200, true);
+ ofstream of(fn.str().c_str(), ofstream::out | ofstream::trunc);
+ if (!of.good())
+ BOOST_FAIL("Unable to open journal data file " << fn.str() << " for writing.");
+ of.write((const char*)&fh, sizeof(file_hdr));
+ of.close();
+}
+
+void create_jinf_file(const char* dirname, const char* base_filename)
+{
+ timespec ts;
+ ::clock_gettime(CLOCK_REALTIME, &ts);
+ jinf ji("test journal id", dirname, base_filename, NUM_JFILES, false, 0, JFSIZE_SBLKS,
+ JRNL_WMGR_DEF_PAGE_SIZE, JRNL_WMGR_DEF_PAGES, ts);
+ ji.write();
+}
+
+void create_jrnl_fileset(const char* dirname, const char* base_filename)
+{
+ create_jinf_file(dirname, base_filename);
+ for (u_int32_t fid = 0; fid < NUM_JFILES; fid++)
+ {
+ u_int64_t rid = 0x12340000 + (fid * 0x25);
+ create_jdat_file(dirname, base_filename, fid, rid);
+ }
+}
+
+unsigned count_dir_contents(const char* dirname, bool incl_files, bool incl_dirs = true)
+{
+ struct dirent* entry;
+ struct stat s;
+ unsigned file_cnt = 0;
+ unsigned dir_cnt = 0;
+ unsigned other_cnt = 0;
+ DIR* dir = ::opendir(dirname);
+ if (!dir)
+ BOOST_FAIL("Unable to open directory " << dirname);
+ while ((entry = ::readdir(dir)) != NULL)
+ {
+ // Ignore . and ..
+ if (std::strcmp(entry->d_name, ".") != 0 && std::strcmp(entry->d_name, "..") != 0)
+ {
+ stringstream fn;
+ fn << dirname << "/" << entry->d_name;
+ if (::stat(fn.str().c_str(), &s))
+ BOOST_FAIL("Unable to stat dir entry " << entry->d_name << "; err=" <<
+ ERRORSTR(errno));
+ if (S_ISREG(s.st_mode))
+ file_cnt++;
+ else if (S_ISDIR(s.st_mode))
+ dir_cnt++;
+ else
+ other_cnt++;
+ }
+ }
+ ::closedir(dir);
+ if (incl_files)
+ {
+ if (incl_dirs)
+ return file_cnt + dir_cnt;
+ return file_cnt;
+ }
+ else if (incl_dirs)
+ return dir_cnt;
+ return other_cnt;
+}
+
+void check_dir_contents(const char* dirname, const char* base_filename, unsigned num_subdirs,
+ bool jrnl_present)
+{
+ if (jdir::is_dir(dirname))
+ {
+ // Subdir count
+ BOOST_CHECK_EQUAL(count_dir_contents(dirname, false, true), num_subdirs);
+
+ // Journal file count
+ unsigned num_jrnl_files = jrnl_present ? NUM_JFILES + 1 : 0;
+ BOOST_CHECK_EQUAL(count_dir_contents(dirname, true, false), num_jrnl_files);
+
+ // Check journal files are present
+ if (jrnl_present)
+ try { jdir::verify_dir(dirname, base_filename); }
+ catch(const jexception& e) { BOOST_ERROR(e); }
+ for (unsigned subdir_num = 1; subdir_num <= num_subdirs; subdir_num++)
+ {
+ stringstream subdir_name;
+ subdir_name << dirname << "/_" << base_filename << ".bak.";
+ subdir_name << hex << setfill('0') << setw(4) << subdir_num;
+ try { jdir::verify_dir(subdir_name.str().c_str(), base_filename); }
+ catch(const jexception& e) { BOOST_ERROR(e); }
+ }
+ }
+ else
+ BOOST_ERROR(dirname << " is not a directory");
+}
+
+void check_dir_not_existing(const char* dirname)
+{
+ if (jdir::exists(dirname) && jdir::is_dir(dirname))
+ jdir::delete_dir(dirname);
+ if (jdir::exists(dirname))
+ BOOST_FAIL("Unable to remove directory " << dirname);
+}
+
+void check_dir_not_existing(const string dirname)
+{
+ check_dir_not_existing(dirname.c_str());
+}
+
+// === Test suite ===
+
+QPID_AUTO_TEST_CASE(constructor)
+{
+ cout << test_filename << ".constructor: " << flush;
+ string dir(test_dir + "/A/B/C/D/E/F");
+ string bfn("test_base");
+ jdir dir1(dir, bfn);
+ BOOST_CHECK(dir1.dirname().compare(dir) == 0);
+ BOOST_CHECK(dir1.base_filename().compare(bfn) == 0);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(create_delete_dir)
+{
+ cout << test_filename << ".create_delete_dir: " << flush;
+ // Use instance
+ string dir_A(test_dir + "/A");
+ string dir_Ats(test_dir + "/A/"); // trailing '/'
+ check_dir_not_existing(test_dir + "/A");
+ jdir dir1(dir_A, "test_base");
+ dir1.create_dir();
+ // check all combos of jdir::exists and jdir::is_dir()
+ BOOST_CHECK(jdir::exists(dir_A));
+ BOOST_CHECK(jdir::exists(dir_Ats));
+ BOOST_CHECK(jdir::exists(dir_A.c_str()));
+ BOOST_CHECK(jdir::exists(dir_Ats.c_str()));
+ BOOST_CHECK(jdir::is_dir(dir_A));
+ BOOST_CHECK(jdir::is_dir(dir_Ats));
+ BOOST_CHECK(jdir::is_dir(dir_Ats.c_str()));
+ BOOST_CHECK(jdir::is_dir(dir_Ats.c_str()));
+ // do it a second time when dir exists
+ dir1.create_dir();
+ BOOST_CHECK(jdir::is_dir(dir_A));
+ dir1.delete_dir();
+ BOOST_CHECK(!jdir::exists(dir_A));
+
+ // Use static fn
+ check_dir_not_existing(test_dir + "/B");
+ jdir::create_dir(test_dir + "/B");
+ BOOST_CHECK(jdir::is_dir(test_dir + "/B"));
+ jdir::create_dir(test_dir + "/B");
+ BOOST_CHECK(jdir::is_dir(test_dir + "/B"));
+ jdir::delete_dir(test_dir + "/B");
+ BOOST_CHECK(!jdir::exists(test_dir + "/B"));
+
+ // Non-empty dirs
+ check_dir_not_existing(test_dir + "/C");
+ jdir::create_dir(test_dir + "/C");
+ BOOST_CHECK(jdir::is_dir(test_dir + "/C"));
+ create_file(test_dir + "/C/test_file_1.txt"); // mode 644 (default)
+ create_file(test_dir + "/C/test_file_2.txt", S_IRWXU | S_IRWXG | S_IRWXO); // mode 777
+ create_file(test_dir + "/C/test_file_3.txt", S_IRUSR | S_IRGRP | S_IROTH); // mode 444 (read-only)
+ create_file(test_dir + "/C/test_file_4.txt", 0); // mode 000 (no permissions)
+ BOOST_CHECK(jdir::is_dir(test_dir + "/C"));
+ jdir::create_dir(test_dir + "/C");
+ BOOST_CHECK(jdir::is_dir(test_dir + "/C"));
+ jdir::delete_dir(test_dir + "/C");
+ BOOST_CHECK(!jdir::exists(test_dir + "/C"));
+
+ // Check non-existent dirs fail
+ check_dir_not_existing(test_dir + "/D");
+ try
+ {
+ jdir::is_dir(test_dir + "/D");
+ BOOST_ERROR("jdir::is_dir() failed to throw jexeption for non-existent directory.");
+ }
+ catch(const jexception& e)
+ {
+ BOOST_CHECK_EQUAL(e.err_code(), jerrno::JERR_JDIR_STAT);
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(create_delete_dir_recursive)
+{
+ cout << test_filename << ".create_delete_dir_recursive: " << flush;
+ // Use instances
+ check_dir_not_existing(test_dir + "/E");
+ jdir dir1(test_dir + "/E/F/G/H", "test_base");
+ dir1.create_dir();
+ BOOST_CHECK(jdir::is_dir(test_dir + "/E/F/G/H"));
+ dir1.delete_dir();
+ BOOST_CHECK(!jdir::exists(test_dir + "/E/F/G/H")); // only H deleted, E/F/G remain
+ BOOST_CHECK(jdir::exists(test_dir + "/E/F/G"));
+ jdir::delete_dir(test_dir + "/E"); // delete remaining dirs
+ BOOST_CHECK(!jdir::exists(test_dir + "/E"));
+
+ check_dir_not_existing(test_dir + "/F");
+ jdir dir2(test_dir + "/F/G/H/I/", "test_base"); // trailing '/'
+ dir2.create_dir();
+ BOOST_CHECK(jdir::is_dir(test_dir + "/F/G/H/I/"));
+ dir2.delete_dir();
+ BOOST_CHECK(!jdir::exists(test_dir + "/F/G/H/I/"));
+ BOOST_CHECK(jdir::exists(test_dir + "/F/G/H/"));
+ jdir::delete_dir(test_dir + "/F");
+ BOOST_CHECK(!jdir::exists(test_dir + "/F"));
+
+ check_dir_not_existing(test_dir + "/G");
+ jdir dir3(test_dir + "/G/H//I//J", "test_base"); // extra '/' in path
+ dir3.create_dir();
+ BOOST_CHECK(jdir::is_dir(test_dir + "/G/H//I//J"));
+ dir3.delete_dir();
+ BOOST_CHECK(!jdir::exists(test_dir + "/G/H//I//J"));
+ BOOST_CHECK(jdir::exists(test_dir + "/G/H//I"));
+ jdir::delete_dir(test_dir + "/F");
+ BOOST_CHECK(!jdir::exists(test_dir + "/F"));
+
+ // Use static fn
+ check_dir_not_existing(test_dir + "/H");
+ jdir::create_dir(test_dir + "/H/I/J/K");
+ BOOST_CHECK(jdir::is_dir(test_dir + "/H/I/J/K"));
+ jdir::delete_dir(test_dir + "/H/I/J/K");
+ BOOST_CHECK(!jdir::exists(test_dir + "/H/I/J/K")); // only J deleted, H/I/J remain
+ BOOST_CHECK(jdir::exists(test_dir + "/H/I/J"));
+ jdir::delete_dir(test_dir + "/H");
+ BOOST_CHECK(!jdir::exists(test_dir + "/H"));
+
+ check_dir_not_existing(test_dir + "/I");
+ jdir::create_dir(test_dir + "/I/J/K/L/"); // trailing '/'
+ BOOST_CHECK(jdir::is_dir(test_dir + "/I/J/K/L/"));
+ jdir::delete_dir(test_dir + "/I/J/K/L/");
+ BOOST_CHECK(!jdir::exists(test_dir + "/I/J/K/L/"));
+ BOOST_CHECK(jdir::exists(test_dir + "/I/J/K/"));
+ jdir::delete_dir(test_dir + "/I");
+ BOOST_CHECK(!jdir::exists(test_dir + "/I"));
+
+ check_dir_not_existing(test_dir + "//J");
+ jdir::create_dir(test_dir + "//J//K//L//M"); // extra '/' in path
+ BOOST_CHECK(jdir::is_dir(test_dir + "//J//K//L//M"));
+ jdir::delete_dir(test_dir + "//J//K//L//M");
+ BOOST_CHECK(!jdir::exists(test_dir + "//J//K//L//M"));
+ BOOST_CHECK(jdir::exists(test_dir + "//J//K//L"));
+ jdir::delete_dir(test_dir + "//J");
+ BOOST_CHECK(!jdir::exists(test_dir + "//J"));
+
+ // Non-empty dirs
+ check_dir_not_existing(test_dir + "/K");
+ jdir::create_dir(test_dir + "/K/L/M1/N1");
+ jdir::create_dir(test_dir + "/K/L/M1/N2");
+ jdir::create_dir(test_dir + "/K/L/M1/N3");
+ jdir::create_dir(test_dir + "/K/L/M1/N4");
+ create_file(test_dir + "/K/L/M1/N4/test_file_1.txt"); // mode 644 (default)
+ create_file(test_dir + "/K/L/M1/N4/test_file_2.txt", S_IRWXU | S_IRWXG | S_IRWXO); // mode 777
+ create_file(test_dir + "/K/L/M1/N4/test_file_3.txt", S_IRUSR | S_IRGRP | S_IROTH); // mode 444
+ create_file(test_dir + "/K/L/M1/N4/test_file_4.txt", 0); // mode 000 (no permissions)
+ jdir::create_dir(test_dir + "/K/L/M2");
+ jdir::create_dir(test_dir + "/K/L/M3/N5");
+ jdir::create_dir(test_dir + "/K/L/M3/N6");
+ BOOST_CHECK(jdir::is_dir(test_dir + "/K/L/M1/N1"));
+ BOOST_CHECK(jdir::is_dir(test_dir + "/K/L/M1/N2"));
+ BOOST_CHECK(jdir::is_dir(test_dir + "/K/L/M1/N3"));
+ BOOST_CHECK(jdir::is_dir(test_dir + "/K/L/M1/N4"));
+ BOOST_CHECK(jdir::is_dir(test_dir + "/K/L/M2"));
+ BOOST_CHECK(jdir::is_dir(test_dir + "/K/L/M3/N5"));
+ BOOST_CHECK(jdir::is_dir(test_dir + "/K/L/M3/N6"));
+ jdir::delete_dir(test_dir + "/K");
+ BOOST_CHECK(!jdir::exists(test_dir + "/K"));
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(clear_verify_dir)
+{
+ cout << test_filename << ".clear_verify_dir: " << flush;
+ // Use instances
+ const char* jrnl_dir = "/var/tmp/test_dir_1";
+ const char* bfn = "test_base";
+ check_dir_not_existing(jrnl_dir);
+ jdir test_dir_1(jrnl_dir, bfn);
+ test_dir_1.create_dir();
+ BOOST_CHECK(jdir::is_dir(jrnl_dir));
+ // add journal files, check they exist, then clear them
+ unsigned cnt = 0;
+ while (cnt < NUM_CLEAR_OPS)
+ {
+ create_jrnl_fileset(jrnl_dir, bfn);
+ check_dir_contents(jrnl_dir, bfn, cnt, true);
+ test_dir_1.clear_dir();
+ check_dir_contents(jrnl_dir, bfn, ++cnt, false);
+ }
+ // clean up
+ test_dir_1.delete_dir();
+ BOOST_CHECK(!jdir::exists(jrnl_dir));
+
+ // Non-existent dir with auto-create true
+ jrnl_dir = "/var/tmp/test_dir_2";
+ check_dir_not_existing(jrnl_dir);
+ jdir test_dir_2(jrnl_dir, bfn);
+ // clear dir
+ test_dir_2.clear_dir(); // create flag is true by default
+ check_dir_contents(jrnl_dir, bfn, 0, false);
+ // clear empty dir, should not create subdir
+ test_dir_2.clear_dir(); // create flag is true by default
+ check_dir_contents(jrnl_dir, bfn, 0, false);
+ // clean up
+ test_dir_2.delete_dir();
+ BOOST_CHECK(!jdir::exists(jrnl_dir));
+
+ // non-existent dir with auto-create false
+ jrnl_dir = "/var/tmp/test_dir_3";
+ check_dir_not_existing(jrnl_dir);
+ jdir test_dir_3(jrnl_dir, bfn);
+ try
+ {
+ test_dir_3.clear_dir(false);
+ BOOST_ERROR("jdir::clear_dir(flase) failed to throw jexeption for non-existent directory.");
+ }
+ catch(const jexception& e)
+ {
+ BOOST_CHECK_EQUAL(e.err_code(), jerrno::JERR_JDIR_OPENDIR);
+ }
+
+ // Use static fn
+ jrnl_dir = "/var/tmp/test_dir_4";
+ check_dir_not_existing(jrnl_dir);
+ jdir::clear_dir(jrnl_dir, bfn); // should create dir if it does not exist
+ // add journal files, check they exist, then clear them
+ cnt = 0;
+ while (cnt < NUM_CLEAR_OPS)
+ {
+ create_jrnl_fileset(jrnl_dir, bfn);
+ check_dir_contents(jrnl_dir, bfn, cnt, true);
+ jdir::clear_dir(jrnl_dir, bfn);
+ check_dir_contents(jrnl_dir, bfn, ++cnt, false);
+ }
+ // clean up
+ jdir::delete_dir(jrnl_dir);
+ BOOST_CHECK(!jdir::exists(jrnl_dir));
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/_ut_jerrno.cpp b/qpid/cpp/src/tests/legacystore/jrnl/_ut_jerrno.cpp
new file mode 100644
index 0000000000..1ae1138355
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/_ut_jerrno.cpp
@@ -0,0 +1,47 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../unit_test.h"
+
+#include <cstring>
+#include <iostream>
+#include "qpid/legacystore/jrnl/jerrno.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(jerrno_suite)
+using namespace mrg::journal;
+
+const string test_filename("_ut_jerrno");
+
+QPID_AUTO_TEST_CASE(jerrno_val)
+{
+ cout << test_filename << ".jerrno_val: " << flush;
+ const char* m = "JERR__MALLOC";
+ string malloc_msg = string(jerrno::err_msg(jerrno::JERR__MALLOC));
+ BOOST_CHECK(malloc_msg.substr(0, std::strlen(m)).compare(m) == 0);
+ BOOST_CHECK(std::strcmp(jerrno::err_msg(0), "<Unknown error code>") == 0);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/_ut_jexception.cpp b/qpid/cpp/src/tests/legacystore/jrnl/_ut_jexception.cpp
new file mode 100644
index 0000000000..8b9e876aa6
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/_ut_jexception.cpp
@@ -0,0 +1,346 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../unit_test.h"
+
+#include <cstring>
+#include <iostream>
+#include "qpid/legacystore/jrnl/jerrno.h"
+#include "qpid/legacystore/jrnl/jexception.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(jexception_suite)
+
+const string test_filename("_ut_jexception");
+
+// === Helper functions ===
+
+void throw_exception(const jexception& e, std::size_t what_len, std::size_t ai_len,
+ std::size_t tc_len, std::size_t tf_len)
+{
+ try { throw e; }
+ catch (const jexception& e)
+ {
+ BOOST_CHECK_EQUAL(std::strlen(e.what()), what_len);
+ BOOST_CHECK_EQUAL(e.additional_info().size(), ai_len);
+ BOOST_CHECK_EQUAL(e.throwing_class().size(), tc_len);
+ BOOST_CHECK_EQUAL(e.throwing_fn().size(), tf_len);
+ }
+}
+
+void throw_exception(const jexception& e, std::size_t what_len, std::size_t ai_len)
+{
+ throw_exception(e, what_len, ai_len, 0, 0);
+}
+
+void throw_exception(const jexception& e, std::size_t what_len, std::size_t tc_len,
+ std::size_t tf_len)
+{
+ throw_exception(e, what_len, 0, tc_len, tf_len);
+}
+
+// === Test suite ===
+
+QPID_AUTO_TEST_CASE(constructor_1)
+{
+ cout << test_filename << ".constructor_1: " << flush;
+ try
+ {
+ jexception e1;
+ BOOST_CHECK_EQUAL(e1.err_code(), (u_int32_t)0);
+ BOOST_CHECK(e1.additional_info().size() == 0);
+ BOOST_CHECK(e1.throwing_class().size() == 0);
+ BOOST_CHECK(e1.throwing_fn().size() == 0);
+ BOOST_CHECK(std::strlen(e1.what()) > 0);
+ throw e1;
+ }
+ catch (const jexception& e)
+ {
+ BOOST_CHECK_EQUAL(e.err_code(), (u_int32_t)0);
+ BOOST_CHECK(e.additional_info().size() == 0);
+ BOOST_CHECK(e.throwing_class().size() == 0);
+ BOOST_CHECK(e.throwing_fn().size() == 0);
+ BOOST_CHECK(std::strlen(e.what()) > 0);
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_2)
+{
+ cout << test_filename << ".constructor_2: " << flush;
+ const u_int32_t err_code = 2;
+ try
+ {
+ jexception e2(err_code);
+ BOOST_CHECK_EQUAL(e2.err_code(), err_code);
+ BOOST_CHECK(e2.additional_info().size() == 0);
+ BOOST_CHECK(e2.throwing_class().size() == 0);
+ BOOST_CHECK(e2.throwing_fn().size() == 0);
+ BOOST_CHECK(std::strlen(e2.what()) > 0);
+ throw e2;
+ }
+ catch (const jexception& e)
+ {
+ BOOST_CHECK_EQUAL(e.err_code(), err_code);
+ BOOST_CHECK(e.additional_info().size() == 0);
+ BOOST_CHECK(e.throwing_class().size() == 0);
+ BOOST_CHECK(e.throwing_fn().size() == 0);
+ BOOST_CHECK(std::strlen(e.what()) > 0);
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_3a)
+{
+ cout << test_filename << ".constructor_3a: " << flush;
+ const char* err_msg = "exception3";
+ try
+ {
+ jexception e3(err_msg);
+ BOOST_CHECK_EQUAL(e3.err_code(), (u_int32_t)0);
+ BOOST_CHECK(e3.additional_info().compare(err_msg) == 0);
+ BOOST_CHECK(e3.throwing_class().size() == 0);
+ BOOST_CHECK(e3.throwing_fn().size() == 0);
+ BOOST_CHECK(std::strlen(e3.what()) > 0);
+ throw e3;
+ }
+ catch (const jexception& e)
+ {
+ BOOST_CHECK_EQUAL(e.err_code(), (u_int32_t)0);
+ BOOST_CHECK(e.additional_info().compare(err_msg) == 0);
+ BOOST_CHECK(e.throwing_class().size() == 0);
+ BOOST_CHECK(e.throwing_fn().size() == 0);
+ BOOST_CHECK(std::strlen(e.what()) > 0);
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_3b)
+{
+ cout << test_filename << ".constructor_3b: " << flush;
+ const string err_msg("exception3");
+ try
+ {
+ jexception e3(err_msg);
+ BOOST_CHECK_EQUAL(e3.err_code(), (u_int32_t)0);
+ BOOST_CHECK(e3.additional_info().compare(err_msg) == 0);
+ BOOST_CHECK(e3.throwing_class().size() == 0);
+ BOOST_CHECK(e3.throwing_fn().size() == 0);
+ BOOST_CHECK(std::strlen(e3.what()) > 0);
+ throw e3;
+ }
+ catch (const jexception& e)
+ {
+ BOOST_CHECK_EQUAL(e.err_code(), (u_int32_t)0);
+ BOOST_CHECK(e.additional_info().compare(err_msg) == 0);
+ BOOST_CHECK(e.throwing_class().size() == 0);
+ BOOST_CHECK(e.throwing_fn().size() == 0);
+ BOOST_CHECK(std::strlen(e.what()) > 0);
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_4a)
+{
+ cout << test_filename << ".constructor_4a: " << flush;
+ const u_int32_t err_code = 4;
+ const char* err_msg = "exception4";
+ try
+ {
+ jexception e4(err_code, err_msg);
+ BOOST_CHECK_EQUAL(e4.err_code(), err_code);
+ BOOST_CHECK(e4.additional_info().compare(err_msg) == 0);
+ BOOST_CHECK(e4.throwing_class().size() == 0);
+ BOOST_CHECK(e4.throwing_fn().size() == 0);
+ BOOST_CHECK(std::strlen(e4.what()) > 0);
+ throw e4;
+ }
+ catch (const jexception& e)
+ {
+ BOOST_CHECK_EQUAL(e.err_code(), err_code);
+ BOOST_CHECK(e.additional_info().compare(err_msg) == 0);
+ BOOST_CHECK(e.throwing_class().size() == 0);
+ BOOST_CHECK(e.throwing_fn().size() == 0);
+ BOOST_CHECK(std::strlen(e.what()) > 0);
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_4b)
+{
+ cout << test_filename << ".constructor_4b: " << flush;
+ const u_int32_t err_code = 4;
+ const string err_msg("exception4");
+ try
+ {
+ jexception e4(err_code, err_msg);
+ BOOST_CHECK_EQUAL(e4.err_code(), err_code);
+ BOOST_CHECK(e4.additional_info().compare(err_msg) == 0);
+ BOOST_CHECK(e4.throwing_class().size() == 0);
+ BOOST_CHECK(e4.throwing_fn().size() == 0);
+ BOOST_CHECK(std::strlen(e4.what()) > 0);
+ throw e4;
+ }
+ catch (const jexception& e)
+ {
+ BOOST_CHECK_EQUAL(e.err_code(), err_code);
+ BOOST_CHECK(e.additional_info().compare(err_msg) == 0);
+ BOOST_CHECK(e.throwing_class().size() == 0);
+ BOOST_CHECK(e.throwing_fn().size() == 0);
+ BOOST_CHECK(std::strlen(e.what()) > 0);
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_5a)
+{
+ cout << test_filename << ".constructor_5a: " << flush;
+ const u_int32_t err_code = 5;
+ const char* err_class = "class5";
+ const char* err_fn = "fn5";
+ try
+ {
+ jexception e5(err_code, err_class, err_fn);
+ BOOST_CHECK_EQUAL(e5.err_code(), err_code);
+ BOOST_CHECK(e5.additional_info().size() == 0);
+ BOOST_CHECK(e5.throwing_class().compare(err_class) == 0);
+ BOOST_CHECK(e5.throwing_fn().compare(err_fn) == 0);
+ BOOST_CHECK(std::strlen(e5.what()) > 0);
+ throw e5;
+ }
+ catch (const jexception& e)
+ {
+ BOOST_CHECK_EQUAL(e.err_code(), err_code);
+ BOOST_CHECK(e.additional_info().size() == 0);
+ BOOST_CHECK(e.throwing_class().compare(err_class) == 0);
+ BOOST_CHECK(e.throwing_fn().compare(err_fn) == 0);
+ BOOST_CHECK(std::strlen(e.what()) > 0);
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_5b)
+{
+ cout << test_filename << ".constructor_5b: " << flush;
+ const u_int32_t err_code = 5;
+ const string err_class("class5");
+ const string err_fn("fn5");
+ try
+ {
+ jexception e5(err_code, err_class, err_fn);
+ BOOST_CHECK_EQUAL(e5.err_code(), err_code);
+ BOOST_CHECK(e5.additional_info().size() == 0);
+ BOOST_CHECK(e5.throwing_class().compare(err_class) == 0);
+ BOOST_CHECK(e5.throwing_fn().compare(err_fn) == 0);
+ BOOST_CHECK(std::strlen(e5.what()) > 0);
+ throw e5;
+ }
+ catch (const jexception& e)
+ {
+ BOOST_CHECK_EQUAL(e.err_code(), err_code);
+ BOOST_CHECK(e.additional_info().size() == 0);
+ BOOST_CHECK(e.throwing_class().compare(err_class) == 0);
+ BOOST_CHECK(e.throwing_fn().compare(err_fn) == 0);
+ BOOST_CHECK(std::strlen(e.what()) > 0);
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_6a)
+{
+ cout << test_filename << ".constructor_6a: " << flush;
+ const u_int32_t err_code = 6;
+ const char* err_msg = "exception6";
+ const char* err_class = "class6";
+ const char* err_fn = "fn6";
+ try
+ {
+ jexception e6(err_code, err_msg, err_class, err_fn);
+ BOOST_CHECK_EQUAL(e6.err_code(), err_code);
+ BOOST_CHECK(e6.additional_info().compare(err_msg) == 0);
+ BOOST_CHECK(e6.throwing_class().compare(err_class) == 0);
+ BOOST_CHECK(e6.throwing_fn().compare(err_fn) == 0);
+ BOOST_CHECK(std::strlen(e6.what()) > 0);
+ throw e6;
+ }
+ catch (const jexception& e)
+ {
+ BOOST_CHECK_EQUAL(e.err_code(), err_code);
+ BOOST_CHECK(e.additional_info().compare(err_msg) == 0);
+ BOOST_CHECK(e.throwing_class().compare(err_class) == 0);
+ BOOST_CHECK(e.throwing_fn().compare(err_fn) == 0);
+ BOOST_CHECK(std::strlen(e.what()) > 0);
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_6b)
+{
+ cout << test_filename << ".constructor_6b: " << flush;
+ const u_int32_t err_code = 6;
+ const string err_msg("exception6");
+ const string err_class("class6");
+ const string err_fn("fn6");
+ try
+ {
+ jexception e6(err_code, err_msg, err_class, err_fn);
+ BOOST_CHECK_EQUAL(e6.err_code(), err_code);
+ BOOST_CHECK(e6.additional_info().compare(err_msg) == 0);
+ BOOST_CHECK(e6.throwing_class().compare(err_class) == 0);
+ BOOST_CHECK(e6.throwing_fn().compare(err_fn) == 0);
+ BOOST_CHECK(std::strlen(e6.what()) > 0);
+ throw e6;
+ }
+ catch (const jexception& e)
+ {
+ BOOST_CHECK_EQUAL(e.err_code(), err_code);
+ BOOST_CHECK(e.additional_info().compare(err_msg) == 0);
+ BOOST_CHECK(e.throwing_class().compare(err_class) == 0);
+ BOOST_CHECK(e.throwing_fn().compare(err_fn) == 0);
+ BOOST_CHECK(std::strlen(e.what()) > 0);
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(msg_scope)
+{
+ cout << test_filename << ".msg_scope: " << flush;
+ try
+ {
+ // These will go out of scope as soon as jexception is thrown...
+ const string msg("Error message");
+ const string cls("class");
+ const string fn("function");
+ throw jexception(100, msg, cls, fn);
+ }
+ catch (const jexception& e)
+ {
+ stringstream ss;
+ ss << e;
+ BOOST_CHECK(ss.str().size() > 0);
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/_ut_jinf.cpp b/qpid/cpp/src/tests/legacystore/jrnl/_ut_jinf.cpp
new file mode 100644
index 0000000000..f239139306
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/_ut_jinf.cpp
@@ -0,0 +1,402 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../unit_test.h"
+
+#include <cmath>
+#include <iostream>
+#include "qpid/legacystore/jrnl/jcntl.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(jinf_suite)
+
+const string test_filename("_ut_jinf");
+
+#include "_st_helper_fns.h"
+
+timespec ts;
+
+QPID_AUTO_TEST_CASE(write_constructor)
+{
+ string test_name = get_test_name(test_filename, "write_constructor");
+ const string jid = test_name + "_jid";
+ const string base_filename = test_name + "_bfn";
+ jdir::create_dir(test_dir); // Check test dir exists; create it if not
+ ::clock_gettime(CLOCK_REALTIME, &ts);
+ jinf ji(jid, test_dir, base_filename, NUM_JFILES, false, 0, JFSIZE_SBLKS, JRNL_WMGR_DEF_PAGE_SIZE, JRNL_WMGR_DEF_PAGES, ts);
+ BOOST_CHECK_EQUAL(ji.jver(), RHM_JDAT_VERSION);
+ BOOST_CHECK(ji.jid().compare(jid) == 0);
+ BOOST_CHECK(ji.jdir().compare(test_dir) == 0);
+ BOOST_CHECK(ji.base_filename().compare(base_filename) == 0);
+ const timespec this_ts = ji.ts();
+ BOOST_CHECK_EQUAL(this_ts.tv_sec, ts.tv_sec);
+ BOOST_CHECK_EQUAL(this_ts.tv_nsec, ts.tv_nsec);
+ BOOST_CHECK_EQUAL(ji.num_jfiles(), u_int16_t(NUM_JFILES));
+ BOOST_CHECK_EQUAL(ji.is_ae(), false);
+ BOOST_CHECK_EQUAL(ji.ae_max_jfiles(), u_int16_t(0));
+ BOOST_CHECK_EQUAL(ji.jfsize_sblks(), u_int32_t(JFSIZE_SBLKS));
+ BOOST_CHECK_EQUAL(ji.sblk_size_dblks(), u_int16_t(JRNL_SBLK_SIZE));
+ BOOST_CHECK_EQUAL(ji.dblk_size(), u_int32_t(JRNL_DBLK_SIZE));
+ BOOST_CHECK_EQUAL(ji.wcache_pgsize_sblks(), u_int32_t(JRNL_WMGR_DEF_PAGE_SIZE));
+ BOOST_CHECK_EQUAL(ji.wcache_num_pages(), u_int16_t(JRNL_WMGR_DEF_PAGES));
+ BOOST_CHECK_EQUAL(ji.rcache_pgsize_sblks(), u_int32_t(JRNL_RMGR_PAGE_SIZE));
+ BOOST_CHECK_EQUAL(ji.rcache_num_pages(), u_int16_t(JRNL_RMGR_PAGES));
+ ji.write();
+ cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(read_constructor)
+{
+ string test_name = get_test_name(test_filename, "read_constructor");
+ const string jid = test_name + "_jid";
+ const string base_filename = test_name + "_bfn";
+ lfid_pfid_map::create_new_jinf(jid, base_filename, false);
+
+ stringstream fn;
+ fn << test_dir << "/" <<base_filename << "." << JRNL_INFO_EXTENSION;
+ jinf ji(fn.str(), false);
+ BOOST_CHECK_EQUAL(ji.jver(), RHM_JDAT_VERSION);
+ BOOST_CHECK(ji.jid().compare(jid) == 0);
+ BOOST_CHECK(ji.jdir().compare(test_dir) == 0);
+ BOOST_CHECK(ji.base_filename().compare(base_filename) == 0);
+// const timespec this_ts = ji.ts();
+// BOOST_CHECK_EQUAL(this_ts.tv_sec, ts.tv_sec);
+// BOOST_CHECK_EQUAL(this_ts.tv_nsec, ts.tv_nsec);
+ BOOST_CHECK_EQUAL(ji.num_jfiles(), u_int16_t(NUM_JFILES));
+ BOOST_CHECK_EQUAL(ji.is_ae(), false);
+ BOOST_CHECK_EQUAL(ji.ae_max_jfiles(), u_int16_t(0));
+ BOOST_CHECK_EQUAL(ji.jfsize_sblks(), u_int32_t(JFSIZE_SBLKS));
+ BOOST_CHECK_EQUAL(ji.sblk_size_dblks(), u_int16_t(JRNL_SBLK_SIZE));
+ BOOST_CHECK_EQUAL(ji.dblk_size(), u_int32_t(JRNL_DBLK_SIZE));
+ BOOST_CHECK_EQUAL(ji.wcache_pgsize_sblks(), u_int32_t(JRNL_WMGR_DEF_PAGE_SIZE));
+ BOOST_CHECK_EQUAL(ji.wcache_num_pages(), u_int16_t(JRNL_WMGR_DEF_PAGES));
+ BOOST_CHECK_EQUAL(ji.rcache_pgsize_sblks(), u_int32_t(JRNL_RMGR_PAGE_SIZE));
+ BOOST_CHECK_EQUAL(ji.rcache_num_pages(), u_int16_t(JRNL_RMGR_PAGES));
+
+ cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(set_functions)
+{
+ string test_name = get_test_name(test_filename, "set_functions");
+ const string jid = test_name + "_jid";
+ const string base_filename = test_name + "_bfn";
+ lfid_pfid_map::create_new_jinf(jid, base_filename, false);
+
+ stringstream fn;
+ fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+ jinf ji(fn.str(), false);
+
+ ji.set_jdir("abc123");
+ BOOST_CHECK(ji.jdir().compare("abc123") == 0);
+ ji.set_jdir(test_dir);
+ BOOST_CHECK(ji.jdir().compare(test_dir) == 0);
+ ji.incr_num_jfiles();
+ BOOST_CHECK_EQUAL(ji.num_jfiles(), u_int16_t(NUM_JFILES+1));
+ ji.incr_num_jfiles();
+ BOOST_CHECK_EQUAL(ji.num_jfiles(), u_int16_t(NUM_JFILES+2));
+
+ lfid_pfid_map::clean_journal_info_file(test_dir);
+ cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(validate)
+{
+ string test_name = get_test_name(test_filename, "validate");
+ const string jid = test_name + "_jid";
+ const string base_filename = test_name + "_bfn";
+ lfid_pfid_map::create_new_jinf(jid, base_filename, false);
+
+ stringstream fn;
+ fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+ jinf ji(fn.str(), true);
+ // TODO: Check validation picks up conflict, but need to be friend to jinf to do it
+
+ lfid_pfid_map::clean_journal_info_file(test_dir);
+ cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_empty_journal)
+{
+ string test_name = get_test_name(test_filename, "analyze_empty_journal");
+ const string jid = test_name + "_jid";
+ const string base_filename = test_name + "_bfn";
+ jdir::create_dir(test_dir); // Check test dir exists; create it if not
+
+ lfid_pfid_map m(jid, base_filename);
+ m.journal_create(NUM_JFILES, 0, 0);
+ m.write_journal(false, 0);
+
+ stringstream fn;
+ fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+ jinf ji(fn.str(), false);
+ try { ji.analyze(); }
+ catch (const jexception& e)
+ {
+ if (e.err_code() != jerrno::JERR_JINF_JDATEMPTY)
+ BOOST_ERROR("Failed to throw expected exception jerrno::JERR_JINF_JDATEMPTY");
+ }
+
+ m.destroy_journal();
+ cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_part_full_journal)
+{
+ string test_name = get_test_name(test_filename, "analyze_part_full_journal");
+ const string jid = test_name + "_jid";
+ const string base_filename = test_name + "_bfn";
+ lfid_pfid_map m(jid, base_filename);
+ for (u_int16_t num_files = 1; num_files < NUM_JFILES; num_files++)
+ {
+ m.journal_create(NUM_JFILES, num_files, 0);
+ m.write_journal(false, 0);
+
+ stringstream fn;
+ fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+ jinf ji(fn.str(), false);
+ ji.analyze();
+ m.check_analysis(ji);
+
+ m.destroy_journal();
+ }
+ cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_full_journal)
+{
+ string test_name = get_test_name(test_filename, "analyze_full_journal");
+ const string jid = test_name + "_jid";
+ const string base_filename = test_name + "_bfn";
+ lfid_pfid_map m(jid, base_filename);
+ for (u_int16_t file_num = 0; file_num < NUM_JFILES; file_num++)
+ {
+ m.journal_create(NUM_JFILES, NUM_JFILES, file_num);
+ m.write_journal(false, 0);
+
+ stringstream fn;
+ fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+ jinf ji(fn.str(), false);
+ ji.analyze();
+ m.check_analysis(ji);
+
+ m.destroy_journal();
+ }
+ cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_single_appended_journal)
+{
+ string test_name = get_test_name(test_filename, "analyze_single_appended_journal");
+ const string jid = test_name + "_jid";
+ const string base_filename = test_name + "_bfn";
+ lfid_pfid_map m(jid, base_filename);
+ for (u_int16_t oldest_lid = 0; oldest_lid < NUM_JFILES; oldest_lid++)
+ for (u_int16_t after_lid = 0; after_lid < NUM_JFILES; after_lid++)
+ for (u_int16_t num_files = 1; num_files <= 5; num_files++)
+ {
+ m.journal_create(NUM_JFILES, NUM_JFILES, oldest_lid);
+ m.journal_insert(after_lid, num_files);
+ m.write_journal(true, 16);
+
+ stringstream fn;
+ fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+ jinf ji(fn.str(), false);
+ ji.analyze();
+ m.check_analysis(ji);
+
+ m.destroy_journal();
+ }
+ cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_multi_appended_journal)
+{
+ string test_name = get_test_name(test_filename, "analyze_multi_appended_journal");
+ const string jid = test_name + "_jid";
+ const string base_filename = test_name + "_bfn";
+ lfid_pfid_map m(jid, base_filename);
+ ::srand48(1);
+
+ for (u_int16_t num_appends = 1; num_appends <= 2*NUM_JFILES; num_appends++)
+ {
+ const u_int16_t oldest_lid = u_int16_t(NUM_JFILES * ::drand48());
+ m.journal_create(NUM_JFILES, NUM_JFILES, oldest_lid);
+ for (u_int16_t a = 0; a < num_appends; a++)
+ {
+ const u_int16_t num_files = u_int16_t(1 + (NUM_JFILES * ::drand48()));
+ const u_int16_t after_lid = u_int16_t(m.size() * ::drand48());
+ m.journal_insert(after_lid, num_files);
+ }
+ m.write_journal(true, 24);
+
+ stringstream fn;
+ fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+ jinf ji(fn.str(), false);
+ ji.analyze();
+ m.check_analysis(ji);
+
+ m.destroy_journal();
+ }
+
+ cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_multi_appended_then_failed_journal)
+{
+ string test_name = get_test_name(test_filename, "analyze_multi_appended_then_failed_journal");
+ const string jid = test_name + "_jid";
+ const string base_filename = test_name + "_bfn";
+ lfid_pfid_map m(jid, base_filename);
+ ::srand48(1);
+
+ // As this test relies on repeatable but random sequences, use many iterations for coverage
+ for (int c = 1; c <= 100; c++)
+ {
+ for (u_int16_t num_appends = 1; num_appends <= 2*NUM_JFILES; num_appends++)
+ {
+ u_int16_t oldest_lid = u_int16_t(NUM_JFILES * ::drand48());
+ m.journal_create(NUM_JFILES, NUM_JFILES, oldest_lid);
+ for (u_int16_t a = 0; a < num_appends-1; a++)
+ {
+ const u_int16_t num_files = u_int16_t(1 + (NUM_JFILES * ::drand48()));
+ const u_int16_t after_lid = u_int16_t(m.size() * ::drand48());
+ m.journal_insert(after_lid, num_files);
+ if (after_lid < oldest_lid)
+ oldest_lid += num_files;
+ }
+ const u_int16_t num_files = u_int16_t(1 + (NUM_JFILES * ::drand48()));
+ const u_int16_t after_lid = oldest_lid == 0 ? m.size() - 1 : oldest_lid - 1;
+ m.journal_insert(after_lid, num_files, false);
+ m.write_journal(true, 32);
+
+ stringstream fn;
+ fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+ jinf ji(fn.str(), false);
+ ji.analyze();
+ m.check_analysis(ji);
+
+ m.destroy_journal();
+ }
+ }
+
+ cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_inconsistent_jdat_file_size_in_journal)
+{
+ string test_name = get_test_name(test_filename, "analyze_inconsistent_jdat_file_size_in_journal");
+ const string jid = test_name + "_jid";
+ const string base_filename = test_name + "_bfn";
+ lfid_pfid_map m(jid, base_filename);
+ ::srand48(1);
+
+ for (u_int16_t pfid = 1; pfid < NUM_JFILES; pfid++)
+ {
+ m.journal_create(NUM_JFILES, NUM_JFILES, 0);
+ m.write_journal(false, 0);
+
+ const std::string filename = m.create_journal_filename(pfid, base_filename);
+ std::ofstream of(filename.c_str(), ofstream::out | ofstream::app);
+ if (!of.good())
+ BOOST_FAIL("Unable to open test journal file \"" << filename << "\" for writing.");
+ std::size_t expand_size = std::size_t(10 * JRNL_DBLK_SIZE * JRNL_SBLK_SIZE * ::drand48());
+ std::vector<char> sblk_buffer(expand_size, 0);
+ of.write(&sblk_buffer[0], expand_size);
+ of.close();
+
+ stringstream fn;
+ fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+ jinf ji(fn.str(), false);
+ try
+ {
+ ji.analyze();
+ BOOST_FAIL("Failed to detect irregular journal file size in file \"" << filename << "\"");
+ }
+ catch (const jexception& e) {} // ignore - expected
+
+ m.destroy_journal();
+ }
+ cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_owi_in_non_ae_journal)
+{
+ string test_name = get_test_name(test_filename, "analyze_owi_in_non_ae_journal");
+ const string jid = test_name + "_jid";
+ const string base_filename = test_name + "_bfn";
+ lfid_pfid_map m(jid, base_filename);
+ for (u_int16_t oldest_file = 1; oldest_file < NUM_DEFAULT_JFILES-1; oldest_file++)
+ {
+ for (u_int16_t bad_owi_file = oldest_file + 1; bad_owi_file < NUM_DEFAULT_JFILES; bad_owi_file++)
+ {
+ m.journal_create(NUM_DEFAULT_JFILES, NUM_DEFAULT_JFILES, oldest_file, bad_owi_file);
+ m.write_journal(false, 0);
+
+ stringstream fn;
+ fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+ jinf ji(fn.str(), false);
+ try
+ {
+ ji.analyze();
+ BOOST_FAIL("Failed to detect irregular OWI flag in non-ae journal file \"" << fn.str() << "\"");
+ }
+ catch (const jexception& e) {} // ignore - expected
+
+ m.destroy_journal();
+ }
+ }
+ cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_owi_in_ae_min_size_journal)
+{
+ string test_name = get_test_name(test_filename, "analyze_owi_in_ae_min_size_journal");
+ const string jid = test_name + "_jid";
+ const string base_filename = test_name + "_bfn";
+ lfid_pfid_map m(jid, base_filename);
+ for (u_int16_t oldest_file = 1; oldest_file < NUM_JFILES-1; oldest_file++)
+ {
+ for (u_int16_t bad_owi_file = oldest_file + 1; bad_owi_file < NUM_JFILES; bad_owi_file++)
+ {
+ m.journal_create(NUM_JFILES, NUM_JFILES, oldest_file, bad_owi_file);
+ m.write_journal(true, 16);
+
+ stringstream fn;
+ fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+ jinf ji(fn.str(), false);
+ try
+ {
+ ji.analyze();
+ BOOST_FAIL("Failed to detect irregular OWI flag in min-sized ae journal file \"" << fn.str() << "\"");
+ }
+ catch (const jexception& e) {} // ignore - expected
+
+ m.destroy_journal();
+ }
+ }
+ cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/_ut_lpmgr.cpp b/qpid/cpp/src/tests/legacystore/jrnl/_ut_lpmgr.cpp
new file mode 100644
index 0000000000..2dc20ffa7c
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/_ut_lpmgr.cpp
@@ -0,0 +1,886 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../unit_test.h"
+#include <cmath>
+#include <iostream>
+#include "qpid/legacystore/jrnl/jcntl.h"
+#include "qpid/legacystore/jrnl/lpmgr.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(arr_cnt_suite)
+
+const string test_filename("_ut_lpmgr");
+
+#include "_st_helper_fns.h"
+
+// === Helper functions and definitions ===
+
+typedef vector<u_int16_t> flist;
+typedef flist::const_iterator flist_citr;
+
+class lpmgr_test_helper
+{
+ lpmgr_test_helper() {}
+ virtual ~lpmgr_test_helper() {}
+
+public:
+ static void check_pfids_lfids(const lpmgr& lm, const u_int16_t pfids[], const u_int16_t lfids[],
+ const size_t pfid_lfid_size)
+ {
+ vector<u_int16_t> res;
+ lm.get_pfid_list(res);
+ vectors_equal(lm, pfids, pfid_lfid_size, res, true);
+ lm.get_lfid_list(res);
+ vectors_equal(lm, lfids, pfid_lfid_size, res, false);
+ }
+
+ static void check_pfids_lfids(const lpmgr& lm, const flist& pfids, const flist lfids)
+ {
+ vector<u_int16_t> res;
+ lm.get_pfid_list(res);
+ vectors_equal(lm, pfids, res, true);
+ lm.get_lfid_list(res);
+ vectors_equal(lm, lfids, res, false);
+ }
+
+ static void check_linear_pfids_lfids(const lpmgr& lm, const size_t pfid_lfid_size)
+ {
+ vector<u_int16_t> res;
+ lm.get_pfid_list(res);
+ linear_vectors_equal(lm, pfid_lfid_size, res, true);
+ lm.get_lfid_list(res);
+ linear_vectors_equal(lm, pfid_lfid_size, res, false);
+ }
+
+ static void rcvdat_init(rcvdat& rd, const u_int16_t num_jfiles, const bool ae, const u_int16_t ae_max_jfiles,
+ const u_int16_t pfids[])
+ {
+ rd.reset(num_jfiles, ae, ae_max_jfiles);
+ load_vector(pfids, num_jfiles, rd._fid_list);
+ rd._jempty = false;
+ rd._lfid = pfids[num_jfiles - 1];
+ rd._eo = 100 * JRNL_DBLK_SIZE * JRNL_SBLK_SIZE;
+ }
+
+ static void rcvdat_init(rcvdat& rd, const flist& pfidl, const bool ae, const u_int16_t ae_max_jfiles)
+ {
+ const u_int16_t num_jfiles = pfidl.size();
+ rd.reset(num_jfiles, ae, ae_max_jfiles);
+ load_vector(pfidl, rd._fid_list);
+ rd._jempty = false;
+ rd._lfid = pfidl[num_jfiles - 1];
+ rd._eo = 100 * JRNL_DBLK_SIZE * JRNL_SBLK_SIZE;
+ }
+
+ static void initialize(lpmgr& lm, test_jrnl& jc, const u_int16_t num_jfiles, const bool ae,
+ const u_int16_t ae_max_jfiles)
+ {
+ lm.initialize(num_jfiles, ae, ae_max_jfiles, &jc, &jc.new_fcntl);
+ BOOST_CHECK_EQUAL(lm.is_init(), true);
+ BOOST_CHECK_EQUAL(lm.is_ae(), ae);
+ BOOST_CHECK_EQUAL(lm.ae_max_jfiles(), ae_max_jfiles);
+ BOOST_CHECK_EQUAL(lm.num_jfiles(), num_jfiles);
+ if (num_jfiles)
+ check_linear_pfids_lfids(lm, num_jfiles);
+ else
+ BOOST_CHECK_EQUAL(lm.get_fcntlp(0), (void*)0);
+ }
+
+ // version which sets up the lfid_pfid_map for later manipulation by insert tests
+ static void initialize(lfid_pfid_map& lfm, lpmgr& lm, test_jrnl& jc, const u_int16_t num_jfiles, const bool ae,
+ const u_int16_t ae_max_jfiles)
+ {
+ lfm.journal_create(num_jfiles, num_jfiles);
+ initialize(lm, jc, num_jfiles, ae, ae_max_jfiles);
+ }
+
+ static void prepare_recover(lfid_pfid_map& lfm, const u_int16_t size)
+ {
+ if (size < 4) BOOST_FAIL("prepare_recover(): size parameter (" << size << ") too small.");
+ lfm.journal_create(4, 4); // initial journal of size 4
+ u_int16_t s = 4; // cumulative size
+ while (s < size)
+ {
+ const u_int16_t ins_posn = u_int16_t(s * ::drand48()); // this insert posn
+ if (3.0 * ::drand48() > 1.0 || size - s < 2) // 2:1 chance of single insert when >= 2 still to insert
+ {
+ lfm.journal_insert(ins_posn); // single insert
+ s++;
+ }
+ else
+ {
+ // multiple insert, either 2 - 5
+ const u_int16_t max_ins_size = size - s >5 ? 5 : size - s;
+ const u_int16_t ins_size = 2 + u_int16_t((max_ins_size - 2) * ::drand48()); // this insert size
+ lfm.journal_insert(ins_posn, ins_size);
+ s += ins_size;
+ }
+ }
+ }
+
+ static void recover(lfid_pfid_map& lfm, lpmgr& lm, test_jrnl& jc, const bool ae, const u_int16_t ae_max_jfiles)
+ {
+ flist pfidl;
+ flist lfidl;
+ rcvdat rd;
+ const u_int16_t num_jfiles = lfm.size();
+
+ lfm.get_pfid_list(pfidl);
+ lfm.get_lfid_list(lfidl);
+ lm.finalize(); // clear all file handles before erasing old journal files
+ lfm.write_journal(ae, ae_max_jfiles, JFSIZE_SBLKS);
+
+ lpmgr_test_helper::rcvdat_init(rd, pfidl, ae, ae_max_jfiles);
+ lm.recover(rd, &jc, &jc.new_fcntl);
+ BOOST_CHECK_EQUAL(lm.is_init(), true);
+ BOOST_CHECK_EQUAL(lm.is_ae(), ae);
+ BOOST_CHECK_EQUAL(lm.ae_max_jfiles(), ae_max_jfiles);
+ BOOST_CHECK_EQUAL(lm.num_jfiles(), num_jfiles);
+ if (num_jfiles)
+ check_pfids_lfids(lm, pfidl, lfidl);
+ else
+ BOOST_CHECK_EQUAL(lm.get_fcntlp(0), (void*)0);
+ }
+
+ static void finalize(lpmgr& lm)
+ {
+ lm.finalize();
+ BOOST_CHECK_EQUAL(lm.is_init(), false);
+ BOOST_CHECK_EQUAL(lm.is_ae(), false);
+ BOOST_CHECK_EQUAL(lm.ae_max_jfiles(), u_int16_t(0));
+ BOOST_CHECK_EQUAL(lm.num_jfiles(), u_int16_t(0));
+ BOOST_CHECK_EQUAL(lm.get_fcntlp(0), (void*)0);
+ vector<u_int16_t> res;
+ lm.get_pfid_list(res);
+ BOOST_CHECK_EQUAL(res.size(), u_int16_t(0));
+ lm.get_lfid_list(res);
+ BOOST_CHECK_EQUAL(res.size(), u_int16_t(0));
+ }
+
+ static void insert(lfid_pfid_map& lfm, lpmgr& lm, test_jrnl& jc, const u_int16_t after_lfid, const u_int16_t incr = 1)
+ {
+ flist pfidl;
+ flist lfidl;
+ const u_int16_t num_jfiles = lm.num_jfiles();
+ lfm.journal_insert(after_lfid, incr);
+ lfm.get_pfid_list(pfidl);
+ lfm.get_lfid_list(lfidl);
+ lm.insert(after_lfid, &jc, &jc.new_fcntl, incr);
+ BOOST_CHECK_EQUAL(lm.num_jfiles(), num_jfiles + incr);
+ lpmgr_test_helper::check_pfids_lfids(lm, pfidl, lfidl);
+ }
+
+ static void check_ae_max_jfiles(lpmgr& lm, const u_int16_t num_jfiles, const u_int16_t ae_max_jfiles)
+ {
+ bool legal = ae_max_jfiles > num_jfiles || ae_max_jfiles == 0;
+
+ lm.set_ae(false);
+ BOOST_CHECK(!lm.is_ae());
+ if (legal)
+ {
+ lm.set_ae_max_jfiles(ae_max_jfiles);
+ BOOST_CHECK_EQUAL(lm.ae_max_jfiles(), ae_max_jfiles);
+ lm.set_ae(true);
+ BOOST_CHECK(lm.is_ae());
+ BOOST_CHECK_EQUAL(lm.ae_jfiles_rem(), ae_max_jfiles
+ ? ae_max_jfiles - num_jfiles
+ : JRNL_MAX_NUM_FILES - num_jfiles);
+ }
+ else
+ {
+ lm.set_ae_max_jfiles(ae_max_jfiles);
+ BOOST_CHECK_EQUAL(lm.ae_max_jfiles(), ae_max_jfiles);
+ try
+ {
+ lm.set_ae(true); // should raise exception
+ BOOST_ERROR("Auto-expand enabled with out-of-range ae_max_jfiles");
+ }
+ catch (const jexception& e) { BOOST_CHECK_EQUAL(e.err_code(), jerrno::JERR_LFMGR_BADAEFNUMLIM); }
+ BOOST_CHECK(!lm.is_ae());
+ BOOST_CHECK_EQUAL(lm.ae_jfiles_rem(), 0);
+ }
+ BOOST_CHECK_EQUAL(lm.ae_max_jfiles(), ae_max_jfiles);
+ }
+
+ static void check_multiple_initialization_recover(lfid_pfid_map& lfm, test_jrnl& jc,
+ const u_int16_t num_jfiles_arr[][2], const bool init_flag_0, const bool finalize_flag,
+ const bool init_flag_1)
+ {
+ unsigned i_njf = 0;
+ while (num_jfiles_arr[i_njf][0] && num_jfiles_arr[i_njf][1]) // cycle through each entry in num_jfiles_arr
+ {
+ for (unsigned i1_njf = 0; i1_njf <= 1; i1_njf++) // cycle through the two numbers in each entry of num_jfiles_arr
+ {
+ const u_int16_t num_jfiles_0 = num_jfiles_arr[i_njf][i1_njf == 0]; // first number in pair
+ const u_int16_t num_jfiles_1 = num_jfiles_arr[i_njf][i1_njf != 0]; // second number in pair
+
+ for (unsigned i_ae = 0; i_ae < 4; i_ae++) // cycle through combinations of enabling AE
+ {
+ const bool ae_0 = i_ae & 0x1; // first bit: enable AE on first init
+ const bool ae_1 = i_ae & 0x2; // second bit: enable AE on second init
+ for (unsigned i_aemjf = 0; i_aemjf < 4; i_aemjf++) // cycle through combinations of enabling/disabling ae limit
+ {
+ const u_int16_t ae_max_jfiles_0 = i_aemjf & 0x1 ? 3 * num_jfiles_0 : 0; // max ae files, 0 = disable max
+ const u_int16_t ae_max_jfiles_1 = i_aemjf & 0x2 ? 4 * num_jfiles_1 : 0; // max ae files, 0 = disable max
+
+ lpmgr lm; // DUT
+
+ if (init_flag_0)
+ initialize(lm, jc, num_jfiles_0, ae_0, ae_max_jfiles_0);
+ else
+ {
+ prepare_recover(lfm, num_jfiles_0);
+ recover(lfm, lm, jc, ae_1, ae_max_jfiles_0);
+ lfm.destroy_journal();
+ }
+
+ if (finalize_flag) finalize(lm);
+
+ if (init_flag_1)
+ initialize(lm, jc, num_jfiles_1, ae_1, ae_max_jfiles_1);
+ else
+ {
+ prepare_recover(lfm, num_jfiles_1);
+ recover(lfm, lm, jc, ae_1, ae_max_jfiles_1);
+ lfm.destroy_journal();
+ }
+ }
+ }
+ }
+ i_njf++;
+ }
+ }
+
+ static void check_insert(lfid_pfid_map& lfm, lpmgr& lm, test_jrnl& jc, const u_int16_t after_lfid,
+ const u_int16_t incr = 1)
+ {
+ const u_int16_t num_jfiles = lm.num_jfiles();
+ const u_int16_t ae_max_jfiles = lm.ae_max_jfiles();
+ const u_int16_t effective_ae_max_jfiles = ae_max_jfiles ? ae_max_jfiles : JRNL_MAX_NUM_FILES;
+ BOOST_CHECK_EQUAL(lm.ae_jfiles_rem(), effective_ae_max_jfiles - num_jfiles);
+ bool legal = lm.is_ae() && num_jfiles + incr <= effective_ae_max_jfiles;
+ if (legal)
+ {
+ insert(lfm, lm, jc, after_lfid, incr);
+ BOOST_CHECK_EQUAL(lm.num_jfiles(), num_jfiles + incr);
+ BOOST_CHECK_EQUAL(lm.ae_jfiles_rem(), effective_ae_max_jfiles - num_jfiles - incr);
+ }
+ else
+ {
+ try
+ {
+ insert(lfm, lm, jc, after_lfid, incr);
+ if (lm.is_ae())
+ BOOST_ERROR("lpmgr::insert() succeeded and exceeded limit");
+ else
+ BOOST_ERROR("lpmgr::insert() succeeded with auto-expand disabled");
+ }
+ catch (const jexception& e)
+ {
+ if (lm.is_ae())
+ BOOST_CHECK_EQUAL(e.err_code(), jerrno::JERR_LFMGR_AEFNUMLIMIT);
+ else
+ BOOST_CHECK_EQUAL(e.err_code(), jerrno::JERR_LFMGR_AEDISABLED);
+ }
+ BOOST_CHECK_EQUAL(lm.num_jfiles(), num_jfiles);
+ BOOST_CHECK_EQUAL(lm.ae_jfiles_rem(), effective_ae_max_jfiles - num_jfiles);
+ }
+ }
+
+ static void check_limit(lfid_pfid_map& lfm, test_jrnl& jc, const bool ae, const u_int16_t num_jfiles,
+ const u_int16_t ae_max_jfiles)
+ {
+ lpmgr lm;
+
+ for (unsigned i = 0; i < 2; i++)
+ {
+ if (i)
+ initialize(lfm, lm, jc, num_jfiles, ae, ae_max_jfiles);
+ else
+ {
+ prepare_recover(lfm, num_jfiles);
+ recover(lfm, lm, jc, ae, ae_max_jfiles);
+ }
+
+ // use up all available files
+ unsigned j = ae_max_jfiles ? ae_max_jfiles : JRNL_MAX_NUM_FILES;
+ while (ae && j > num_jfiles)
+ {
+ const u_int16_t posn = static_cast<u_int16_t>((lm.num_jfiles() - 1) * ::drand48());
+ const u_int16_t incr = 1 + static_cast<u_int16_t>((lm.ae_jfiles_rem() > 4
+ ? 3 : lm.ae_jfiles_rem() - 1) * ::drand48());
+ check_insert(lfm, lm, jc, posn, incr);
+ j -= incr;
+ }
+ // these should be over the limit or illegal
+ check_insert(lfm, lm, jc, 0);
+ check_insert(lfm, lm, jc, 2, 2);
+ lfm.destroy_journal();
+ }
+ }
+
+private:
+ static void load_vector(const u_int16_t a[], const size_t n, flist& v)
+ {
+ for (size_t i = 0; i < n; i++)
+ v.push_back(a[i]);
+ }
+
+ static void load_vector(const flist& a, flist& b)
+ {
+ for (flist_citr i = a.begin(); i < a.end(); i++)
+ b.push_back(*i);
+ }
+
+ static void vectors_equal(const lpmgr& lm, const u_int16_t a[], const size_t n, const flist& b,
+ const bool pfid_check)
+ {
+ BOOST_CHECK_EQUAL(n, b.size());
+ for (size_t i = 0; i < n; i++)
+ {
+ BOOST_CHECK_EQUAL(a[i], b[i]);
+ fcntl* fp = lm.get_fcntlp(i);
+ BOOST_CHECK_MESSAGE(fp != (void*)0, "Unexpected void pointer returned by lpmgr::get_fcntlp()");
+ if (fp) BOOST_CHECK_EQUAL(pfid_check ? fp->pfid() : fp->lfid(), pfid_check ? a[i] : i);
+ }
+ }
+
+ static void vectors_equal(const lpmgr& lm, const flist& a, const flist& b, const bool pfid_check)
+ {
+ BOOST_CHECK_EQUAL(a.size(), b.size());
+ for (size_t i = 0; i < a.size(); i++)
+ {
+ BOOST_CHECK_EQUAL(a[i], b[i]);
+ fcntl* fp = lm.get_fcntlp(i);
+ BOOST_CHECK_MESSAGE(fp != (void*)0, "Unexpected void pointer returned by lpmgr::get_fcntlp()");
+ if (fp) BOOST_CHECK_EQUAL(pfid_check ? fp->pfid() : fp->lfid(), pfid_check ? a[i] : i);
+ }
+ }
+
+ static void linear_vectors_equal(const lpmgr& lm, const size_t n, const flist& f, const bool pfid_check)
+ {
+ BOOST_CHECK_EQUAL(n, f.size());
+ for (size_t i = 0; i < n; i++)
+ {
+ BOOST_CHECK_EQUAL(i, f[i]);
+ fcntl* fp = lm.get_fcntlp(i);
+ BOOST_CHECK_MESSAGE(fp != (void*)0, "Unexpected void pointer returned by lpmgr::get_fcntlp()");
+ if (fp) BOOST_CHECK_EQUAL(pfid_check ? fp->pfid() : fp->lfid(), i);
+ }
+ }
+};
+
+// === Tests ===
+
+#ifndef LONG_TEST
+/*
+ * ==============================================
+ * NORMAL TESTS
+ * This section contains normal "make check" tests
+ * for building/packaging. These are built when
+ * LONG_TEST is _not_ defined.
+ * ==============================================
+ */
+
+/*
+ * Check that after construction, the fcntl array _fcntl_arr is empty and the is_init() function returns false.
+ */
+QPID_AUTO_TEST_CASE(default_constructor)
+{
+ string test_name = get_test_name(test_filename, "default_constructor");
+ try
+ {
+ lpmgr lm;
+ BOOST_CHECK_EQUAL(lm.is_init(), false);
+ BOOST_CHECK_EQUAL(lm.is_ae(), false);
+ BOOST_CHECK_EQUAL(lm.ae_max_jfiles(), u_int16_t(0));
+ BOOST_CHECK_EQUAL(lm.num_jfiles(), u_int16_t(0));
+ BOOST_CHECK_EQUAL(lm.get_fcntlp(0), (void*)0);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "done" << endl;
+}
+
+/*
+ * Check that initialize() correctly creates an ordered fcntl array _fcntl_arr.
+ */
+QPID_AUTO_TEST_CASE(initialize)
+{
+ string test_name = get_test_name(test_filename, "initialize");
+ const u_int16_t num_jfiles = 8;
+ try
+ {
+ jdir::create_dir(test_dir); // Check test dir exists; create it if not
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ {
+ lpmgr lm;
+ lpmgr_test_helper::initialize(lm, jc, num_jfiles, false, 0);
+ }
+ {
+ lpmgr lm;
+ lpmgr_test_helper::initialize(lm, jc, num_jfiles, true, 0);
+ }
+ {
+ lpmgr lm;
+ lpmgr_test_helper::initialize(lm, jc, num_jfiles, true, 5 * num_jfiles);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "done" << endl;
+}
+
+/*
+ * Check that recover() correctly sets up the specified pfid list order.
+ */
+QPID_AUTO_TEST_CASE(recover)
+{
+ string test_name = get_test_name(test_filename, "recover");
+ ::srand48(1); // init random gen for repeatable tests when using lpmgr_test_helper::prepare_recover()
+ try
+ {
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ lfid_pfid_map lfm(test_name, test_name);
+
+ {
+ lpmgr lm;
+ lpmgr_test_helper::prepare_recover(lfm, 8);
+ lpmgr_test_helper::recover(lfm, lm, jc, false, 0);
+ lfm.destroy_journal();
+ }
+ {
+ lpmgr lm;
+ lpmgr_test_helper::prepare_recover(lfm, 8);
+ lpmgr_test_helper::recover(lfm, lm, jc, true, 0);
+ lfm.destroy_journal();
+ }
+ {
+ lpmgr lm;
+ lpmgr_test_helper::prepare_recover(lfm, 8);
+ lpmgr_test_helper::recover(lfm, lm, jc, true, 5 * lfm.size());
+ lfm.destroy_journal();
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "done" << endl;
+}
+
+/*
+ * Check that finalize() after an initialize() empties _fcntl_arr and that afterwards is_init() returns false.
+ */
+QPID_AUTO_TEST_CASE(initialize_finalize)
+{
+ string test_name = get_test_name(test_filename, "initialize_finalize");
+ const u_int16_t num_jfiles = 8;
+ try
+ {
+ jdir::create_dir(test_dir); // Check test dir exists; create it if not
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ {
+ lpmgr lm;
+ lpmgr_test_helper::initialize(lm, jc, num_jfiles, false, 0);
+ lpmgr_test_helper::finalize(lm);
+ }
+ {
+ lpmgr lm;
+ lpmgr_test_helper::initialize(lm, jc, num_jfiles, true, 0);
+ lpmgr_test_helper::finalize(lm);
+ }
+ {
+ lpmgr lm;
+ lpmgr_test_helper::initialize(lm, jc, num_jfiles, true, 5 * num_jfiles);
+ lpmgr_test_helper::finalize(lm);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "done" << endl;
+}
+
+/*
+ * Check that finalize() after a recover() empties _fcntl_arr and that afterwards is_init() returns false.
+ */
+QPID_AUTO_TEST_CASE(recover_finalize)
+{
+ string test_name = get_test_name(test_filename, "recover_finalize");
+ const u_int16_t num_jfiles = 8;
+ ::srand48(1); // init random gen for repeatable tests when using lpmgr_test_helper::prepare_recover()
+ try
+ {
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ lfid_pfid_map lfm(test_name, test_name);
+
+ {
+ lpmgr lm;
+ lpmgr_test_helper::prepare_recover(lfm, num_jfiles);
+ lpmgr_test_helper::recover(lfm, lm, jc, false, 0);
+ lpmgr_test_helper::finalize(lm);
+ lfm.destroy_journal();
+ }
+ {
+ lpmgr lm;
+ lpmgr_test_helper::prepare_recover(lfm, num_jfiles);
+ lpmgr_test_helper::recover(lfm, lm, jc, true, 0);
+ lpmgr_test_helper::finalize(lm);
+ lfm.destroy_journal();
+ }
+ {
+ lpmgr lm;
+ lpmgr_test_helper::prepare_recover(lfm, num_jfiles);
+ lpmgr_test_helper::recover(lfm, lm, jc, true, 5 * lfm.size());
+ lpmgr_test_helper::finalize(lm);
+ lfm.destroy_journal();
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "done" << endl;
+}
+
+/*
+ * Check that 0 and/or null and other extreme/boundary parameters behave as expected.
+ */
+QPID_AUTO_TEST_CASE(zero_null_params)
+{
+ string test_name = get_test_name(test_filename, "zero_null_params");
+ const u_int16_t num_jfiles = 8;
+ try
+ {
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ lfid_pfid_map lfm(test_name, test_name);
+ lpmgr lm;
+ lpmgr_test_helper::initialize(lfm, lm, jc, num_jfiles, true, 0);
+
+ // Check that inserting 0 files works ok
+ lpmgr_test_helper::insert(lfm, lm, jc, 0, 0);
+ lpmgr_test_helper::insert(lfm, lm, jc, 2, 0);
+ lpmgr_test_helper::insert(lfm, lm, jc, num_jfiles - 1, 0);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "done" << endl;
+}
+
+/*
+ * Check that initialize()/recover() works correctly after a previous initialize()/recover() with/without an intervening
+ * finalize().
+ */
+QPID_AUTO_TEST_CASE(multiple_initialization_recover)
+{
+ string test_name = get_test_name(test_filename, "multiple_initialization_recover");
+ ::srand48(1); // init random gen for repeatable tests when using lpmgr_test_helper::prepare_recover()
+
+ // Set combinations of value pairs to be used for number of journal files in first and second init
+ u_int16_t num_jfiles_arr[][2] = {{8, 12}, {4, 7}, {0, 0}}; // end with zeros
+ try
+ {
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ lfid_pfid_map lfm(test_name, test_name);
+ for (unsigned p = 0; p < 8; p++)
+ {
+ const bool i_0 = p & 0x01; // first bit
+ const bool i_1 = p & 0x02; // second bit
+ const bool f = p & 0x04; // third bit
+ lpmgr_test_helper::check_multiple_initialization_recover(lfm, jc, num_jfiles_arr, i_0, f, i_1);
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "done" << endl;
+}
+
+/*
+ * Check that insert() works correctly after initialize() and shifts the pfid sequence beyond the insert point correctly:
+ *
+ * The following sequence is tested:
+ * initialize 4 pfids=[0,1,2,3] lfids=[0,1,2,3]
+ * insert 1 after lfid 0 pfids=[0,4,1,2,3] lfids=[0,2,3,4,1]
+ * insert 2 after lfid 2 pfids=[0,4,1,5,6,2,3] lfids=[0,2,5,6,1,3,4]
+ * insert 1 after lfid 6 pfids=[0,4,1,5,6,2,3,7] lfids=[0,2,5,6,1,3,4,7]
+ * issert 1 after lfid 3 pfids=[0,4,1,5,8,6,2,3,7] lfids=[0,2,6,7,1,3,5,8,4]
+ */
+QPID_AUTO_TEST_CASE(initialize_insert)
+{
+ string test_name = get_test_name(test_filename, "initialize_insert");
+ const u_int16_t initial_num_jfiles = 8;
+ try
+ {
+ jdir::create_dir(test_dir); // Check test dir exists; create it if not
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ lfid_pfid_map lfm(test_name, test_name);
+ lpmgr lm;
+ lpmgr_test_helper::initialize(lfm, lm, jc, initial_num_jfiles, true, 0);
+
+ lpmgr_test_helper::insert(lfm, lm, jc, 0);
+ lpmgr_test_helper::insert(lfm, lm, jc, 2, 2);
+ lpmgr_test_helper::insert(lfm, lm, jc, 6);
+ lpmgr_test_helper::insert(lfm, lm, jc, 3);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "done" << endl;
+}
+
+/*
+ * Check that insert() works correctly after recover() and shifts the pfid sequence beyond the insert point correctly:
+ *
+ * The following sequence is tested:
+ * recover 4 pfids=[0,2,3,1] lfids=[0,3,1,2]
+ * insert 1 after lfid 0 pfids=[0,4,2,3,1] lfids=[0,4,2,3,1]
+ * insert 2 after lfid 2 pfids=[0,4,2,5,6,3,1] lfids=[0,6,2,5,1,3,4]
+ * insert 1 after lfid 6 pfids=[0,4,2,5,6,3,1,7] lfids=[0,6,2,5,1,3,4,7]
+ * issert 1 after lfid 3 pfids=[0,4,2,5,8,6,3,1,7] lfids=[0,7,2,6,1,3,5,8,4]
+ */
+QPID_AUTO_TEST_CASE(recover_insert)
+{
+ string test_name = get_test_name(test_filename, "recover_insert");
+ const u_int16_t initial_num_jfiles = 4;
+ ::srand48(1); // init random gen for repeatable tests when using lpmgr_test_helper::prepare_recover()
+ try
+ {
+ jdir::create_dir(test_dir); // Check test dir exists; create it if not
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ lfid_pfid_map lfm(test_name, test_name);
+ lpmgr lm;
+ lpmgr_test_helper::prepare_recover(lfm, initial_num_jfiles);
+ lpmgr_test_helper::recover(lfm, lm, jc, true, 0);
+
+ lpmgr_test_helper::insert(lfm, lm, jc, 0);
+ lpmgr_test_helper::insert(lfm, lm, jc, 2, 2);
+ lpmgr_test_helper::insert(lfm, lm, jc, 6);
+ lpmgr_test_helper::insert(lfm, lm, jc, 3);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "done" << endl;
+}
+
+/*
+ * Check that illegal ae parameter combinations are caught and result in an exception being thrown.
+ */
+QPID_AUTO_TEST_CASE(ae_parameters)
+{
+ string test_name = get_test_name(test_filename, "ae_parameters");
+ ::srand48(1); // init random gen for repeatable tests when using lpmgr_test_helper::prepare_recover()
+ try
+ {
+ jdir::create_dir(test_dir); // Check test dir exists; create it if not
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ lfid_pfid_map lfm(test_name, test_name);
+ const u_int16_t num_jfiles = 8;
+ lpmgr lm;
+
+ for (unsigned i = 0; i < 2; i++)
+ {
+ if (i)
+ lpmgr_test_helper::initialize(lfm, lm, jc, num_jfiles, false, 0);
+ else
+ {
+ lpmgr_test_helper::prepare_recover(lfm, num_jfiles);
+ lpmgr_test_helper::recover(lfm, lm, jc, false, 0);
+ }
+
+ lpmgr_test_helper::check_ae_max_jfiles(lm, num_jfiles, num_jfiles - 2);
+ lpmgr_test_helper::check_ae_max_jfiles(lm, num_jfiles, 0);
+ lpmgr_test_helper::check_ae_max_jfiles(lm, num_jfiles, 2 * num_jfiles);
+ lpmgr_test_helper::check_ae_max_jfiles(lm, num_jfiles, num_jfiles);
+ lfm.destroy_journal();
+ }
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "done" << endl;
+}
+
+/*
+ * Check that initialized or recovered journals with auto-expand disabled will not allow either inserts or appends.
+ */
+QPID_AUTO_TEST_CASE(ae_disabled)
+{
+ string test_name = get_test_name(test_filename, "ae_disabled");
+ ::srand48(1); // init random gen for repeatable tests when using lpmgr_test_helper::prepare_recover()
+ try
+ {
+ jdir::create_dir(test_dir); // Check test dir exists; create it if not
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ lfid_pfid_map lfm(test_name, test_name);
+ lpmgr_test_helper::check_limit(lfm, jc, false, 8, 0);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "done" << endl;
+}
+
+/*
+ * Check that initialized or recovered journals with auto-expand enabled and a file limit set will enforce the correct
+ * limits on inserts and appends.
+ */
+QPID_AUTO_TEST_CASE(ae_enabled_limit)
+{
+ string test_name = get_test_name(test_filename, "ae_enabled_limit");
+ ::srand48(1); // init random gen for repeatable tests when using lpmgr_test_helper::prepare_recover()
+ try
+ {
+ jdir::create_dir(test_dir); // Check test dir exists; create it if not
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ lfid_pfid_map lfm(test_name, test_name);
+ lpmgr_test_helper::check_limit(lfm, jc, true, 8, 32);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "done" << endl;
+}
+
+/*
+ * Check that initialized or recovered journals with auto-expand enabled and no file limit set (0) will allow inserts and
+ * appends up to the file limit JRNL_MAX_NUM_FILES.
+ */
+QPID_AUTO_TEST_CASE(ae_enabled_unlimited)
+{
+ string test_name = get_test_name(test_filename, "ae_enabled_unlimited");
+ ::srand48(1); // init random gen for repeatable tests when using lpmgr_test_helper::prepare_recover()
+ try
+ {
+ jdir::create_dir(test_dir); // Check test dir exists; create it if not
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ lfid_pfid_map lfm(test_name, test_name);
+ lpmgr_test_helper::check_limit(lfm, jc, true, 8, 0);
+ }
+ catch(const exception& e) { BOOST_FAIL(e.what()); }
+ cout << "done" << endl;
+}
+
+#else
+/*
+ * ==============================================
+ * LONG TESTS
+ * This section contains long tests and soak tests,
+ * and are run using target check-long (ie "make
+ * check-long"). These are built when LONG_TEST is
+ * defined.
+ * ==============================================
+ */
+
+/*
+ * Tests randomized combinations of initialization/recovery, initial size, number, size and location of inserts.
+ *
+ * To reproduce a specific test, comment out the get_seed() statement and uncomment the literal below, adjusting the seed
+ * value to that required.
+ */
+QPID_AUTO_TEST_CASE(randomized_tests)
+{
+ string test_name = get_test_name(test_filename, "randomized_tests");
+ const long seed = get_seed();
+ // const long seed = 0x2d9b69d32;
+ cout << "seed=0x" << hex << seed << dec << " " << flush;
+ ::srand48(seed);
+
+ lfid_pfid_map lfm(test_name, test_name);
+ flist pfidl;
+ flist lfidl;
+ rcvdat rd;
+ u_int16_t curr_ae_max_jfiles = 0;
+ jdir::create_dir(test_dir); // Check test dir exists; create it if not
+
+ for (int test_num = 0; test_num < 250; test_num++)
+ {
+ test_jrnl_cb cb;
+ test_jrnl jc(test_name, test_dir, test_name, cb);
+ lpmgr lm;
+ // 50% chance of recovery except first run and if there is still ae space left
+ const bool recover_flag = test_num > 0 &&
+ curr_ae_max_jfiles > lfm.size() &&
+ 2.0 * ::drand48() < 1.0;
+ if (recover_flag)
+ {
+ // Recover from previous iteration
+ lfm.get_pfid_list(pfidl);
+ lfm.get_lfid_list(lfidl);
+ lfm.write_journal(true, curr_ae_max_jfiles, JFSIZE_SBLKS);
+ lpmgr_test_helper::rcvdat_init(rd, pfidl, true, curr_ae_max_jfiles);
+ lm.recover(rd, &jc, &jc.new_fcntl);
+ lpmgr_test_helper::check_pfids_lfids(lm, pfidl, lfidl);
+ }
+ else
+ {
+ // Initialize from scratch
+ const u_int16_t num_jfiles = 4 + u_int16_t(21.0 * ::drand48()); // size: 4 - 25 files
+ curr_ae_max_jfiles = u_int16_t(4 * num_jfiles * ::drand48()); // size: 0 - 100 files
+ if (curr_ae_max_jfiles > JRNL_MAX_NUM_FILES) curr_ae_max_jfiles = JRNL_MAX_NUM_FILES;
+ else if (curr_ae_max_jfiles <= num_jfiles) curr_ae_max_jfiles = 0;
+ lfm.destroy_journal();
+ lfm.journal_create(num_jfiles, num_jfiles);
+ lfm.get_pfid_list(pfidl);
+ lfm.get_lfid_list(lfidl);
+ lm.initialize(num_jfiles, true, curr_ae_max_jfiles, &jc, &jc.new_fcntl);
+ lpmgr_test_helper::check_linear_pfids_lfids(lm, num_jfiles);
+ }
+
+ // Loop to insert pfids
+ const int num_inserts = 1 + int(lfm.size() * ::drand48());
+ for (int i = 0; i < num_inserts; i++)
+ {
+ const u_int16_t size = lm.num_jfiles();
+ const u_int16_t after_lfid = u_int16_t(1.0 * size * ::drand48());
+ const u_int16_t num_jfiles = 1 + u_int16_t(4.0 * ::drand48());
+ const bool legal = lm.ae_max_jfiles()
+ ? size + num_jfiles <= lm.ae_max_jfiles()
+ : size + num_jfiles <= JRNL_MAX_NUM_FILES;
+ if (legal)
+ {
+ lfm.journal_insert(after_lfid, num_jfiles);
+ lfm.get_pfid_list(pfidl);
+ lfm.get_lfid_list(lfidl);
+
+ lm.insert(after_lfid, &jc, &jc.new_fcntl, num_jfiles);
+ lpmgr_test_helper::check_pfids_lfids(lm, pfidl, lfidl);
+ }
+ else
+ {
+ try
+ {
+ lm.insert(after_lfid, &jc, &jc.new_fcntl, num_jfiles);
+ BOOST_FAIL("lpmgr::insert() succeeded and exceeded limit");
+ }
+ catch (const jexception& e)
+ {
+ BOOST_CHECK_EQUAL(e.err_code(), jerrno::JERR_LFMGR_AEFNUMLIMIT);
+ break; // no more inserts...
+ }
+ }
+ }
+ lm.finalize();
+ BOOST_CHECK_EQUAL(lm.is_init(), false);
+ BOOST_CHECK_EQUAL(lm.num_jfiles(), u_int16_t(0));
+ BOOST_CHECK_EQUAL(lm.get_fcntlp(0), (void*)0);
+ }
+ cout << "done" << endl;
+}
+
+#endif
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/_ut_rec_hdr.cpp b/qpid/cpp/src/tests/legacystore/jrnl/_ut_rec_hdr.cpp
new file mode 100644
index 0000000000..099e576bbd
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/_ut_rec_hdr.cpp
@@ -0,0 +1,438 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../unit_test.h"
+
+#include <ctime>
+#include <iostream>
+#include "qpid/legacystore/jrnl/deq_hdr.h"
+#include "qpid/legacystore/jrnl/enq_hdr.h"
+#include "qpid/legacystore/jrnl/file_hdr.h"
+#include "qpid/legacystore/jrnl/jcfg.h"
+#include "qpid/legacystore/jrnl/rec_tail.h"
+#include "qpid/legacystore/jrnl/txn_hdr.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(rec_hdr_suite)
+
+const string test_filename("_ut_rec_hdr");
+
+QPID_AUTO_TEST_CASE(hdr_class)
+{
+ cout << test_filename << ".hdr_class: " << flush;
+ rec_hdr h1;
+ BOOST_CHECK_EQUAL(h1._magic, 0UL);
+ BOOST_CHECK_EQUAL(h1._version, 0);
+ BOOST_CHECK_EQUAL(h1._eflag, 0);
+ BOOST_CHECK_EQUAL(h1._uflag, 0);
+ BOOST_CHECK_EQUAL(h1._rid, 0ULL);
+ BOOST_CHECK(!h1.get_owi());
+
+ const u_int32_t magic = 0x89abcdefUL;
+ const u_int16_t uflag = 0x5537;
+ const u_int8_t version = 0xef;
+ const u_int64_t rid = 0x123456789abcdef0ULL;
+ const bool owi = true;
+
+ rec_hdr h2(magic, version, rid, owi);
+ BOOST_CHECK_EQUAL(h2._magic, magic);
+ BOOST_CHECK_EQUAL(h2._version, version);
+#ifdef JRNL_LITTLE_ENDIAN
+ BOOST_CHECK_EQUAL(h2._eflag, RHM_LENDIAN_FLAG);
+#else
+ BOOST_CHECK_EQUAL(h2._eflag, RHM_BENDIAN_FLAG);
+#endif
+ BOOST_CHECK_EQUAL(h2._uflag, (const u_int16_t)rec_hdr::HDR_OVERWRITE_INDICATOR_MASK);
+ BOOST_CHECK_EQUAL(h2._rid, rid);
+ BOOST_CHECK_EQUAL(h2.get_owi(), owi);
+ h2._uflag = uflag;
+ BOOST_CHECK(h2.get_owi());
+ h2.set_owi(true);
+ BOOST_CHECK(h2.get_owi());
+ BOOST_CHECK_EQUAL(h2._uflag, uflag);
+ h2.set_owi(false);
+ BOOST_CHECK(!h2.get_owi());
+ BOOST_CHECK_EQUAL(h2._uflag, (uflag & ~(const u_int16_t)rec_hdr::HDR_OVERWRITE_INDICATOR_MASK));
+ h2.set_owi(true);
+ BOOST_CHECK(h2.get_owi());
+ BOOST_CHECK_EQUAL(h2._uflag, uflag);
+
+ h1.hdr_copy(h2);
+ BOOST_CHECK_EQUAL(h1._magic, magic);
+ BOOST_CHECK_EQUAL(h1._version, version);
+#ifdef JRNL_LITTLE_ENDIAN
+ BOOST_CHECK_EQUAL(h1._eflag, RHM_LENDIAN_FLAG);
+#else
+ BOOST_CHECK_EQUAL(h1._eflag, RHM_BENDIAN_FLAG);
+#endif
+ BOOST_CHECK_EQUAL(h1._uflag, uflag);
+ BOOST_CHECK_EQUAL(h1._rid, rid);
+ BOOST_CHECK(h1.get_owi());
+ BOOST_CHECK_EQUAL(h1._uflag, uflag);
+
+ h1.reset();
+ BOOST_CHECK_EQUAL(h1._magic, 0UL);
+ BOOST_CHECK_EQUAL(h1._version, 0);
+ BOOST_CHECK_EQUAL(h1._eflag, 0);
+ BOOST_CHECK_EQUAL(h1._uflag, 0);
+ BOOST_CHECK_EQUAL(h1._rid, 0ULL);
+ BOOST_CHECK(!h1.get_owi());
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(rec_tail_class)
+{
+ cout << test_filename << ".rec_tail_class: " << flush;
+ const u_int32_t magic = 0xfedcba98;
+ const u_int64_t rid = 0xfedcba9876543210ULL;
+ const u_int32_t xmagic = ~magic;
+
+ {
+ rec_tail rt1;
+ BOOST_CHECK_EQUAL(rt1._xmagic, 0xffffffffUL);
+ BOOST_CHECK_EQUAL(rt1._rid, 0ULL);
+ }
+
+ {
+ rec_tail rt2(magic, rid);
+ BOOST_CHECK_EQUAL(rt2._xmagic, magic);
+ BOOST_CHECK_EQUAL(rt2._rid, rid);
+ }
+
+ {
+ rec_hdr h(magic, RHM_JDAT_VERSION, rid, true);
+ rec_tail rt3(h);
+ BOOST_CHECK_EQUAL(rt3._xmagic, xmagic);
+ BOOST_CHECK_EQUAL(rt3._rid, rid);
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(file_hdr_class)
+{
+ cout << test_filename << ".file_hdr_class: " << flush;
+ const u_int32_t magic = 0xfedcba98UL;
+ const u_int8_t version = 0xa5;
+ const u_int16_t uflag = 0x5537;
+ const u_int64_t rid = 0xfedcba9876543210ULL;
+ const u_int16_t pfid = 0xfedcU;
+ const u_int16_t lfid = 0xf0e1U;
+#ifdef JRNL_32_BIT
+ const std::size_t fro = 0xfedcba98UL;
+#else
+ const std::size_t fro = 0xfedcba9876543210ULL;
+#endif
+ timespec ts;
+ const bool owi = true;
+
+ {
+ file_hdr fh1;
+ BOOST_CHECK_EQUAL(fh1._magic, 0UL);
+ BOOST_CHECK_EQUAL(fh1._version, 0);
+ BOOST_CHECK_EQUAL(fh1._eflag, 0);
+ BOOST_CHECK_EQUAL(fh1._uflag, 0);
+ BOOST_CHECK_EQUAL(fh1._rid, 0ULL);
+ BOOST_CHECK_EQUAL(fh1._pfid, 0UL);
+ BOOST_CHECK_EQUAL(fh1._lfid, 0U);
+ BOOST_CHECK_EQUAL(fh1._fro, std::size_t(0));
+ BOOST_CHECK_EQUAL(fh1._ts_sec, std::time_t(0));
+ BOOST_CHECK_EQUAL(fh1._ts_nsec, u_int32_t(0));
+ BOOST_CHECK(!fh1.get_owi());
+ }
+
+ {
+ file_hdr fh2(magic, version, rid, pfid, lfid, fro, owi, false);
+ BOOST_CHECK_EQUAL(fh2._magic, magic);
+ BOOST_CHECK_EQUAL(fh2._version, version);
+#ifdef JRNL_LITTLE_ENDIAN
+ BOOST_CHECK_EQUAL(fh2._eflag, RHM_LENDIAN_FLAG);
+#else
+ BOOST_CHECK_EQUAL(fh2._eflag, RHM_BENDIAN_FLAG);
+#endif
+ BOOST_CHECK_EQUAL(fh2._uflag, (const u_int16_t)rec_hdr::HDR_OVERWRITE_INDICATOR_MASK);
+ BOOST_CHECK_EQUAL(fh2._rid, rid);
+ BOOST_CHECK_EQUAL(fh2._pfid, pfid );
+ BOOST_CHECK_EQUAL(fh2._lfid, lfid);
+ BOOST_CHECK_EQUAL(fh2._fro, fro);
+ BOOST_CHECK_EQUAL(fh2._ts_sec, std::time_t(0));
+ BOOST_CHECK_EQUAL(fh2._ts_nsec, u_int32_t(0));
+ ::clock_gettime(CLOCK_REALTIME, &ts);
+ fh2.set_time(ts);
+ BOOST_CHECK_EQUAL(fh2._ts_sec, ts.tv_sec);
+ BOOST_CHECK_EQUAL(fh2._ts_nsec, u_int32_t(ts.tv_nsec));
+ BOOST_CHECK(fh2.get_owi());
+
+ fh2._uflag = uflag;
+ BOOST_CHECK(fh2.get_owi());
+
+ fh2.set_owi(false);
+ BOOST_CHECK(!fh2.get_owi());
+ BOOST_CHECK_EQUAL(fh2._uflag,
+ (uflag & ~(const u_int16_t)rec_hdr::HDR_OVERWRITE_INDICATOR_MASK));
+
+ fh2.set_owi(true);
+ BOOST_CHECK(fh2.get_owi());
+ BOOST_CHECK_EQUAL(fh2._uflag, uflag);
+ }
+
+ {
+ file_hdr fh3(magic, version, rid, pfid, lfid, fro, owi, true);
+ BOOST_CHECK_EQUAL(fh3._magic, magic);
+ BOOST_CHECK_EQUAL(fh3._version, version);
+#ifdef JRNL_LITTLE_ENDIAN
+ BOOST_CHECK_EQUAL(fh3._eflag, RHM_LENDIAN_FLAG);
+#else
+ BOOST_CHECK_EQUAL(fh3._eflag, RHM_BENDIAN_FLAG);
+#endif
+ BOOST_CHECK_EQUAL(fh3._uflag, (const u_int16_t)rec_hdr::HDR_OVERWRITE_INDICATOR_MASK);
+ BOOST_CHECK_EQUAL(fh3._rid, rid);
+ BOOST_CHECK_EQUAL(fh3._pfid, pfid);
+ BOOST_CHECK_EQUAL(fh3._lfid, lfid);
+ BOOST_CHECK_EQUAL(fh3._fro, fro);
+ BOOST_CHECK(fh3._ts_sec - ts.tv_sec <= 1); // No more than 1 sec difference
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(enq_hdr_class)
+{
+ cout << test_filename << ".enq_hdr_class: " << flush;
+ const u_int32_t magic = 0xfedcba98UL;
+ const u_int8_t version = 0xa5;
+ const u_int64_t rid = 0xfedcba9876543210ULL;
+ const u_int16_t uflag = 0x5537;
+#ifdef JRNL_32_BIT
+ const std::size_t xidsize = 0xfedcba98UL;
+ const std::size_t dsize = 0x76543210UL;
+#else
+ const std::size_t xidsize = 0xfedcba9876543210ULL;
+ const std::size_t dsize = 0x76543210fedcba98ULL;
+#endif
+ const bool owi = true;
+
+ {
+ enq_hdr eh1;
+ BOOST_CHECK_EQUAL(eh1._magic, 0UL);
+ BOOST_CHECK_EQUAL(eh1._version, 0);
+ BOOST_CHECK_EQUAL(eh1._eflag, 0);
+ BOOST_CHECK_EQUAL(eh1._uflag, 0);
+ BOOST_CHECK_EQUAL(eh1._rid, 0ULL);
+ BOOST_CHECK_EQUAL(eh1._xidsize, std::size_t(0));
+ BOOST_CHECK_EQUAL(eh1._dsize, std::size_t(0));
+ BOOST_CHECK(!eh1.get_owi());
+ }
+
+ {
+ enq_hdr eh2(magic, version, rid, xidsize, dsize, owi, false);
+ BOOST_CHECK_EQUAL(eh2._magic, magic);
+ BOOST_CHECK_EQUAL(eh2._version, version);
+#ifdef JRNL_LITTLE_ENDIAN
+ BOOST_CHECK_EQUAL(eh2._eflag, RHM_LENDIAN_FLAG);
+#else
+ BOOST_CHECK_EQUAL(eh2._eflag, RHM_BENDIAN_FLAG);
+#endif
+ BOOST_CHECK_EQUAL(eh2._uflag, (const u_int16_t)rec_hdr::HDR_OVERWRITE_INDICATOR_MASK);
+ BOOST_CHECK_EQUAL(eh2._rid, rid);
+ BOOST_CHECK_EQUAL(eh2._xidsize, xidsize);
+ BOOST_CHECK_EQUAL(eh2._dsize, dsize);
+ BOOST_CHECK(eh2.get_owi());
+ BOOST_CHECK(!eh2.is_transient());
+ BOOST_CHECK(!eh2.is_external());
+
+ eh2._uflag = uflag;
+ BOOST_CHECK(eh2.get_owi());
+ BOOST_CHECK(eh2.is_transient());
+ BOOST_CHECK(eh2.is_external());
+
+ eh2.set_owi(false);
+ BOOST_CHECK(!eh2.get_owi());
+ BOOST_CHECK(eh2.is_transient());
+ BOOST_CHECK(eh2.is_external());
+ BOOST_CHECK_EQUAL(eh2._uflag,
+ (uflag & ~(const u_int16_t)rec_hdr::HDR_OVERWRITE_INDICATOR_MASK));
+
+ eh2.set_owi(true);
+ BOOST_CHECK(eh2.get_owi());
+ BOOST_CHECK(eh2.is_transient());
+ BOOST_CHECK(eh2.is_external());
+ BOOST_CHECK_EQUAL(eh2._uflag, uflag);
+
+ eh2.set_transient(false);
+ BOOST_CHECK(eh2.get_owi());
+ BOOST_CHECK(!eh2.is_transient());
+ BOOST_CHECK(eh2.is_external());
+ BOOST_CHECK_EQUAL(eh2._uflag, uflag & ~(const u_int16_t)enq_hdr::ENQ_HDR_TRANSIENT_MASK);
+
+ eh2.set_transient(true);
+ BOOST_CHECK(eh2.get_owi());
+ BOOST_CHECK(eh2.is_transient());
+ BOOST_CHECK(eh2.is_external());
+ BOOST_CHECK_EQUAL(eh2._uflag, uflag);
+
+ eh2.set_external(false);
+ BOOST_CHECK(eh2.get_owi());
+ BOOST_CHECK(eh2.is_transient());
+ BOOST_CHECK(!eh2.is_external());
+ BOOST_CHECK_EQUAL(eh2._uflag, uflag & ~(const u_int16_t)enq_hdr::ENQ_HDR_EXTERNAL_MASK);
+
+ eh2.set_external(true);
+ BOOST_CHECK(eh2.get_owi());
+ BOOST_CHECK(eh2.is_transient());
+ BOOST_CHECK(eh2.is_external());
+ BOOST_CHECK_EQUAL(eh2._uflag, uflag);
+ }
+
+ {
+ enq_hdr eh3(magic, version, rid, xidsize, dsize, owi, true);
+ BOOST_CHECK_EQUAL(eh3._magic, magic);
+ BOOST_CHECK_EQUAL(eh3._version, version);
+#ifdef JRNL_LITTLE_ENDIAN
+ BOOST_CHECK_EQUAL(eh3._eflag, RHM_LENDIAN_FLAG);
+#else
+ BOOST_CHECK_EQUAL(eh3._eflag, RHM_BENDIAN_FLAG);
+#endif
+ BOOST_CHECK_EQUAL(eh3._uflag, (const u_int16_t)enq_hdr::ENQ_HDR_TRANSIENT_MASK |
+ (const u_int16_t)rec_hdr::HDR_OVERWRITE_INDICATOR_MASK);
+ BOOST_CHECK_EQUAL(eh3._rid, rid);
+ BOOST_CHECK_EQUAL(eh3._xidsize, xidsize);
+ BOOST_CHECK_EQUAL(eh3._dsize, dsize);
+ BOOST_CHECK(eh3.get_owi());
+ BOOST_CHECK(eh3.is_transient());
+ BOOST_CHECK(!eh3.is_external());
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(deq_hdr_class)
+{
+ cout << test_filename << ".deq_hdr_class: " << flush;
+ const u_int32_t magic = 0xfedcba98UL;
+ const u_int8_t version = 0xa5;
+ const u_int16_t uflag = 0x5537;
+ const u_int64_t rid = 0xfedcba9876543210ULL;
+ const u_int64_t drid = 0x76543210fedcba98ULL;
+#ifdef JRNL_32_BIT
+ const std::size_t xidsize = 0xfedcba98UL;
+#else
+ const std::size_t xidsize = 0xfedcba9876543210ULL;
+#endif
+ const bool owi = true;
+
+ {
+ deq_hdr dh1;
+ BOOST_CHECK_EQUAL(dh1._magic, 0UL);
+ BOOST_CHECK_EQUAL(dh1._version, 0);
+ BOOST_CHECK_EQUAL(dh1._eflag, 0);
+ BOOST_CHECK_EQUAL(dh1._uflag, 0);
+ BOOST_CHECK_EQUAL(dh1._rid, 0ULL);
+ BOOST_CHECK_EQUAL(dh1._deq_rid, 0ULL);
+ BOOST_CHECK_EQUAL(dh1._xidsize, std::size_t(0));
+ BOOST_CHECK(!dh1.get_owi());
+ }
+
+ {
+ deq_hdr dh2(magic, version, rid, drid, xidsize, owi);
+ BOOST_CHECK_EQUAL(dh2._magic, magic);
+ BOOST_CHECK_EQUAL(dh2._version, version);
+#ifdef JRNL_LITTLE_ENDIAN
+ BOOST_CHECK_EQUAL(dh2._eflag, RHM_LENDIAN_FLAG);
+#else
+ BOOST_CHECK_EQUAL(dh2._eflag, RHM_BENDIAN_FLAG);
+#endif
+ BOOST_CHECK_EQUAL(dh2._uflag, (const u_int16_t)rec_hdr::HDR_OVERWRITE_INDICATOR_MASK);
+ BOOST_CHECK_EQUAL(dh2._rid, rid);
+ BOOST_CHECK_EQUAL(dh2._deq_rid, drid);
+ BOOST_CHECK_EQUAL(dh2._xidsize, xidsize);
+ BOOST_CHECK(dh2.get_owi());
+
+ dh2._uflag = uflag;
+ BOOST_CHECK(dh2.get_owi());
+
+ dh2.set_owi(false);
+ BOOST_CHECK(!dh2.get_owi());
+ BOOST_CHECK_EQUAL(dh2._uflag,
+ (uflag & ~(const u_int16_t)rec_hdr::HDR_OVERWRITE_INDICATOR_MASK));
+
+ dh2.set_owi(true);
+ BOOST_CHECK(dh2.get_owi());
+ BOOST_CHECK_EQUAL(dh2._uflag, uflag);
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(txn_hdr_class)
+{
+ cout << test_filename << ".txn_hdr_class: " << flush;
+ const u_int32_t magic = 0xfedcba98UL;
+ const u_int8_t version = 0xa5;
+ const u_int16_t uflag = 0x5537;
+ const u_int64_t rid = 0xfedcba9876543210ULL;
+#ifdef JRNL_32_BIT
+ const std::size_t xidsize = 0xfedcba98UL;
+#else
+ const std::size_t xidsize = 0xfedcba9876543210ULL;
+#endif
+ const bool owi = true;
+
+ {
+ txn_hdr th1;
+ BOOST_CHECK_EQUAL(th1._magic, 0UL);
+ BOOST_CHECK_EQUAL(th1._version, 0);
+ BOOST_CHECK_EQUAL(th1._eflag, 0);
+ BOOST_CHECK_EQUAL(th1._uflag, 0);
+ BOOST_CHECK_EQUAL(th1._rid, 0ULL);
+ BOOST_CHECK_EQUAL(th1._xidsize, std::size_t(0));
+ BOOST_CHECK(!th1.get_owi());
+ }
+
+ {
+ txn_hdr th2(magic, version, rid, xidsize, owi);
+ BOOST_CHECK_EQUAL(th2._magic, magic);
+ BOOST_CHECK_EQUAL(th2._version, version);
+#ifdef JRNL_LITTLE_ENDIAN
+ BOOST_CHECK_EQUAL(th2._eflag, RHM_LENDIAN_FLAG);
+#else
+ BOOST_CHECK_EQUAL(th2._eflag, RHM_BENDIAN_FLAG);
+#endif
+ BOOST_CHECK_EQUAL(th2._uflag, (const u_int16_t)rec_hdr::HDR_OVERWRITE_INDICATOR_MASK);
+ BOOST_CHECK_EQUAL(th2._rid, rid);
+ BOOST_CHECK_EQUAL(th2._xidsize, xidsize);
+ BOOST_CHECK(th2.get_owi());
+
+ th2._uflag = uflag;
+ BOOST_CHECK(th2.get_owi());
+
+ th2.set_owi(false);
+ BOOST_CHECK(!th2.get_owi());
+ BOOST_CHECK_EQUAL(th2._uflag,
+ (uflag & ~(const u_int16_t)rec_hdr::HDR_OVERWRITE_INDICATOR_MASK));
+
+ th2.set_owi(true);
+ BOOST_CHECK(th2.get_owi());
+ BOOST_CHECK_EQUAL(th2._uflag, uflag);
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/_ut_time_ns.cpp b/qpid/cpp/src/tests/legacystore/jrnl/_ut_time_ns.cpp
new file mode 100644
index 0000000000..f1b53bb97b
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/_ut_time_ns.cpp
@@ -0,0 +1,163 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../unit_test.h"
+
+#include <ctime>
+#include <iostream>
+#include "qpid/legacystore/jrnl/time_ns.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(time_ns_suite)
+
+const string test_filename("_ut_time_ns");
+
+QPID_AUTO_TEST_CASE(constructors)
+{
+ cout << test_filename << ".constructors: " << flush;
+ const std::time_t sec = 123;
+ const long nsec = 123456789;
+
+ time_ns t1;
+ BOOST_CHECK_EQUAL(t1.tv_sec, 0);
+ BOOST_CHECK_EQUAL(t1.tv_nsec, 0);
+ BOOST_CHECK_EQUAL(t1.is_zero(), true);
+ time_ns t2(sec, nsec);
+ BOOST_CHECK_EQUAL(t2.tv_sec, sec);
+ BOOST_CHECK_EQUAL(t2.tv_nsec, nsec);
+ BOOST_CHECK_EQUAL(t2.is_zero(), false);
+ time_ns t3(t1);
+ BOOST_CHECK_EQUAL(t3.tv_sec, 0);
+ BOOST_CHECK_EQUAL(t3.tv_nsec, 0);
+ BOOST_CHECK_EQUAL(t3.is_zero(), true);
+ time_ns t4(t2);
+ BOOST_CHECK_EQUAL(t4.tv_sec, sec);
+ BOOST_CHECK_EQUAL(t4.tv_nsec, nsec);
+ BOOST_CHECK_EQUAL(t4.is_zero(), false);
+ t4.set_zero();
+ BOOST_CHECK_EQUAL(t4.tv_sec, 0);
+ BOOST_CHECK_EQUAL(t4.tv_nsec, 0);
+ BOOST_CHECK_EQUAL(t4.is_zero(), true);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(operators)
+{
+ cout << test_filename << ".operators: " << flush;
+ const std::time_t sec1 = 123;
+ const long nsec1 = 123456789;
+ const std::time_t sec2 = 1;
+ const long nsec2 = 999999999;
+ const std::time_t sec_sum = sec1 + sec2 + 1;
+ const long nsec_sum = nsec1 + nsec2 - 1000000000;
+ const std::time_t sec_1_minus_2 = sec1 - sec2 - 1;
+ const long nsec_1_minus_2 = nsec1 - nsec2 + 1000000000;
+ const std::time_t sec_2_minus_1 = sec2 - sec1;
+ const long nsec_2_minus_1 = nsec2 - nsec1;
+ time_ns z;
+ time_ns t1(sec1, nsec1);
+ time_ns t2(sec2, nsec2);
+
+ time_ns t3 = z;
+ BOOST_CHECK_EQUAL(t3.tv_sec, 0);
+ BOOST_CHECK_EQUAL(t3.tv_nsec, 0);
+ BOOST_CHECK_EQUAL(t3 == z, true);
+ BOOST_CHECK_EQUAL(t3 != z, false);
+ BOOST_CHECK_EQUAL(t3 > z, false);
+ BOOST_CHECK_EQUAL(t3 >= z, true);
+ BOOST_CHECK_EQUAL(t3 < z, false);
+ BOOST_CHECK_EQUAL(t3 <= z, true);
+
+ t3 = t1;
+ BOOST_CHECK_EQUAL(t3.tv_sec, sec1);
+ BOOST_CHECK_EQUAL(t3.tv_nsec, nsec1);
+ BOOST_CHECK_EQUAL(t3 == t1, true);
+ BOOST_CHECK_EQUAL(t3 != t1, false);
+ BOOST_CHECK_EQUAL(t3 > t1, false);
+ BOOST_CHECK_EQUAL(t3 >= t1, true);
+ BOOST_CHECK_EQUAL(t3 < t1, false);
+ BOOST_CHECK_EQUAL(t3 <= t1, true);
+
+ t3 += z;
+ BOOST_CHECK_EQUAL(t3.tv_sec, sec1);
+ BOOST_CHECK_EQUAL(t3.tv_nsec, nsec1);
+
+ t3 = t2;
+ BOOST_CHECK_EQUAL(t3.tv_sec, sec2);
+ BOOST_CHECK_EQUAL(t3.tv_nsec, nsec2);
+ BOOST_CHECK_EQUAL(t3 == t2, true);
+ BOOST_CHECK_EQUAL(t3 != t2, false);
+ BOOST_CHECK_EQUAL(t3 > t2, false);
+ BOOST_CHECK_EQUAL(t3 >= t2, true);
+ BOOST_CHECK_EQUAL(t3 < t2, false);
+ BOOST_CHECK_EQUAL(t3 <= t2, true);
+
+ t3 += z;
+ BOOST_CHECK_EQUAL(t3.tv_sec, sec2);
+ BOOST_CHECK_EQUAL(t3.tv_nsec, nsec2);
+
+ t3 = t1;
+ t3 += t2;
+ BOOST_CHECK_EQUAL(t3.tv_sec, sec_sum);
+ BOOST_CHECK_EQUAL(t3.tv_nsec, nsec_sum);
+
+ t3 = t1;
+ t3 -= t2;
+ BOOST_CHECK_EQUAL(t3.tv_sec, sec_1_minus_2);
+ BOOST_CHECK_EQUAL(t3.tv_nsec, nsec_1_minus_2);
+
+ t3 = t2;
+ t3 -= t1;
+ BOOST_CHECK_EQUAL(t3.tv_sec, sec_2_minus_1);
+ BOOST_CHECK_EQUAL(t3.tv_nsec, nsec_2_minus_1);
+
+ t3 = t1 + t2;
+ BOOST_CHECK_EQUAL(t3.tv_sec, sec_sum);
+ BOOST_CHECK_EQUAL(t3.tv_nsec, nsec_sum);
+
+ t3 = t1 - t2;
+ BOOST_CHECK_EQUAL(t3.tv_sec, sec_1_minus_2);
+ BOOST_CHECK_EQUAL(t3.tv_nsec, nsec_1_minus_2);
+
+ t3 = t2 - t1;
+ BOOST_CHECK_EQUAL(t3.tv_sec, sec_2_minus_1);
+ BOOST_CHECK_EQUAL(t3.tv_nsec, nsec_2_minus_1);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(str)
+{
+ cout << test_filename << ".str: " << flush;
+ time_ns t1(123, 123456789);
+ BOOST_CHECK_EQUAL(t1.str(), "123.123457");
+ BOOST_CHECK_EQUAL(t1.str(9), "123.123456789");
+ BOOST_CHECK_EQUAL(t1.str(0), "123");
+ time_ns t2(1, 1);
+ BOOST_CHECK_EQUAL(t2.str(9), "1.000000001");
+ time_ns t3(-12, 345);
+ BOOST_CHECK_EQUAL(t3.str(9), "-11.999999655");
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/_ut_txn_map.cpp b/qpid/cpp/src/tests/legacystore/jrnl/_ut_txn_map.cpp
new file mode 100644
index 0000000000..595ce0f6c6
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/_ut_txn_map.cpp
@@ -0,0 +1,106 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../unit_test.h"
+
+#include <iomanip>
+#include <iostream>
+#include "qpid/legacystore/jrnl/txn_map.h"
+#include <sstream>
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(txn_map_suite)
+
+const string test_filename("_ut_txn_map");
+
+// === Helper functions ===
+
+const string make_xid(u_int64_t rid)
+{
+ stringstream ss;
+ ss << "XID-" << setfill('0') << setw(16) << hex << rid;
+ ss << "-0123456789abcdef";
+ return ss.str();
+}
+
+void check_td_equal(txn_data& td1, txn_data& td2)
+{
+ BOOST_CHECK_EQUAL(td1._rid, td2._rid);
+ BOOST_CHECK_EQUAL(td1._drid, td2._drid);
+ BOOST_CHECK_EQUAL(td1._pfid, td2._pfid);
+ BOOST_CHECK_EQUAL(td1._enq_flag, td2._enq_flag);
+ BOOST_CHECK_EQUAL(td1._aio_compl, td2._aio_compl);
+}
+
+// === Test suite ===
+
+QPID_AUTO_TEST_CASE(constructor)
+{
+ cout << test_filename << ".constructor: " << flush;
+ const u_int64_t rid = 0x123456789abcdef0ULL;
+ const u_int64_t drid = 0xfedcba9876543210ULL;
+ const u_int16_t pfid = 0xfedcU;
+ const bool enq_flag = true;
+ txn_data td(rid, drid, pfid, enq_flag);
+ BOOST_CHECK_EQUAL(td._rid, rid);
+ BOOST_CHECK_EQUAL(td._drid, drid);
+ BOOST_CHECK_EQUAL(td._pfid, pfid);
+ BOOST_CHECK_EQUAL(td._enq_flag, enq_flag);
+ BOOST_CHECK_EQUAL(td._aio_compl, false);
+
+ txn_map t1;
+ BOOST_CHECK(t1.empty());
+ BOOST_CHECK_EQUAL(t1.size(), u_int32_t(0));
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(insert_get)
+{
+ cout << test_filename << ".insert_get: " << flush;
+ u_int16_t fid;
+ u_int64_t rid;
+ u_int16_t pfid_start = 0x2000U;
+ u_int64_t rid_begin = 0xffffffff00000000ULL;
+ u_int64_t rid_end = 0xffffffff00000200ULL;
+
+ // insert with no dups
+ u_int64_t rid_incr_1 = 4ULL;
+ txn_map t2;
+ t2.set_num_jfiles(pfid_start + (rid_end - rid_begin)/rid_incr_1);
+ for (rid = rid_begin, fid = pfid_start; rid < rid_end; rid += rid_incr_1, fid++)
+ t2.insert_txn_data(make_xid(rid), txn_data(rid, ~rid, fid, false));
+ BOOST_CHECK(!t2.empty());
+ BOOST_CHECK_EQUAL(t2.size(), u_int32_t(128));
+
+ // get
+ u_int64_t rid_incr_2 = 6ULL;
+ for (u_int64_t rid = rid_begin; rid < rid_end; rid += rid_incr_2)
+ {
+ string xid = make_xid(rid);
+ BOOST_CHECK_EQUAL(t2.in_map(xid), (rid%rid_incr_1 ? false : true));
+ }
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/chk_jdata b/qpid/cpp/src/tests/legacystore/jrnl/chk_jdata
new file mode 100755
index 0000000000..2ac87d91b9
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/chk_jdata
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
+JRNL_BLK_SIZE=512 # Block size in bytes
+JRNL_PAGE_SIZE=256 # Journal page size in blocks
+JRNL_FILE_SIZE=12 # Journal file size in pages
+let END_OFFSET=${JRNL_BLK_SIZE}*${JRNL_PAGE_SIZE}*${JRNL_FILE_SIZE}
+for f in jdata/test.*.jdat; do
+ echo $f
+ hexdump -C -n 1024 $f
+ hexdump -C -s ${END_OFFSET} $f
+ echo "============"
+done
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/cp_rtest_jrnl b/qpid/cpp/src/tests/legacystore/jrnl/cp_rtest_jrnl
new file mode 100755
index 0000000000..e21f991788
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/cp_rtest_jrnl
@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+JDATA_DIR=jdata
+TAR_DIR=rd_test_jrnls
+
+function get_filename
+{
+ local prefix=$1
+ local file_num=$2
+ local suffix=$3
+
+ if (( file_num < 10 )); then
+ local num="000${file_num}"
+ elif (( file_num < 100 )); then
+ local num="00${file_num}"
+ elif (( file_num < 1000 )); then
+ local num="0${file_num}"
+ else
+ local num="${file_num}"
+ fi
+ FILENAME=${prefix}${num}${suffix}
+ return 0
+}
+
+if (( $# != 1 )); then
+ echo "Incorrect args, expected 1 arg (usage: \"prep <testnum>\")"
+ exit
+fi
+
+get_filename "t" $1 ".tar.gz"
+if [[ -d ${JDATA_DIR} ]]; then
+ rm -rf ${JDATA_DIR}/*
+else
+ mkdir -p ${JDATA_DIR}
+fi
+if [[ -f "${TAR_DIR}/${FILENAME}" ]]; then
+ tar -C ${JDATA_DIR} -xzf "${TAR_DIR}/${FILENAME}"
+else
+ echo "Error: file \"${TAR_DIR}/${FILENAME}\" not found."
+fi
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jhexdump b/qpid/cpp/src/tests/legacystore/jrnl/jhexdump
new file mode 100755
index 0000000000..b013914441
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jhexdump
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if [ -z "$1" ]; then
+ echo "No directory specified."
+ exit
+fi
+
+JDIR=$1
+echo "Target directory: ${JDIR}"
+
+rm -f j*.txt
+
+if [ -d "${JDIR}" ]; then
+ n=0
+ for f in "${JDIR}"/*.jdat; do
+ echo "$f -> j$n.txt"
+ hexdump -C "$f" > j$n.txt
+ (( n += 1 ))
+ done
+else
+ echo "This directory does not exist."
+fi
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_data_src.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_data_src.cpp
new file mode 100644
index 0000000000..e4656ef83f
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_data_src.cpp
@@ -0,0 +1,207 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../../unit_test.h"
+#include <cstddef>
+#include "data_src.h"
+#include <iomanip>
+#include <iostream>
+
+using namespace boost::unit_test;
+using namespace mrg::jtt;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(jtt_data_src)
+
+const string test_filename("_ut_data_src");
+
+long
+get_seed()
+{
+ timespec ts;
+ if (::clock_gettime(CLOCK_REALTIME, &ts))
+ BOOST_FAIL("Unable to read clock to generate seed.");
+ long tenths = ts.tv_nsec / 100000000;
+ return long(10 * ts.tv_sec + tenths); // time in tenths of a second
+}
+
+#ifndef LONG_TEST
+/*
+ * ==============================================
+ * NORMAL TESTS
+ * This section contains normal "make check" tests
+ * for building/packaging. These are built when
+ * LONG_TEST is _not_ defined.
+ * ==============================================
+ */
+
+QPID_AUTO_TEST_CASE(data)
+{
+ cout << test_filename << ".data: " << flush;
+ BOOST_CHECK(data_src::max_dsize > 0);
+ for (std::size_t i=0; i<1024; i++)
+ {
+ const char* dp = data_src::get_data(i);
+ BOOST_CHECK_EQUAL(*dp, static_cast<char>('0' + ((i + 1) % 10)));
+ }
+ for (std::size_t i=data_src::max_dsize-1024; i<data_src::max_dsize; i++)
+ {
+ const char* dp = data_src::get_data(i);
+ BOOST_CHECK_EQUAL(*dp, static_cast<char>('0' + ((i + 1) % 10)));
+ }
+ const char* dp1 = data_src::get_data(data_src::max_dsize);
+ BOOST_CHECK_EQUAL(dp1,(char*) 0);
+ const char* dp2 = data_src::get_data(data_src::max_dsize + 0x1000);
+ BOOST_CHECK_EQUAL(dp2, (char*)0);
+ cout << "ok" << endl;
+}
+
+// There is a long version of this test in _ut_long_data_src.cpp
+QPID_AUTO_TEST_CASE(xid_data_xid)
+{
+ const std::size_t num = 64;
+ cout << test_filename << ".xid_data_xid: " << flush;
+ BOOST_CHECK_EQUAL(data_src::get_xid(1), "0");
+ BOOST_CHECK_EQUAL(data_src::get_xid(2), "01");
+ BOOST_CHECK_EQUAL(data_src::get_xid(3), "002");
+ BOOST_CHECK_EQUAL(data_src::get_xid(4), "0003");
+ BOOST_CHECK_EQUAL(data_src::get_xid(5), "00004");
+ BOOST_CHECK_EQUAL(data_src::get_xid(6), "000005");
+ BOOST_CHECK_EQUAL(data_src::get_xid(7), "0000006");
+ BOOST_CHECK_EQUAL(data_src::get_xid(8), "00000007");
+ BOOST_CHECK_EQUAL(data_src::get_xid(9), "xid:00008");
+ BOOST_CHECK_EQUAL(data_src::get_xid(10), "xid:000009");
+ BOOST_CHECK_EQUAL(data_src::get_xid(11), "xid:0000010");
+ BOOST_CHECK_EQUAL(data_src::get_xid(12), "xid:00000011");
+ BOOST_CHECK_EQUAL(data_src::get_xid(13), "xid:00000012:");
+ BOOST_CHECK_EQUAL(data_src::get_xid(14), "xid:00000013:n");
+ BOOST_CHECK_EQUAL(data_src::get_xid(15), "xid:00000014:no");
+ std::size_t i = 15;
+ for (; i<num; i++)
+ {
+ string xid(data_src::get_xid(i));
+
+ ostringstream oss;
+ oss << setfill('0') << "xid:" << setw(8) << i << ":";
+
+ BOOST_CHECK_EQUAL(xid.size(), i);
+ BOOST_CHECK_EQUAL(xid.substr(0, 13), oss.str());
+ BOOST_CHECK_EQUAL(xid[13], 'n');
+ BOOST_CHECK_EQUAL(xid[i-1], (char)('a' + ((i-1)%26)));
+ }
+ for (std::size_t j=data_src::max_xsize-num; j<data_src::max_xsize; j++,i++)
+ {
+ string xid(data_src::get_xid(j));
+
+ ostringstream oss;
+ oss << setfill('0') << "xid:" << setw(8) << i << ":";
+
+ BOOST_CHECK_EQUAL(xid.size(), j);
+ BOOST_CHECK_EQUAL(xid.substr(0, 13), oss.str());
+ BOOST_CHECK_EQUAL(xid[13], 'n');
+ BOOST_CHECK_EQUAL(xid[j-1], (char)('a' + ((j-1)%26)));
+ }
+ cout << "ok" << endl;
+}
+
+#else
+/*
+ * ==============================================
+ * LONG TESTS
+ * This section contains long tests and soak tests,
+ * and are run using target check-long (ie "make
+ * check-long"). These are built when LONG_TEST is
+ * defined.
+ * ==============================================
+ */
+
+/*
+ * To reproduce a specific test, comment out the get_seed() statement and uncomment the literal below, adjusting the seed
+ * value to that required.
+ */
+QPID_AUTO_TEST_CASE(xid_data_xid)
+{
+ const long seed = get_seed();
+ // const long seed = 0x2d9b69d32;
+ ::srand48(seed);
+
+ const std::size_t num = 1024;
+ cout << test_filename << ".xid_data_xid seed=0x" << std::hex << seed << std::dec << ": " << flush;
+ BOOST_CHECK_EQUAL(data_src::get_xid(1), "0");
+ BOOST_CHECK_EQUAL(data_src::get_xid(2), "01");
+ BOOST_CHECK_EQUAL(data_src::get_xid(3), "002");
+ BOOST_CHECK_EQUAL(data_src::get_xid(4), "0003");
+ BOOST_CHECK_EQUAL(data_src::get_xid(5), "00004");
+ BOOST_CHECK_EQUAL(data_src::get_xid(6), "000005");
+ BOOST_CHECK_EQUAL(data_src::get_xid(7), "0000006");
+ BOOST_CHECK_EQUAL(data_src::get_xid(8), "00000007");
+ BOOST_CHECK_EQUAL(data_src::get_xid(9), "xid:00008");
+ BOOST_CHECK_EQUAL(data_src::get_xid(10), "xid:000009");
+ BOOST_CHECK_EQUAL(data_src::get_xid(11), "xid:0000010");
+ BOOST_CHECK_EQUAL(data_src::get_xid(12), "xid:00000011");
+ BOOST_CHECK_EQUAL(data_src::get_xid(13), "xid:00000012:");
+ BOOST_CHECK_EQUAL(data_src::get_xid(14), "xid:00000013:n");
+ BOOST_CHECK_EQUAL(data_src::get_xid(15), "xid:00000014:no");
+ std::size_t i = 15;
+ for (; i<num; i++)
+ {
+ string xid(data_src::get_xid(i));
+
+ ostringstream oss;
+ oss << setfill('0') << "xid:" << setw(8) << i << ":";
+
+ BOOST_CHECK_EQUAL(xid.size(), i);
+ BOOST_CHECK_EQUAL(xid.substr(0, 13), oss.str());
+ BOOST_CHECK_EQUAL(xid[13], 'n');
+ BOOST_CHECK_EQUAL(xid[i-1], (char)('a' + ((i-1)%26)));
+ }
+ for (std::size_t j=data_src::max_xsize-num; j<data_src::max_xsize; j++,i++)
+ {
+ string xid(data_src::get_xid(j));
+
+ ostringstream oss;
+ oss << setfill('0') << "xid:" << setw(8) << i << ":";
+
+ BOOST_CHECK_EQUAL(xid.size(), j);
+ BOOST_CHECK_EQUAL(xid.substr(0, 13), oss.str());
+ BOOST_CHECK_EQUAL(xid[13], 'n');
+ BOOST_CHECK_EQUAL(xid[j-1], (char)('a' + ((j-1)%26)));
+ }
+ std::srand(seed);
+ for (int cnt=0; cnt<1000; cnt++,i++)
+ {
+ std::size_t k = 1 + ::lrand48() % (data_src::max_xsize - 1);
+ string xid(data_src::get_xid(k));
+
+ ostringstream oss;
+ oss << setfill('0') << "xid:" << setw(8) << i << ":";
+
+ BOOST_CHECK_EQUAL(xid.size(), k);
+ BOOST_CHECK_EQUAL(xid.substr(0, 13), oss.str());
+ BOOST_CHECK_EQUAL(xid[13], 'n');
+ BOOST_CHECK_EQUAL(xid[k-1], (char)('a' + ((k-1)%26)));
+ }
+ cout << "ok" << endl;
+}
+
+#endif
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_jrnl_init_params.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_jrnl_init_params.cpp
new file mode 100644
index 0000000000..9fefe25105
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_jrnl_init_params.cpp
@@ -0,0 +1,100 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../../unit_test.h"
+#include "jrnl_init_params.h"
+#include <iostream>
+
+using namespace boost::unit_test;
+using namespace mrg::jtt;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(jtt_jrnl_init_params)
+
+const string test_filename("_ut_jrnl_init_params");
+
+QPID_AUTO_TEST_CASE(constructor)
+{
+ cout << test_filename << ".constructor: " << flush;
+ const string jid = "jid";
+ const string jdir = "jdir";
+ const string bfn = "base filename";
+ const u_int16_t num_jfiles = 123;
+ const bool ae = false;
+ const u_int16_t ae_max_jfiles = 456;
+ const u_int32_t jfsize_sblks = 789;
+ jrnl_init_params jip(jid, jdir, bfn, num_jfiles, ae, ae_max_jfiles, jfsize_sblks);
+ BOOST_CHECK_EQUAL(jip.jid(), jid);
+ BOOST_CHECK_EQUAL(jip.jdir(), jdir);
+ BOOST_CHECK_EQUAL(jip.base_filename(), bfn);
+ BOOST_CHECK_EQUAL(jip.num_jfiles(), num_jfiles);
+ BOOST_CHECK_EQUAL(jip.is_ae(), ae);
+ BOOST_CHECK_EQUAL(jip.ae_max_jfiles(), ae_max_jfiles);
+ BOOST_CHECK_EQUAL(jip.jfsize_sblks(), jfsize_sblks);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(copy_constructor_1)
+{
+ cout << test_filename << ".copy_constructor_1: " << flush;
+ const string jid = "jid";
+ const string jdir = "jdir";
+ const string bfn = "base filename";
+ const u_int16_t num_jfiles = 123;
+ const bool ae = false;
+ const u_int16_t ae_max_jfiles = 456;
+ const u_int32_t jfsize_sblks = 789;
+ jrnl_init_params jip1(jid, jdir, bfn, num_jfiles, ae, ae_max_jfiles, jfsize_sblks);
+ jrnl_init_params jip2(jip1);
+ BOOST_CHECK_EQUAL(jip2.jid(), jid);
+ BOOST_CHECK_EQUAL(jip2.jdir(), jdir);
+ BOOST_CHECK_EQUAL(jip2.base_filename(), bfn);
+ BOOST_CHECK_EQUAL(jip2.num_jfiles(), num_jfiles);
+ BOOST_CHECK_EQUAL(jip2.is_ae(), ae);
+ BOOST_CHECK_EQUAL(jip2.ae_max_jfiles(), ae_max_jfiles);
+ BOOST_CHECK_EQUAL(jip2.jfsize_sblks(), jfsize_sblks);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(copy_constructor_2)
+{
+ cout << test_filename << ".copy_constructor_2: " << flush;
+ const string jid = "jid";
+ const string jdir = "jdir";
+ const string bfn = "base filename";
+ const u_int16_t num_jfiles = 123;
+ const bool ae = false;
+ const u_int16_t ae_max_jfiles = 456;
+ const u_int32_t jfsize_sblks = 789;
+ jrnl_init_params::shared_ptr p(new jrnl_init_params(jid, jdir, bfn, num_jfiles, ae, ae_max_jfiles, jfsize_sblks));
+ jrnl_init_params jip2(p.get());
+ BOOST_CHECK_EQUAL(jip2.jid(), jid);
+ BOOST_CHECK_EQUAL(jip2.jdir(), jdir);
+ BOOST_CHECK_EQUAL(jip2.base_filename(), bfn);
+ BOOST_CHECK_EQUAL(jip2.num_jfiles(), num_jfiles);
+ BOOST_CHECK_EQUAL(jip2.is_ae(), ae);
+ BOOST_CHECK_EQUAL(jip2.ae_max_jfiles(), ae_max_jfiles);
+ BOOST_CHECK_EQUAL(jip2.jfsize_sblks(), jfsize_sblks);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_jrnl_instance.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_jrnl_instance.cpp
new file mode 100644
index 0000000000..12f1c542d6
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_jrnl_instance.cpp
@@ -0,0 +1,178 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../../unit_test.h"
+
+#include <iostream>
+#include "jrnl_init_params.h"
+#include "jrnl_instance.h"
+#include "qpid/legacystore/jrnl/jdir.h"
+#include "qpid/legacystore/jrnl/jerrno.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace mrg::jtt;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(jtt_jrnl_instance)
+
+const string test_filename("_ut_jrnl_instance");
+const char* tdp = getenv("TMP_DATA_DIR");
+const string test_dir(tdp && strlen(tdp) > 0 ? tdp : "/var/tmp/JttTest");
+
+QPID_AUTO_TEST_CASE(constructor_1)
+{
+ cout << test_filename << ".constructor_1: " << flush;
+ const string jid = "jid1";
+ const string jdir = test_dir + "/test1";
+ const string bfn = "test";
+ const u_int16_t num_jfiles = 20;
+ const bool ae = false;
+ const u_int16_t ae_max_jfiles = 45;
+ const u_int32_t jfsize_sblks = 128;
+
+ args a("a1");
+ using mrg::jtt::test_case;
+ test_case::shared_ptr p(new test_case(1, 0, 0, 0, false, 0, 0, test_case::JTT_PERSISTNET, test_case::JDL_INTERNAL,
+ "t1"));
+ jrnl_instance ji(jid, jdir, bfn, num_jfiles, ae, ae_max_jfiles, jfsize_sblks);
+ ji.init_tc(p, &a);
+ ji.run_tc();
+ ji.tc_wait_compl();
+ try { jdir::verify_dir(jdir, bfn); }
+ catch (const jexception& e) { BOOST_ERROR(e.what()); }
+ jdir::delete_dir(jdir);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_2)
+{
+ cout << test_filename << ".constructor_2: " << flush;
+ const string jid = "jid2";
+ const string jdir = test_dir + "/test2";
+ const string bfn = "test";
+ const u_int16_t num_jfiles = 20;
+ const bool ae = false;
+ const u_int16_t ae_max_jfiles = 45;
+ const u_int32_t jfsize_sblks = 128;
+
+ args a("a2");
+ using mrg::jtt::test_case;
+ test_case::shared_ptr p(new test_case(2, 0, 0, 0, false, 0, 0, test_case::JTT_PERSISTNET, test_case::JDL_INTERNAL,
+ "t2"));
+ jrnl_init_params::shared_ptr jpp(new jrnl_init_params(jid, jdir, bfn, num_jfiles, ae, ae_max_jfiles, jfsize_sblks));
+ jrnl_instance ji(jpp);
+ ji.init_tc(p, &a);
+ ji.run_tc();
+ ji.tc_wait_compl();
+ try { jdir::verify_dir(jdir, bfn); }
+ catch (const jexception& e) { BOOST_ERROR(e.what()); }
+ jdir::delete_dir(jdir);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_3)
+{
+ cout << test_filename << ".constructor_3: " << flush;
+ const string jid = "jid3";
+ const string jdir = test_dir + "/test3";
+ const string bfn = "test";
+ const u_int16_t num_jfiles = 20;
+ const bool ae = false;
+ const u_int16_t ae_max_jfiles = 45;
+ const u_int32_t jfsize_sblks = 128;
+
+ args a("a3");
+ using mrg::jtt::test_case;
+ test_case::shared_ptr p(new test_case(3, 0, 0, 0, false, 0, 0, test_case::JTT_PERSISTNET, test_case::JDL_INTERNAL,
+ "t3"));
+ jrnl_init_params::shared_ptr jpp(new jrnl_init_params(jid, jdir, bfn, num_jfiles, ae, ae_max_jfiles, jfsize_sblks));
+ jrnl_instance ji(jpp);
+ ji.init_tc(p, &a);
+ ji.run_tc();
+ ji.tc_wait_compl();
+ try { jdir::verify_dir(jdir, bfn); }
+ catch (const jexception& e) { BOOST_ERROR(e.what()); }
+ jdir::delete_dir(jdir);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(recover)
+{
+ cout << test_filename << ".recover: " << flush;
+ const string jid = "jid5";
+ const string jdir = test_dir + "/test5";
+ const string bfn = "test";
+ const u_int16_t num_jfiles = 20;
+ const bool ae = false;
+ const u_int16_t ae_max_jfiles = 0;
+ const u_int32_t jfsize_sblks = 128;
+
+ args a("a4");
+ using mrg::jtt::test_case;
+ test_case::shared_ptr p(new test_case(5, 0, 0, 0, false, 0, 0, test_case::JTT_PERSISTNET, test_case::JDL_INTERNAL,
+ "t5"));
+ jrnl_init_params::shared_ptr jpp(new jrnl_init_params(jid, jdir, bfn, num_jfiles, ae, ae_max_jfiles, jfsize_sblks));
+ jrnl_instance ji(jpp);
+ ji.init_tc(p, &a);
+ ji.run_tc();
+ ji.tc_wait_compl();
+ try { jdir::verify_dir(jdir, bfn); }
+ catch (const jexception& e) { BOOST_ERROR(e.what()); }
+ a.recover_mode = true;
+ ji.init_tc(p, &a);
+ ji.run_tc();
+ ji.tc_wait_compl();
+ try { jdir::verify_dir(jdir, bfn); }
+ catch (const jexception& e) { BOOST_ERROR(e.what()); }
+ jdir::delete_dir(jdir);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(recover_no_files)
+{
+ cout << test_filename << ".recover_no_files: " << flush;
+ const string jid = "jid6";
+ const string jdir = test_dir + "/test6";
+ const string bfn = "test";
+ const u_int16_t num_jfiles = 20;
+ const bool ae = false;
+ const u_int16_t ae_max_jfiles = 0;
+ const u_int32_t jfsize_sblks = 128;
+
+ args a("a5");
+ a.recover_mode = true;
+ using mrg::jtt::test_case;
+ test_case::shared_ptr p(new test_case(6, 0, 0, 0, false, 0, 0, test_case::JTT_PERSISTNET, test_case::JDL_INTERNAL,
+ "t6"));
+ jrnl_init_params::shared_ptr jpp(new jrnl_init_params(jid, jdir, bfn, num_jfiles, ae, ae_max_jfiles, jfsize_sblks));
+ jrnl_instance ji(jpp);
+ ji.init_tc(p, &a);
+ ji.run_tc();
+ ji.tc_wait_compl();
+ try { jdir::verify_dir(jdir, bfn); }
+ catch (const jexception& e) { BOOST_ERROR(e.what()); }
+ jdir::delete_dir(jdir);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_read_arg.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_read_arg.cpp
new file mode 100644
index 0000000000..0d2025270d
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_read_arg.cpp
@@ -0,0 +1,146 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../../unit_test.h"
+#include <boost/test/unit_test_log.hpp>
+#include "read_arg.h"
+#include <iostream>
+
+#include <boost/program_options.hpp>
+namespace po = boost::program_options;
+using namespace mrg::jtt;
+using namespace boost::unit_test;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(jtt_read_arg)
+
+const string test_filename("_ut_read_arg");
+
+QPID_AUTO_TEST_CASE(constructor)
+{
+ cout << test_filename << ".constructor: " << flush;
+ read_arg ra1;
+ BOOST_CHECK_EQUAL(ra1.val(), read_arg::NONE);
+ BOOST_CHECK_EQUAL(ra1.str(), "NONE");
+ read_arg ra2(read_arg::NONE);
+ BOOST_CHECK_EQUAL(ra2.val(), read_arg::NONE);
+ BOOST_CHECK_EQUAL(ra2.str(), "NONE");
+ read_arg ra3(read_arg::ALL);
+ BOOST_CHECK_EQUAL(ra3.val(), read_arg::ALL);
+ BOOST_CHECK_EQUAL(ra3.str(), "ALL");
+ read_arg ra4(read_arg::RANDOM);
+ BOOST_CHECK_EQUAL(ra4.val(), read_arg::RANDOM);
+ BOOST_CHECK_EQUAL(ra4.str(), "RANDOM");
+ read_arg ra5(read_arg::LAZYLOAD);
+ BOOST_CHECK_EQUAL(ra5.val(), read_arg::LAZYLOAD);
+ BOOST_CHECK_EQUAL(ra5.str(), "LAZYLOAD");
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(set_val)
+{
+ cout << test_filename << ".set_val: " << flush;
+ read_arg ra;
+ BOOST_CHECK_EQUAL(ra.val(), read_arg::NONE);
+ BOOST_CHECK_EQUAL(ra.str(), "NONE");
+ ra.set_val(read_arg::ALL);
+ BOOST_CHECK_EQUAL(ra.val(), read_arg::ALL);
+ BOOST_CHECK_EQUAL(ra.str(), "ALL");
+ ra.set_val(read_arg::RANDOM);
+ BOOST_CHECK_EQUAL(ra.val(), read_arg::RANDOM);
+ BOOST_CHECK_EQUAL(ra.str(), "RANDOM");
+ ra.set_val(read_arg::LAZYLOAD);
+ BOOST_CHECK_EQUAL(ra.val(), read_arg::LAZYLOAD);
+ BOOST_CHECK_EQUAL(ra.str(), "LAZYLOAD");
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(parse)
+{
+ cout << test_filename << ".parse: " << flush;
+ read_arg ra;
+ ra.parse("LAZYLOAD");
+ BOOST_CHECK_EQUAL(ra.val(), read_arg::LAZYLOAD);
+ BOOST_CHECK_EQUAL(ra.str(), "LAZYLOAD");
+ ra.parse("ALL");
+ BOOST_CHECK_EQUAL(ra.val(), read_arg::ALL);
+ BOOST_CHECK_EQUAL(ra.str(), "ALL");
+ BOOST_CHECK_THROW(ra.parse(""), po::invalid_option_value)
+ BOOST_CHECK_EQUAL(ra.val(), read_arg::ALL);
+ BOOST_CHECK_EQUAL(ra.str(), "ALL");
+ BOOST_CHECK_THROW(ra.parse("abc123"), po::invalid_option_value)
+ BOOST_CHECK_EQUAL(ra.val(), read_arg::ALL);
+ BOOST_CHECK_EQUAL(ra.str(), "ALL");
+ ra.parse("NONE");
+ BOOST_CHECK_EQUAL(ra.val(), read_arg::NONE);
+ BOOST_CHECK_EQUAL(ra.str(), "NONE");
+ ra.parse("RANDOM");
+ BOOST_CHECK_EQUAL(ra.val(), read_arg::RANDOM);
+ BOOST_CHECK_EQUAL(ra.str(), "RANDOM");
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(istream_)
+{
+ cout << test_filename << ".istream_: " << flush;
+ read_arg ra;
+ istringstream ss1("LAZYLOAD", ios::in);
+ ss1 >> ra;
+ BOOST_CHECK_EQUAL(ra.val(), read_arg::LAZYLOAD);
+ BOOST_CHECK_EQUAL(ra.str(), "LAZYLOAD");
+ istringstream ss2("ALL", ios::in);
+ ss2 >> ra;
+ BOOST_CHECK_EQUAL(ra.val(), read_arg::ALL);
+ BOOST_CHECK_EQUAL(ra.str(), "ALL");
+ istringstream ss3("NONE", ios::in);
+ ss3 >> ra;
+ BOOST_CHECK_EQUAL(ra.val(), read_arg::NONE);
+ BOOST_CHECK_EQUAL(ra.str(), "NONE");
+ istringstream ss4("RANDOM", ios::in);
+ ss4 >> ra;
+ BOOST_CHECK_EQUAL(ra.val(), read_arg::RANDOM);
+ BOOST_CHECK_EQUAL(ra.str(), "RANDOM");
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(ostream_)
+{
+ cout << test_filename << ".ostream_: " << flush;
+ ostringstream s1;
+ read_arg ra(read_arg::LAZYLOAD);
+ s1 << ra;
+ BOOST_CHECK_EQUAL(s1.str(), "LAZYLOAD");
+ ra.set_val(read_arg::ALL);
+ ostringstream s2;
+ s2 << ra;
+ BOOST_CHECK_EQUAL(s2.str(), "ALL");
+ ra.set_val(read_arg::NONE);
+ ostringstream s3;
+ s3 << ra;
+ BOOST_CHECK_EQUAL(s3.str(), "NONE");
+ ra.set_val(read_arg::RANDOM);
+ ostringstream s4;
+ s4 << ra;
+ BOOST_CHECK_EQUAL(s4.str(), "RANDOM");
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case.cpp
new file mode 100644
index 0000000000..3a7d0f951c
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case.cpp
@@ -0,0 +1,113 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../../unit_test.h"
+#include <cstddef>
+#include <iomanip>
+#include <iostream>
+#include "test_case.h"
+#include "test_case_result.h"
+
+using namespace boost::unit_test;
+using namespace mrg::jtt;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(jtt_test_case)
+
+const string test_filename("_ut_test_case");
+
+QPID_AUTO_TEST_CASE(constructor)
+{
+ cout << test_filename << ".constructor: " << flush;
+ const unsigned test_case_num = 0x12345;
+ const u_int32_t num_msgs = 0x100;
+ const std::size_t min_data_size = 0x1000;
+ const std::size_t max_data_size = 0;
+ const bool auto_deq = true;
+ const std::size_t min_xid_size = 0x200;
+ const std::size_t max_xid_size = 0x200;
+ using mrg::jtt::test_case;
+ const test_case::transient_t transient = test_case::JTT_PERSISTNET;
+ const test_case::external_t external = test_case::JDL_INTERNAL;
+ const string comment = "This is a test";
+
+ test_case tc(test_case_num, num_msgs, min_data_size, max_data_size, auto_deq,
+ min_xid_size, max_xid_size, transient, external, comment);
+ BOOST_CHECK_EQUAL(tc.test_case_num(), test_case_num);
+ BOOST_CHECK_EQUAL(tc.num_msgs(), num_msgs);
+ BOOST_CHECK_EQUAL(tc.min_data_size(), min_data_size);
+ BOOST_CHECK_EQUAL(tc.max_data_size(), max_data_size);
+ BOOST_CHECK_EQUAL(tc.auto_deq(), auto_deq);
+ BOOST_CHECK_EQUAL(tc.min_xid_size(), min_xid_size);
+ BOOST_CHECK_EQUAL(tc.max_xid_size(), max_xid_size);
+ BOOST_CHECK_EQUAL(tc.transient(), transient);
+ BOOST_CHECK_EQUAL(tc.external(), external);
+ BOOST_CHECK_EQUAL(tc.comment(), comment);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(results)
+{
+ cout << test_filename << ".results: " << flush;
+ const unsigned test_case_num = 0x12345;
+ const u_int32_t num_msgs = 0x100;
+ const std::size_t min_data_size = 0x1000;
+ const std::size_t max_data_size = 0;
+ const bool auto_deq = true;
+ const std::size_t min_xid_size = 0x200;
+ const std::size_t max_xid_size = 0x200;
+ using mrg::jtt::test_case;
+ const test_case::transient_t transient = test_case::JTT_PERSISTNET;
+ const test_case::external_t external = test_case::JDL_INTERNAL;
+ const string comment = "This is a test";
+ const unsigned num_results = 20;
+
+ test_case tc(test_case_num, num_msgs, min_data_size, max_data_size, auto_deq,
+ min_xid_size, max_xid_size, transient, external, comment);
+ for (unsigned i=0; i<num_results; i++)
+ {
+ ostringstream oss;
+ oss << "JID_" << setfill('0') << setw(2) << i;
+ test_case_result::shared_ptr p(new test_case_result(oss.str()));
+ tc.add_result(p);
+ }
+ BOOST_CHECK_EQUAL(tc.num_results(), num_results);
+ test_case_result_agregation ave = tc.average();
+ unsigned i=0;
+ for (test_case_result_agregation::tcrp_list_citr j=ave.rlist_begin(); j!=ave.rlist_end();
+ i++,j++)
+ {
+ ostringstream oss;
+ oss << "JID_" << setfill('0') << setw(2) << i;
+ BOOST_CHECK_EQUAL((*j)->jid(), oss.str());
+ }
+ for (unsigned i=0; i<num_results; i++)
+ {
+ ostringstream oss;
+ oss << "JID_" << setfill('0') << setw(2) << i;
+ BOOST_CHECK_EQUAL(ave[i]->jid(), oss.str());
+ }
+ tc.clear();
+ BOOST_CHECK_EQUAL(tc.num_results(), unsigned(0));
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case_result.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case_result.cpp
new file mode 100644
index 0000000000..dd83dbee69
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case_result.cpp
@@ -0,0 +1,206 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../../unit_test.h"
+
+#include <iostream>
+#include "qpid/legacystore/jrnl/jexception.h"
+#include "test_case_result.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace mrg::jtt;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(jtt_test_case_result)
+
+const string test_filename("_ut_test_case_result");
+
+QPID_AUTO_TEST_CASE(constructor)
+{
+ cout << test_filename << ".constructor: " << flush;
+ const string jid("journal id 1");
+ test_case_result tcr(jid);
+ BOOST_CHECK_EQUAL(tcr.jid(), jid);
+ BOOST_CHECK_EQUAL(tcr.exception(), false);
+ BOOST_CHECK_EQUAL(tcr.exception_count(), 0U);
+ const time_ns& ts1 = tcr.start_time();
+ BOOST_CHECK(ts1.is_zero());
+ const time_ns& ts2 = tcr.stop_time();
+ BOOST_CHECK(ts2.is_zero());
+ const time_ns& ts3 = tcr.test_time();
+ BOOST_CHECK(ts3.is_zero());
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(start_stop)
+{
+ cout << test_filename << ".start_stop: " << flush;
+ const string jid("journal id 2");
+ test_case_result tcr(jid);
+ BOOST_CHECK_EQUAL(tcr.exception(), false);
+ BOOST_CHECK_EQUAL(tcr.exception_count(), 0U);
+ const time_ns& ts1 = tcr.start_time();
+ BOOST_CHECK(ts1.is_zero());
+ const time_ns& ts2 = tcr.stop_time();
+ BOOST_CHECK(ts2.is_zero());
+ const time_ns& ts3 = tcr.test_time();
+ BOOST_CHECK(ts3.is_zero());
+
+ tcr.set_start_time();
+ BOOST_CHECK_EQUAL(tcr.exception(), false);
+ BOOST_CHECK_EQUAL(tcr.exception_count(), 0U);
+ const time_ns& ts4 = tcr.start_time();
+ BOOST_CHECK(!ts4.is_zero());
+ const time_ns& ts5 = tcr.stop_time();
+ BOOST_CHECK(ts5.is_zero());
+ const time_ns& ts6 = tcr.test_time();
+ BOOST_CHECK(ts6.is_zero());
+
+ ::usleep(1100000); // 1.1 sec in microseconds
+ tcr.set_stop_time();
+ BOOST_CHECK_EQUAL(tcr.exception(), false);
+ BOOST_CHECK_EQUAL(tcr.exception_count(), 0U);
+ const time_ns& ts7 = tcr.stop_time();
+ BOOST_CHECK(!ts7.is_zero());
+ const time_ns& ts8 = tcr.test_time();
+ BOOST_CHECK(ts8.tv_sec == 1);
+ BOOST_CHECK(ts8.tv_nsec > 100000000); // 0.1 sec in nanoseconds
+ BOOST_CHECK(ts8.tv_nsec < 200000000); // 0.2 sec in nanoseconds
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(start_exception_stop_1)
+{
+ cout << test_filename << ".start_exception_stop_1: " << flush;
+ const string jid("journal id 3");
+ test_case_result tcr(jid);
+ const u_int32_t err_code = 0x321;
+ const string err_msg = "exception message";
+ const jexception e(err_code, err_msg);
+ tcr.set_start_time();
+ ::usleep(1100000); // 1.1 sec in microseconds
+ tcr.add_exception(e);
+ BOOST_CHECK_EQUAL(tcr.exception(), true);
+ BOOST_CHECK_EQUAL(tcr.exception_count(), 1U);
+ BOOST_CHECK_EQUAL(tcr[0], e.what());
+ const time_ns& ts1 = tcr.stop_time();
+ BOOST_CHECK(!ts1.is_zero());
+ const time_ns& ts2 = tcr.test_time();
+ BOOST_CHECK(ts2.tv_sec == 1);
+ BOOST_CHECK(ts2.tv_nsec > 100000000); // 0.1 sec in nanoseconds
+ BOOST_CHECK(ts2.tv_nsec < 200000000); // 0.2 sec in nanoseconds
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(start_exception_stop_2)
+{
+ cout << test_filename << ".start_exception_stop_2: " << flush;
+ const string jid("journal id 4");
+ test_case_result tcr(jid);
+ const string err_msg = "exception message";
+ tcr.set_start_time();
+ ::usleep(1100000); // 1.1 sec in microseconds
+ tcr.add_exception(err_msg);
+ BOOST_CHECK_EQUAL(tcr.exception(), true);
+ BOOST_CHECK_EQUAL(tcr.exception_count(), 1U);
+ BOOST_CHECK_EQUAL(tcr[0], err_msg);
+ const time_ns& ts1 = tcr.stop_time();
+ BOOST_CHECK(!ts1.is_zero());
+ const time_ns& ts2 = tcr.test_time();
+ BOOST_CHECK(ts2.tv_sec == 1);
+ BOOST_CHECK(ts2.tv_nsec > 100000000); // 0.1 sec in nanoseconds
+ BOOST_CHECK(ts2.tv_nsec < 200000000); // 0.2 sec in nanoseconds
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(start_exception_stop_3)
+{
+ cout << test_filename << ".start_exception_stop_3: " << flush;
+ const string jid("journal id 5");
+ test_case_result tcr(jid);
+ const char* err_msg = "exception message";
+ tcr.set_start_time();
+ ::usleep(1100000); // 1.1 sec in microseconds
+ tcr.add_exception(err_msg);
+ BOOST_CHECK_EQUAL(tcr.exception(), true);
+ BOOST_CHECK_EQUAL(tcr.exception_count(), 1U);
+ BOOST_CHECK_EQUAL(tcr[0], err_msg);
+ const time_ns& ts1 = tcr.stop_time();
+ BOOST_CHECK(!ts1.is_zero());
+ const time_ns& ts2 = tcr.test_time();
+ BOOST_CHECK(ts2.tv_sec == 1);
+ BOOST_CHECK(ts2.tv_nsec > 100000000); // 0.1 sec in nanoseconds
+ BOOST_CHECK(ts2.tv_nsec < 200000000); // 0.2 sec in nanoseconds
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(start_exception)
+{
+ cout << test_filename << ".start_exception: " << flush;
+ const string jid("journal id 6");
+ test_case_result tcr(jid);
+ u_int32_t err_code = 0x654;
+ const string err_msg = "exception message";
+ const jexception e(err_code, err_msg);
+ tcr.set_start_time();
+ ::usleep(1100000); // 1.1 sec in microseconds
+ tcr.add_exception(e, false);
+ BOOST_CHECK_EQUAL(tcr.exception(), true);
+ BOOST_CHECK_EQUAL(tcr.exception_count(), 1U);
+ BOOST_CHECK_EQUAL(tcr[0], e.what());
+ const time_ns& ts1 = tcr.stop_time();
+ BOOST_CHECK(ts1.is_zero());
+ const time_ns& ts2 = tcr.test_time();
+ BOOST_CHECK(ts2.is_zero());
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(counters)
+{
+ cout << test_filename << ".counters: " << flush;
+ const u_int32_t num_enq = 125;
+ const u_int32_t num_deq = 64;
+ const u_int32_t num_read = 22;
+ const string jid("journal id 7");
+ test_case_result tcr(jid);
+ BOOST_CHECK_EQUAL(tcr.num_enq(), u_int32_t(0));
+ BOOST_CHECK_EQUAL(tcr.num_deq(), u_int32_t(0));
+ BOOST_CHECK_EQUAL(tcr.num_read(), u_int32_t(0));
+ for (unsigned i=0; i<num_enq; i++)
+ tcr.incr_num_enq();
+ BOOST_CHECK_EQUAL(tcr.num_enq(), num_enq);
+ BOOST_CHECK_EQUAL(tcr.num_deq(), u_int32_t(0));
+ BOOST_CHECK_EQUAL(tcr.num_read(), u_int32_t(0));
+ for (unsigned j=0; j<num_deq; j++)
+ tcr.incr_num_deq();
+ BOOST_CHECK_EQUAL(tcr.num_enq(), num_enq);
+ BOOST_CHECK_EQUAL(tcr.num_deq(), num_deq);
+ BOOST_CHECK_EQUAL(tcr.num_read(), u_int32_t(0));
+ for (unsigned k=0; k<num_read; k++)
+ tcr.incr_num_read();
+ BOOST_CHECK_EQUAL(tcr.num_enq(), num_enq);
+ BOOST_CHECK_EQUAL(tcr.num_deq(), num_deq);
+ BOOST_CHECK_EQUAL(tcr.num_read(), num_read);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case_result_agregation.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case_result_agregation.cpp
new file mode 100644
index 0000000000..aa01bf833d
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case_result_agregation.cpp
@@ -0,0 +1,178 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../../unit_test.h"
+#include <ctime>
+#include <iostream>
+#include "test_case_result_agregation.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace mrg::jtt;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(jtt_test_case_result_agregation)
+
+const string test_filename("_ut_test_case_result_agregation");
+
+// === Helper functions ===
+
+void check_agregate(const test_case_result_agregation& tcra, const u_int32_t num_enq,
+ const u_int32_t num_deq, const u_int32_t num_reads, const u_int32_t num_results,
+ const u_int32_t num_exceptions, const std::time_t secs, const long nsec)
+{
+ BOOST_CHECK_EQUAL(tcra.num_enq(), num_enq);
+ BOOST_CHECK_EQUAL(tcra.num_deq(), num_deq);
+ BOOST_CHECK_EQUAL(tcra.num_read(), num_reads);
+ BOOST_CHECK_EQUAL(tcra.num_results(), num_results);
+ BOOST_CHECK_EQUAL(tcra.exception_count(), num_exceptions);
+ BOOST_CHECK_EQUAL(tcra.exception(), num_exceptions > 0);
+ const time_ns& ts1 = tcra.test_time();
+ BOOST_CHECK_EQUAL(ts1.tv_sec, secs);
+ BOOST_CHECK_EQUAL(ts1.tv_nsec, nsec);
+}
+
+test_case_result::shared_ptr make_result(const string& jid, const u_int32_t num_enq,
+ const u_int32_t num_deq, const u_int32_t num_reads, const std::time_t secs, const long nsec)
+{
+ test_case_result::shared_ptr tcrp(new test_case_result(jid));
+ for (unsigned i=0; i<num_enq; i++)
+ tcrp->incr_num_enq();
+ for (unsigned i=0; i<num_deq; i++)
+ tcrp->incr_num_deq();
+ for (unsigned i=0; i<num_reads; i++)
+ tcrp->incr_num_read();
+ time_ns ts(secs, nsec);
+ tcrp->set_test_time(ts);
+ return tcrp;
+}
+
+// === Test suite ===
+
+QPID_AUTO_TEST_CASE(constructor_1)
+{
+ cout << test_filename << ".constructor_1: " << flush;
+ test_case_result_agregation tcra;
+ BOOST_CHECK_EQUAL(tcra.tc_average_mode(), true);
+ BOOST_CHECK_EQUAL(tcra.jid(), "Average");
+ BOOST_CHECK_EQUAL(tcra.exception(), false);
+ BOOST_CHECK_EQUAL(tcra.exception_count(), 0U);
+ const time_ns& ts1 = tcra.start_time();
+ BOOST_CHECK(ts1.is_zero());
+ const time_ns& ts2 = tcra.stop_time();
+ BOOST_CHECK(ts2.is_zero());
+ const time_ns& ts3 = tcra.test_time();
+ BOOST_CHECK(ts3.is_zero());
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_2)
+{
+ cout << test_filename << ".constructor_2: " << flush;
+ string jid("journal id");
+ test_case_result_agregation tcra(jid);
+ BOOST_CHECK_EQUAL(tcra.tc_average_mode(), false);
+ BOOST_CHECK_EQUAL(tcra.jid(), jid);
+ BOOST_CHECK_EQUAL(tcra.exception(), false);
+ BOOST_CHECK_EQUAL(tcra.exception_count(), 0U);
+ const time_ns& ts1 = tcra.start_time();
+ BOOST_CHECK(ts1.is_zero());
+ const time_ns& ts2 = tcra.stop_time();
+ BOOST_CHECK(ts2.is_zero());
+ const time_ns& ts3 = tcra.test_time();
+ BOOST_CHECK(ts3.is_zero());
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(add_test_case)
+{
+ cout << test_filename << ".add_test_case: " << flush;
+ string jid("jid1");
+ test_case_result::shared_ptr tcrp1 = make_result("jid1", 10, 10, 0, 1, 101010101L);
+ test_case_result::shared_ptr tcrp2 = make_result("jid1", 25, 0, 35, 10, 20202020L);
+ test_case_result::shared_ptr tcrp3 = make_result("jid1", 0, 15, 5, 2, 555555555L);
+ test_case_result::shared_ptr tcrp4 = make_result("jid2", 100, 100, 100, 100, 323232324L);
+ test_case_result::shared_ptr tcrp5 = make_result("jid1", 5, 0, 0, 0, 100L);
+ tcrp5->add_exception(string("error 1"), false);
+ test_case_result::shared_ptr tcrp6 = make_result("jid3", 0, 5, 0, 0, 100L);
+ jexception e(0x123, "exception 2");
+ tcrp6->add_exception(e, false);
+ test_case_result::shared_ptr tcrp7 = make_result("jid1", 0, 0, 0, 0, 0L);
+ test_case_result::shared_ptr tcrp8 = make_result("jid1", 200, 100, 300, 12, 323232224L);
+
+ test_case_result_agregation tcra(jid);
+ check_agregate(tcra, 0, 0, 0, 0, 0, 0, 0L);
+ tcra.add_test_result(tcrp1);
+ check_agregate(tcra, 10, 10, 0, 1, 0, 1, 101010101L);
+ tcra.add_test_result(tcrp2);
+ check_agregate(tcra, 35, 10, 35, 2, 0, 11, 121212121L);
+ tcra.add_test_result(tcrp3);
+ check_agregate(tcra, 35, 25, 40, 3, 0, 13, 676767676L);
+ tcra.add_test_result(tcrp4);
+ check_agregate(tcra, 35, 25, 40, 3, 0, 13, 676767676L);
+ tcra.add_test_result(tcrp5);
+ check_agregate(tcra, 40, 25, 40, 4, 1, 13, 676767776L);
+ tcra.add_test_result(tcrp6);
+ check_agregate(tcra, 40, 25, 40, 4, 1, 13, 676767776L);
+ tcra.add_test_result(tcrp7);
+ check_agregate(tcra, 40, 25, 40, 5, 1, 13, 676767776L);
+ tcra.add_test_result(tcrp8);
+ check_agregate(tcra, 240, 125, 340, 6, 1, 26, 0L);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(add_test_case_average)
+{
+ cout << test_filename << ".add_test_case_average: " << flush;
+ test_case_result::shared_ptr tcrp1 = make_result("jid1", 10, 10, 0, 1, 101010101L);
+ test_case_result::shared_ptr tcrp2 = make_result("jid2", 25, 0, 35, 10, 20202020L);
+ test_case_result::shared_ptr tcrp3 = make_result("jid3", 0, 15, 5, 2, 555555555L);
+ test_case_result::shared_ptr tcrp4 = make_result("jid4", 100, 100, 100, 100, 323232324L);
+ test_case_result::shared_ptr tcrp5 = make_result("jid5", 5, 0, 0, 0, 100L);
+ tcrp5->add_exception(string("error 1"), false);
+ test_case_result::shared_ptr tcrp6 = make_result("jid6", 0, 5, 0, 0, 100L);
+ jexception e(0x123, "exception 2");
+ tcrp6->add_exception(e, false);
+ test_case_result::shared_ptr tcrp7 = make_result("jid7", 0, 0, 0, 0, 0L);
+ test_case_result::shared_ptr tcrp8 = make_result("jid8", 200, 100, 300, 12, 222222022L);
+
+ test_case_result_agregation tcra;
+ check_agregate(tcra, 0, 0, 0, 0, 0, 0, 0L);
+ tcra.add_test_result(tcrp1);
+ check_agregate(tcra, 10, 10, 0, 1, 0, 1, 101010101L);
+ tcra.add_test_result(tcrp2);
+ check_agregate(tcra, 35, 10, 35, 2, 0, 11, 121212121L);
+ tcra.add_test_result(tcrp3);
+ check_agregate(tcra, 35, 25, 40, 3, 0, 13, 676767676L);
+ tcra.add_test_result(tcrp4);
+ check_agregate(tcra, 135, 125, 140, 4, 0, 114, 0L);
+ tcra.add_test_result(tcrp5);
+ check_agregate(tcra, 140, 125, 140, 5, 1, 114, 100L);
+ tcra.add_test_result(tcrp6);
+ check_agregate(tcra, 140, 130, 140, 6, 2, 114, 200L);
+ tcra.add_test_result(tcrp7);
+ check_agregate(tcra, 140, 130, 140, 7, 2, 114, 200L);
+ tcra.add_test_result(tcrp8);
+ check_agregate(tcra, 340, 230, 440, 8, 2, 126, 222222222L);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case_set.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case_set.cpp
new file mode 100644
index 0000000000..adbdf6884b
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case_set.cpp
@@ -0,0 +1,147 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../../unit_test.h"
+#include <cstddef>
+#include <iostream>
+#include <sys/stat.h>
+#include "test_case.h"
+#include "test_case_set.h"
+
+using namespace boost::unit_test;
+using namespace mrg::jtt;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(jtt_test_case_set)
+
+const string csv_file("_ut_test_case_set.csv");
+const string test_filename("_ut_test_case_set");
+
+// === Helper functions ===
+
+bool check_csv_file(const char* filename)
+{
+ struct stat s;
+ if (::stat(filename, &s))
+ return false;
+ if (S_ISREG(s.st_mode))
+ return true;
+ return false;
+}
+
+// === Test suite ===
+
+QPID_AUTO_TEST_CASE(constructor)
+{
+ cout << test_filename << ".constructor: " << flush;
+ test_case_set tcs;
+ BOOST_CHECK(tcs.empty());
+ BOOST_CHECK_EQUAL(tcs.size(), unsigned(0));
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(append_1)
+{
+ cout << test_filename << ".append_1: " << flush;
+ const unsigned test_case_num = 0x12345;
+ const u_int32_t num_msgs = 0x100;
+ const std::size_t min_data_size = 0x1000;
+ const std::size_t max_data_size = 0;
+ const bool auto_deq = true;
+ const std::size_t min_xid_size = 0x200;
+ const std::size_t max_xid_size = 0x200;
+ using mrg::jtt::test_case;
+ const test_case::transient_t transient = test_case::JTT_PERSISTNET;
+ const test_case::external_t external = test_case::JDL_INTERNAL;
+ const string comment = "This is a test";
+
+ test_case_set tcs;
+ tcs.append(test_case_num, num_msgs, min_data_size, max_data_size, auto_deq, min_xid_size,
+ max_xid_size, transient, external, comment);
+ BOOST_CHECK(!tcs.empty());
+ BOOST_CHECK_EQUAL(tcs.size(), unsigned(1));
+ test_case::shared_ptr tcp = tcs[0];
+ BOOST_CHECK_EQUAL(tcp->test_case_num(), test_case_num);
+ BOOST_CHECK_EQUAL(tcp->num_msgs(), num_msgs);
+ BOOST_CHECK_EQUAL(tcp->min_data_size(), min_data_size);
+ BOOST_CHECK_EQUAL(tcp->max_data_size(), max_data_size);
+ BOOST_CHECK_EQUAL(tcp->min_xid_size(), min_xid_size);
+ BOOST_CHECK_EQUAL(tcp->max_xid_size(), max_xid_size);
+ BOOST_CHECK_EQUAL(tcp->transient(), transient);
+ BOOST_CHECK_EQUAL(tcp->external(), external);
+ BOOST_CHECK_EQUAL(tcp->comment(), comment);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(append_2)
+{
+ cout << test_filename << ".append_2: " << flush;
+ const unsigned test_case_num = 0x12345;
+ const u_int32_t num_msgs = 0x100;
+ const std::size_t min_data_size = 0x1000;
+ const std::size_t max_data_size = 0;
+ const bool auto_deq = true;
+ const std::size_t min_xid_size = 0x200;
+ const std::size_t max_xid_size = 0x200;
+ using mrg::jtt::test_case;
+ const test_case::transient_t transient = test_case::JTT_PERSISTNET;
+ const test_case::external_t external = test_case::JDL_INTERNAL;
+ const string comment = "This is a test";
+
+ test_case::shared_ptr tcp(new test_case(test_case_num, num_msgs, min_data_size, max_data_size,
+ auto_deq, min_xid_size, max_xid_size, transient, external, comment));
+ test_case_set tcs;
+ tcs.append(tcp);
+ BOOST_CHECK(!tcs.empty());
+ BOOST_CHECK_EQUAL(tcs.size(), unsigned(1));
+ tcp = tcs[0];
+ BOOST_CHECK_EQUAL(tcp->test_case_num(), test_case_num);
+ BOOST_CHECK_EQUAL(tcp->num_msgs(), num_msgs);
+ BOOST_CHECK_EQUAL(tcp->min_data_size(), min_data_size);
+ BOOST_CHECK_EQUAL(tcp->max_data_size(), max_data_size);
+ BOOST_CHECK_EQUAL(tcp->min_xid_size(), min_xid_size);
+ BOOST_CHECK_EQUAL(tcp->max_xid_size(), max_xid_size);
+ BOOST_CHECK_EQUAL(tcp->transient(), transient);
+ BOOST_CHECK_EQUAL(tcp->external(), external);
+ BOOST_CHECK_EQUAL(tcp->comment(), comment);
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(append_from_csv)
+{
+ cout << test_filename << ".append_from_csv: " << flush;
+ test_case_set tcs;
+ BOOST_REQUIRE_MESSAGE(check_csv_file(csv_file.c_str()), "Test CSV file \"" << csv_file <<
+ "\" is missing.");
+ tcs.append_from_csv(csv_file, false);
+ BOOST_CHECK(!tcs.empty());
+ BOOST_CHECK_EQUAL(tcs.size(), unsigned(44));
+ BOOST_CHECK_EQUAL(tcs.ignored(), unsigned(0));
+ tcs.clear();
+ BOOST_CHECK(tcs.empty());
+ tcs.append_from_csv(csv_file, true);
+ BOOST_CHECK(!tcs.empty());
+ BOOST_CHECK_EQUAL(tcs.size(), unsigned(18));
+ BOOST_CHECK_EQUAL(tcs.ignored(), unsigned(26));
+ cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case_set.csv b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case_set.csv
new file mode 100644
index 0000000000..f886186275
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/_ut_test_case_set.csv
@@ -0,0 +1,74 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+,,,,,,,"Msg size",,"Xid size",,,,,"enq-size",,"deq-size",,"txn-size",,
+"Col. 0","1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20"
+"Test #","tf","pf","amn","mn incr","#msgs","ms incr","Min","Max","Min","Max","auto-deq","transient","extern","bytes","dblks","bytes","dblks","bytes","dblks","comment"
+,,,,,,,,,,,,,,,,,,,,
+"Initialize only",,,,,,,,,,,,,,,,,,,,
+0,"L",0,0,0,0,0,0,0,0,0,FALSE,FALSE,FALSE,44,1,0,0,0,0,"No messages - journal creation/initialization only"
+,,,,,,,,,,,,,,,,,,,,
+"Simple message combinations of persistent/deq transientueued/non-dequeued, transactional/non-transactional",,,,,,,,,,,,,,,,,,,,
+1,"L",1,1,0,1,0,10,10,0,0,FALSE,FALSE,FALSE,54,1,0,0,0,0,"1 * 10-byte message"
+2,"L",1,10,0,10,0,10,10,0,0,FALSE,FALSE,FALSE,54,1,0,0,0,0,"10 * 10-byte message"
+3,"L",1,1,0,1,0,10,10,0,0,FALSE,TRUE,FALSE,54,1,0,0,0,0,"1 * 10-byte message [transient]"
+4,"L",1,10,0,10,0,10,10,0,0,FALSE,TRUE,FALSE,54,1,0,0,0,0,"10 * 10-byte message [transient]"
+5,"L",1,1,0,1,0,10,10,10,10,FALSE,FALSE,FALSE,64,1,0,0,0,0,"1 * 10-byte message [txn]"
+6,"L",1,10,0,10,0,10,10,10,10,FALSE,FALSE,FALSE,64,1,0,0,0,0,"10 * 10-byte message [txn]"
+7,"L",1,1,0,1,0,10,10,10,10,FALSE,TRUE,FALSE,64,1,0,0,0,0,"1 * 10-byte message [txn transient]"
+8,"L",1,10,0,10,0,10,10,10,10,FALSE,TRUE,FALSE,64,1,0,0,0,0,"10 * 10-byte message [txn transient]"
+9,"L",1,1,0,1,0,10,10,0,0,TRUE,FALSE,FALSE,54,1,32,1,0,0,"1 * 10-byte message [deq]"
+10,"L",1,10,0,10,0,10,10,0,0,TRUE,FALSE,FALSE,54,1,32,1,0,0,"10 * 10-byte message [deq]"
+11,"L",1,1,0,1,0,10,10,0,0,TRUE,TRUE,FALSE,54,1,32,1,0,0,"1 * 10-byte message [deq transient]"
+12,"L",1,10,0,10,0,10,10,0,0,TRUE,TRUE,FALSE,54,1,32,1,0,0,"10 * 10-byte message [deq transient]"
+13,"L",1,1,0,1,0,10,10,10,10,TRUE,FALSE,FALSE,64,1,54,1,46,1,"1 * 10-byte message [deq txn]"
+14,"L",1,10,0,10,0,10,10,10,10,TRUE,FALSE,FALSE,64,1,54,1,46,1,"10 * 10-byte message [deq txn]"
+15,"L",1,1,0,1,0,10,10,10,10,TRUE,TRUE,FALSE,64,1,54,1,46,1,"1 * 10-byte message [txn deq transient]"
+16,"L",1,10,0,10,0,10,10,10,10,TRUE,TRUE,FALSE,64,1,54,1,46,1,"10 * 10-byte message [txn deq transient]"
+17,"L",1,1,0,1,0,10,10,0,0,FALSE,FALSE,TRUE,54,1,0,0,0,0,"1 * 10-byte message [extern]"
+18,"L",1,10,0,10,0,10,10,0,0,FALSE,FALSE,TRUE,54,1,0,0,0,0,"10 * 10-byte message [extern]"
+19,"L",1,1,0,1,0,10,10,0,0,FALSE,TRUE,TRUE,54,1,0,0,0,0,"1 * 10-byte message [transient extern]"
+20,"L",1,10,0,10,0,10,10,0,0,FALSE,TRUE,TRUE,54,1,0,0,0,0,"10 * 10-byte message [transient extern]"
+21,"L",1,1,0,1,0,10,10,10,10,FALSE,FALSE,TRUE,64,1,0,0,0,0,"1 * 10-byte message [txn extern]"
+22,"L",1,10,0,10,0,10,10,10,10,FALSE,FALSE,TRUE,64,1,0,0,0,0,"10 * 10-byte message [txn extern]"
+23,"L",1,1,0,1,0,10,10,10,10,FALSE,TRUE,TRUE,64,1,0,0,0,0,"1 * 10-byte message [txn transient extern]"
+24,"L",1,10,0,10,0,10,10,10,10,FALSE,TRUE,TRUE,64,1,0,0,0,0,"10 * 10-byte message [txn transient extern]"
+25,"L",1,1,0,1,0,10,10,0,0,TRUE,FALSE,TRUE,54,1,32,1,0,0,"1 * 10-byte message [deq extern]"
+26,"L",1,10,0,10,0,10,10,0,0,TRUE,FALSE,TRUE,54,1,32,1,0,0,"10 * 10-byte message [deq extern]"
+27,"L",1,1,0,1,0,10,10,0,0,TRUE,TRUE,TRUE,54,1,32,1,0,0,"1 * 10-byte message [deq transient extern]"
+28,"L",1,10,0,10,0,10,10,0,0,TRUE,TRUE,TRUE,54,1,32,1,0,0,"10 * 10-byte message [deq transient extern]"
+29,"L",1,1,0,1,0,10,10,10,10,TRUE,FALSE,TRUE,64,1,54,1,46,1,"1 * 10-byte message [deq txn extern]"
+30,"L",1,10,0,10,0,10,10,10,10,TRUE,FALSE,TRUE,64,1,54,1,46,1,"10 * 10-byte message [deq txn extern]"
+31,"L",1,1,0,1,0,10,10,10,10,TRUE,TRUE,TRUE,64,1,54,1,46,1,"1 * 10-byte message [txn deq transient extern]"
+32,"L",1,10,0,10,0,10,10,10,10,TRUE,TRUE,TRUE,64,1,54,1,46,1,"10 * 10-byte message [txn deq transient extern]"
+,,,,,,,,,,,,,,,,,,,,
+"High volume tests of random message lengths - RHM_WRONLY req'd for auto-dequeue == FALSE",,,,,,,,,,,,,,,,,,,,
+33,"M",1,5000000,0,5000000,0,0,100,1,100,FALSE,RANDOM,RANDOM,244,2,0,0,0,0,"100 bytes xid max + 100 bytes data max [txn]"
+34,"M",3,3000000,0,3000000,0,0,300,1,300,FALSE,RANDOM,RANDOM,644,6,0,0,0,0,"300 bytes xid max + 300 bytes data max [txn]"
+35,"M",10,1600000,0,1600000,0,0,1000,1,1000,FALSE,RANDOM,RANDOM,2044,16,0,0,0,0,"1000 bytes xid max + 1000 bytes data max [txn]"
+36,"M",30,600000,0,600000,0,0,3000,1,3000,FALSE,RANDOM,RANDOM,6044,48,0,0,0,0,"3000 bytes xid max + 3000 bytes data max [txn]"
+37,"M",100,200000,0,200000,0,0,10000,1,10000,FALSE,RANDOM,RANDOM,20044,157,0,0,0,0,"10000 bytes xid max + 10000 bytes data max [txn]"
+38,"M",300,60000,0,60000,0,0,30000,1,30000,FALSE,RANDOM,RANDOM,60044,470,0,0,0,0,"30000 bytes xid max + 30000 bytes data max [txn]"
+39,"M",1000,20000,0,20000,0,0,100000,1,100000,FALSE,RANDOM,RANDOM,200044,1563,0,0,0,0,"100000 bytes xid max + 100000 bytes data max [txn]"
+,,,,,,,,,,,,,,,,,,,,
+"STANDARD PERFORMANCE BENCHMARK: 10,000,000 writes, data=212b (2 dblks)",,,,,,,,,,,,,,,,,,,,
+40,"M",1,10000000,0,10000000,0,212,212,0,0,FALSE,FALSE,FALSE,256,2,0,0,0,0,"212 bytes data (2 dblks enq)"
+41,"M",1,10000000,0,10000000,0,148,148,64,64,FALSE,FALSE,FALSE,256,2,0,0,0,0,"148 bytes data + 64 bytes xid (2 dblks enq)"
+42,"M",1,10000000,0,10000000,0,212,212,0,0,TRUE,FALSE,FALSE,256,2,32,1,0,0,"212 bytes data (2 dblks enq + 1 dblk deq)"
+43,"M",1,10000000,0,10000000,0,148,148,64,64,TRUE,FALSE,FALSE,256,2,108,1,100,1,"148 bytes data + 64 bytes xid (2 dblks enq + 1 dblks deq + 1 dblks txn)"
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/args.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/args.cpp
new file mode 100644
index 0000000000..0f041c380e
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/args.cpp
@@ -0,0 +1,226 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "args.h"
+
+#include <cstddef>
+#include <iostream>
+
+namespace po = boost::program_options;
+
+namespace mrg
+{
+namespace jtt
+{
+
+args::args(std::string opt_title):
+ _options_descr(opt_title),
+ format_chk(false),
+ keep_jrnls(false),
+ lld_rd_num(10),
+ lld_skip_num(100),
+ num_jrnls(1),
+ pause_secs(0),
+ randomize(false),
+ read_mode(),
+ read_prob(50),
+ recover_mode(false),
+ repeat_flag(false),
+ reuse_instance(false),
+ seed(0)
+{
+ _options_descr.add_options()
+ ("csv-file,c",
+ po::value<std::string>(&test_case_csv_file_name)->default_value("jtt.csv"),
+ "CSV file containing test cases.")
+
+ ("format-chk",
+ po::value<bool>(&format_chk)->zero_tokens(),
+ "Check the format of each journal file.")
+
+ ("help,h", "This help message.")
+
+ ("jrnl-dir",
+ po::value<std::string>(&journal_dir)->default_value("/var/tmp/jtt"),
+ "Directory in which journal files will be placed.")
+
+ ("keep-jrnls",
+ po::value<bool>(&keep_jrnls)->zero_tokens(),
+ "Keep all test journals.")
+
+ ("lld-rd-num",
+ po::value<unsigned>(&lld_rd_num)->default_value(10),
+ "Number of consecutive messages to read after only dequeueing lld-skip-num "
+ "messages during lazy-loading. Ignored if read-mode is not set to LAZYLOAD.")
+
+ ("lld-skip-num",
+ po::value<unsigned>(&lld_skip_num)->default_value(100),
+ "Number of consecutive messages to dequeue only (without reading) prior to "
+ "reading lld-rd-num messages. Ignored if read-mode is not set to LAZYLOAD.")
+
+ ("num-jrnls",
+ po::value<unsigned>(&num_jrnls)->default_value(1),
+ "Number of simultaneous journal instances to test.")
+
+ ("pause",
+ po::value<unsigned>(&pause_secs)->default_value(0),
+ "Pause in seconds between test cases (allows disk to catch up).")
+
+ ("randomize",
+ po::value<bool>(&randomize)->zero_tokens(),
+ "Randomize the order of the tests.")
+
+ ("read-mode",
+ po::value<read_arg>(&read_mode)->default_value(read_arg::NONE),
+ read_arg::descr().c_str())
+
+ ("read-prob",
+ po::value<unsigned>(&read_prob)->default_value(50),
+ "Read probability (percent) for each message when read-mode is set to RANDOM.")
+
+ ("recover-mode",
+ po::value<bool>(&recover_mode)->zero_tokens(),
+ "Recover journal from the previous test for each test case.")
+
+ ("repeat",
+ po::value<bool>(&repeat_flag)->zero_tokens(),
+ "Repeat all test cases indefinitely.")
+
+ ("reuse-instance",
+ po::value<bool>(&reuse_instance)->zero_tokens(),
+ "Reuse journal instance for all test cases.")
+
+ ("seed",
+ po::value<unsigned>(&seed)->default_value(0),
+ "Seed for use in random number generator.")
+
+ ("analyzer",
+ po::value<std::string>(&jfile_analyzer)->default_value("./file_chk.py"),
+ "Journal file analyzer program to use when the --format-chk option is used, ignored otherwise.")
+
+ ;
+}
+
+bool
+args::parse(int argc, char** argv) // return true if error, false if ok
+{
+ try
+ {
+ po::store(po::parse_command_line(argc, argv, _options_descr), _vmap);
+ po::notify(_vmap);
+ }
+ catch (const std::exception& e)
+ {
+ std::cout << "ERROR: " << e.what() << std::endl;
+ return usage();
+ }
+ if (_vmap.count("help"))
+ return usage();
+ if (num_jrnls == 0)
+ {
+ std::cout << "ERROR: num-jrnls must be 1 or more." << std::endl;
+ return usage();
+ }
+ if (read_prob > 100) // read_prob is unsigned, so no need to check < 0
+ {
+ std::cout << "ERROR: read-prob must be between 0 and 100 inclusive." << std::endl;
+ return usage();
+ }
+ if (repeat_flag && keep_jrnls)
+ {
+ std::string resp;
+ std::cout << "WARNING: repeat and keep-jrnls: Monitor disk usage as test journals will"
+ " accumulate." << std::endl;
+ std::cout << "Continue? <y/n> ";
+ std::cin >> resp;
+ if (resp.size() == 1)
+ {
+ if (resp[0] != 'y' && resp[0] != 'Y')
+ return true;
+ }
+ else if (resp.size() == 3) // any combo of lower- and upper-case
+ {
+ if (resp[0] != 'y' && resp[0] != 'Y')
+ return true;
+ if (resp[1] != 'e' && resp[1] != 'E')
+ return true;
+ if (resp[2] != 's' && resp[2] != 'S')
+ return true;
+ }
+ else
+ return true;
+ }
+ return false;
+}
+
+bool
+args::usage() const
+{
+ std::cout << _options_descr << std::endl;
+ return true;
+}
+
+void
+args::print_args() const
+{
+ std::cout << "Number of journals: " << num_jrnls << std::endl;
+ std::cout << "Read mode: " << read_mode << std::endl;
+ if (read_mode.val() == read_arg::RANDOM)
+ std::cout << "Read probability: " << read_prob << " %" << std::endl;
+ if (read_mode.val() == read_arg::LAZYLOAD)
+ {
+ std::cout << "Lazy-load skips: " << lld_skip_num << std::endl;
+ std::cout << "Lazy-load reads: " << lld_rd_num << std::endl;
+ }
+ if (pause_secs)
+ std::cout << "Pause between test cases: " << pause_secs << " sec." << std::endl;
+ if (seed)
+ std::cout << "Randomize seed: " << seed << std::endl;
+ print_flags();
+}
+
+void
+args::print_flags() const
+{
+ if (format_chk || keep_jrnls || randomize || recover_mode || repeat_flag ||
+ reuse_instance)
+ {
+ std::cout << "Flag options:";
+ // TODO: Get flag args and their strings directly from _options_descr.
+ if (format_chk)
+ std::cout << " format-chk";
+ if (keep_jrnls)
+ std::cout << " keep-jrnls";
+ if (randomize)
+ std::cout << " randomize";
+ if (recover_mode)
+ std::cout << " recover-mode";
+ if (repeat_flag)
+ std::cout << " repeat-flag";
+ if (reuse_instance)
+ std::cout << " reuse-instance";
+ std::cout << std::endl;
+ }
+ std::cout << std::endl;
+}
+
+} // namespace jtt
+} // namespace mrg
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/args.h b/qpid/cpp/src/tests/legacystore/jrnl/jtt/args.h
new file mode 100644
index 0000000000..b6f7fb4a79
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/args.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef mrg_jtt_args_hpp
+#define mrg_jtt_args_hpp
+
+#include <boost/program_options.hpp>
+#include "read_arg.h"
+
+namespace mrg
+{
+namespace jtt
+{
+
+ struct args
+ {
+ boost::program_options::options_description _options_descr;
+ boost::program_options::variables_map _vmap;
+
+ // Add args here
+ std::string jfile_analyzer;
+ std::string test_case_csv_file_name;
+ std::string journal_dir;
+ bool format_chk;
+ bool keep_jrnls;
+ unsigned lld_rd_num;
+ unsigned lld_skip_num;
+ unsigned num_jrnls;
+ unsigned pause_secs;
+ bool randomize;
+ read_arg read_mode;
+ unsigned read_prob;
+ bool recover_mode;
+ bool repeat_flag;
+ bool reuse_instance;
+ unsigned seed;
+
+ args(std::string opt_title);
+ bool parse(int argc, char** argv); // return true if error, false if ok
+ bool usage() const; // return true
+ void print_args() const;
+ void print_flags() const;
+ };
+
+} // namespace jtt
+} // namespace mrg
+
+#endif // ifndef mrg_jtt_args_hpp
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/data_src.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/data_src.cpp
new file mode 100644
index 0000000000..3530e0b223
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/data_src.cpp
@@ -0,0 +1,87 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "data_src.h"
+
+#include <cstddef>
+#include <iomanip>
+#include <sstream>
+
+namespace mrg
+{
+namespace jtt
+{
+
+char data_src::_data_src[data_src::max_dsize];
+char data_src::_xid_src[data_src::max_xsize];
+bool data_src::_initialized = data_src::__init();
+u_int64_t data_src::_xid_cnt = 0ULL;
+mrg::journal::smutex data_src::_sm;
+
+data_src::data_src()
+{}
+
+bool
+data_src::__init()
+{
+ for (unsigned i=0; i<max_dsize; i++)
+ _data_src[i] = '0' + ((i + 1) % 10); // 123456789012345...
+ for (unsigned j=0; j<max_xsize; j++)
+ _xid_src[j] = 'a' + (j % 26); // abc...xyzabc...
+ return true;
+}
+
+const char*
+data_src::get_data(const std::size_t offs)
+{
+ if (offs >= max_dsize) return 0;
+ return _data_src + offs;
+}
+
+std::string
+data_src::get_xid(const std::size_t xid_size)
+{
+ if (xid_size == 0)
+ return "";
+ std::ostringstream oss;
+ oss << std::setfill('0');
+ if (xid_size < 9)
+ oss << std::setw(xid_size) << get_xid_cnt();
+ else if (xid_size < 13)
+ oss << "xid:" << std::setw(xid_size - 4) << get_xid_cnt();
+ else
+ {
+ oss << "xid:" << std::setw(8) << get_xid_cnt() << ":";
+ oss.write(get_xid_content(13), xid_size - 13);
+ }
+ return oss.str();
+}
+
+const char*
+data_src::get_xid_content(const std::size_t offs)
+{
+ if (offs >= max_xsize) return 0;
+ return _xid_src + offs;
+}
+
+} // namespace jtt
+} // namespace mrg
+
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/data_src.h b/qpid/cpp/src/tests/legacystore/jrnl/jtt/data_src.h
new file mode 100644
index 0000000000..66dc613787
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/data_src.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef mrg_jtt_data_src_hpp
+#define mrg_jtt_data_src_hpp
+
+#include <cstddef>
+#include "qpid/legacystore/jrnl/slock.h"
+#include "qpid/legacystore/jrnl/smutex.h"
+#include <pthread.h>
+#include <string>
+#include <sys/types.h>
+
+#define DATA_SIZE 1024 * 1024
+#define XID_SIZE 1024 * 1024
+
+namespace mrg
+{
+namespace jtt
+{
+ class data_src
+ {
+ public:
+ static const std::size_t max_dsize = DATA_SIZE;
+ static const std::size_t max_xsize = XID_SIZE;
+
+ private:
+ static char _data_src[];
+ static char _xid_src[];
+ static u_int64_t _xid_cnt;
+ static bool _initialized;
+ static mrg::journal::smutex _sm;
+
+ public:
+ static const char* get_data(const std::size_t offs);
+ static std::string get_xid(const std::size_t xid_size);
+
+ private:
+ data_src();
+ static u_int64_t get_xid_cnt() { mrg::journal::slock s(_sm); return _xid_cnt++; }
+ static const char* get_xid_content(const std::size_t offs);
+ static bool __init();
+ };
+
+} // namespace jtt
+} // namespace mrg
+
+#endif // ifndef mrg_jtt_data_src_hpp
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/jfile_chk.py b/qpid/cpp/src/tests/legacystore/jrnl/jtt/jfile_chk.py
new file mode 100755
index 0000000000..36ef511f5c
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/jfile_chk.py
@@ -0,0 +1,838 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import sys
+import getopt
+import string
+import xml.parsers.expat
+from struct import unpack, calcsize
+from time import gmtime, strftime
+
+dblk_size = 128
+sblk_size = 4 * dblk_size
+jfsize = None
+hdr_ver = 1
+
+TEST_NUM_COL = 0
+NUM_MSGS_COL = 5
+MIN_MSG_SIZE_COL = 7
+MAX_MSG_SIZE_COL = 8
+MIN_XID_SIZE_COL = 9
+MAX_XID_SIZE_COL = 10
+AUTO_DEQ_COL = 11
+TRANSIENT_COL = 12
+EXTERN_COL = 13
+COMMENT_COL = 20
+
+owi_mask = 0x01
+transient_mask = 0x10
+extern_mask = 0x20
+
+printchars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ '
+
+
+
+#== global functions ===========================================================
+
+def load(f, klass):
+ args = load_args(f, klass)
+ subclass = klass.discriminate(args)
+ result = subclass(*args)
+ if subclass != klass:
+ result.init(f, *load_args(f, subclass))
+ result.skip(f)
+ return result;
+
+def load_args(f, klass):
+ size = calcsize(klass.format)
+ foffs = f.tell(),
+ bin = f.read(size)
+ if len(bin) != size:
+ raise Exception("end of file")
+ return foffs + unpack(klass.format, bin)
+
+def size_blks(size, blk_size):
+ return (size + blk_size - 1)/blk_size
+
+def rem_in_blk(f, blk_size):
+ foffs = f.tell()
+ return (size_blks(f.tell(), blk_size) * blk_size) - foffs;
+
+def file_full(f):
+ return f.tell() >= jfsize
+
+def isprintable(s):
+ return s.strip(printchars) == ''
+
+def print_xid(xidsize, xid):
+ if xid == None:
+ if xidsize > 0:
+ raise Exception('Inconsistent XID size: xidsize=%d, xid=None' % xidsize)
+ return ''
+ if isprintable(xid):
+ xidstr = split_str(xid)
+ else:
+ xidstr = hex_split_str(xid)
+ if xidsize != len(xid):
+ raise Exception('Inconsistent XID size: xidsize=%d, xid(%d)=\"%s\"' % (xidsize, len(xid), xidstr))
+ return 'xid(%d)=\"%s\" ' % (xidsize, xidstr)
+
+def print_data(dsize, data):
+ if data == None:
+ return ''
+ if isprintable(data):
+ datastr = split_str(data)
+ else:
+ datastr = hex_split_str(data)
+ if dsize != len(data):
+ raise Exception('Inconsistent data size: dsize=%d, data(%d)=\"%s\"' % (dsize, len(data), datastr))
+ return 'data(%d)=\"%s\" ' % (dsize, datastr)
+
+def hex_split_str(s, split_size = 50):
+ if len(s) <= split_size:
+ return hex_str(s, 0, len(s))
+ if len(s) > split_size + 25:
+ return hex_str(s, 0, 10) + ' ... ' + hex_str(s, 55, 65) + ' ... ' + hex_str(s, len(s)-10, len(s))
+ return hex_str(s, 0, 10) + ' ... ' + hex_str(s, len(s)-10, len(s))
+
+def hex_str(s, b, e):
+ o = ''
+ for i in range(b, e):
+ if isprintable(s[i]):
+ o += s[i]
+ else:
+ o += '\\%02x' % ord(s[i])
+ return o
+
+def split_str(s, split_size = 50):
+ if len(s) < split_size:
+ return s
+ return s[:25] + ' ... ' + s[-25:]
+
+def inv_str(s):
+ si = ''
+ for i in range(0,len(s)):
+ si += chr(~ord(s[i]) & 0xff)
+ return si
+
+def load_file_data(f, size, data):
+ if size == 0:
+ return (data, True)
+ if data == None:
+ loaded = 0
+ else:
+ loaded = len(data)
+ foverflow = f.tell() + size - loaded > jfsize
+ if foverflow:
+ rsize = jfsize - f.tell()
+ else:
+ rsize = size - loaded
+ bin = f.read(rsize)
+ if data == None:
+ data = unpack('%ds' % (rsize), bin)[0]
+ else:
+ data = data + unpack('%ds' % (rsize), bin)[0]
+ return (data, not foverflow)
+
+def exit(code, qflag):
+ if code != 0 or not qflag:
+ print out.getvalue()
+ out.close()
+ sys.exit(code)
+
+#== class Sizeable =============================================================
+
+class Sizeable:
+
+ def size(self):
+ classes = [self.__class__]
+
+ size = 0
+ while classes:
+ cls = classes.pop()
+ if hasattr(cls, "format"):
+ size += calcsize(cls.format)
+ classes.extend(cls.__bases__)
+
+ return size
+
+
+#== class Hdr ==================================================================
+
+class Hdr(Sizeable):
+
+ format = '=4sBBHQ'
+
+ def discriminate(args):
+ return CLASSES.get(args[1][-1], Hdr)
+ discriminate = staticmethod(discriminate)
+
+ def __init__(self, foffs, magic, ver, end, flags, rid):
+ self.foffs = foffs
+ self.magic = magic
+ self.ver = ver
+ self.end = end
+ self.flags = flags
+ self.rid = rid
+ if self.magic[-1] not in ['0x00', 'a', 'c', 'd', 'e', 'f', 'x']:
+ error = 3
+
+ def __str__(self):
+ if self.empty():
+ return '0x%08x: <empty>' % (self.foffs)
+ if self.magic[-1] == 'x':
+ return '0x%08x: [\"%s\"]' % (self.foffs, self.magic)
+ if self.magic[-1] in ['a', 'c', 'd', 'e', 'f', 'x']:
+ return '0x%08x: [\"%s\" v=%d e=%d f=0x%04x rid=0x%x]' % (self.foffs, self.magic, self.ver, self.end, self.flags, self.rid)
+ return '0x%08x: <error, unknown magic \"%s\" (possible overwrite boundary?)>' % (self.foffs, self.magic)
+
+ def empty(self):
+ return self.magic == '\x00'*4
+
+ def owi(self):
+ return self.flags & owi_mask != 0
+
+ def skip(self, f):
+ f.read(rem_in_blk(f, dblk_size))
+
+ def check(self):
+ if self.empty() or self.magic[:3] != 'RHM' or self.magic[3] not in ['a', 'c', 'd', 'e', 'f', 'x']:
+ return True
+ if self.ver != hdr_ver and self.magic[-1] != 'x':
+ raise Exception('%s: Invalid header version: found %d, expected %d.' % (self, self.ver, hdr_ver))
+ return False
+
+
+#== class FileHdr ==============================================================
+
+class FileHdr(Hdr):
+
+ format = '=2H4x3Q'
+
+ def init(self, f, foffs, fid, lid, fro, time_sec, time_ns):
+ self.fid = fid
+ self.lid = lid
+ self.fro = fro
+ self.time_sec = time_sec
+ self.time_ns = time_ns
+
+ def __str__(self):
+ return '%s fid=%d lid=%d fro=0x%08x t=%s' % (Hdr.__str__(self), self.fid, self.lid, self.fro, self.timestamp_str())
+
+ def skip(self, f):
+ f.read(rem_in_blk(f, sblk_size))
+
+ def timestamp(self):
+ return (self.time_sec, self.time_ns)
+
+ def timestamp_str(self):
+ ts = gmtime(self.time_sec)
+ fstr = '%%a %%b %%d %%H:%%M:%%S.%09d %%Y' % (self.time_ns)
+ return strftime(fstr, ts)
+
+
+#== class DeqHdr ===============================================================
+
+class DeqHdr(Hdr):
+
+ format = '=QQ'
+
+ def init(self, f, foffs, deq_rid, xidsize):
+ self.deq_rid = deq_rid
+ self.xidsize = xidsize
+ self.xid = None
+ self.deq_tail = None
+ self.xid_complete = False
+ self.tail_complete = False
+ self.tail_bin = None
+ self.tail_offs = 0
+ self.load(f)
+
+ def load(self, f):
+ if self.xidsize == 0:
+ self.xid_complete = True
+ self.tail_complete = True
+ else:
+ if not self.xid_complete:
+ ret = load_file_data(f, self.xidsize, self.xid)
+ self.xid = ret[0]
+ self.xid_complete = ret[1]
+ if self.xid_complete and not self.tail_complete:
+ ret = load_file_data(f, calcsize(RecTail.format), self.tail_bin)
+ self.tail_bin = ret[0]
+ if ret[1]:
+ self.enq_tail = RecTail(self.tail_offs, *unpack(RecTail.format, self.tail_bin))
+ if self.enq_tail.magic_inv != inv_str(self.magic) or self.enq_tail.rid != self.rid:
+ print " > %s" % self
+ raise Exception('Invalid dequeue record tail (magic=%s; rid=%d) at 0x%08x' % (self.enq_tail, self.enq_tail.rid, self.enq_tail.foffs))
+ self.enq_tail.skip(f)
+ self.tail_complete = ret[1]
+ return self.complete()
+
+ def complete(self):
+ return self.xid_complete and self.tail_complete
+
+ def __str__(self):
+ return '%s %sdrid=0x%x' % (Hdr.__str__(self), print_xid(self.xidsize, self.xid), self.deq_rid)
+
+
+#== class TxnHdr ===============================================================
+
+class TxnHdr(Hdr):
+
+ format = '=Q'
+
+ def init(self, f, foffs, xidsize):
+ self.xidsize = xidsize
+ self.xid = None
+ self.tx_tail = None
+ self.xid_complete = False
+ self.tail_complete = False
+ self.tail_bin = None
+ self.tail_offs = 0
+ self.load(f)
+
+ def load(self, f):
+ if not self.xid_complete:
+ ret = load_file_data(f, self.xidsize, self.xid)
+ self.xid = ret[0]
+ self.xid_complete = ret[1]
+ if self.xid_complete and not self.tail_complete:
+ ret = load_file_data(f, calcsize(RecTail.format), self.tail_bin)
+ self.tail_bin = ret[0]
+ if ret[1]:
+ self.enq_tail = RecTail(self.tail_offs, *unpack(RecTail.format, self.tail_bin))
+ if self.enq_tail.magic_inv != inv_str(self.magic) or self.enq_tail.rid != self.rid:
+ print " > %s" % self
+ raise Exception('Invalid transaction record tail (magic=%s; rid=%d) at 0x%08x' % (self.enq_tail, self.enq_tail.rid, self.enq_tail.foffs))
+ self.enq_tail.skip(f)
+ self.tail_complete = ret[1]
+ return self.complete()
+
+ def complete(self):
+ return self.xid_complete and self.tail_complete
+
+ def __str__(self):
+ return '%s %s' % (Hdr.__str__(self), print_xid(self.xidsize, self.xid))
+
+
+#== class RecTail ==============================================================
+
+class RecTail(Sizeable):
+
+ format = '=4sQ'
+
+ def __init__(self, foffs, magic_inv, rid):
+ self.foffs = foffs
+ self.magic_inv = magic_inv
+ self.rid = rid
+
+ def __str__(self):
+ magic = inv_str(self.magic_inv)
+ return '[\"%s\" rid=0x%x]' % (magic, self.rid)
+
+ def skip(self, f):
+ f.read(rem_in_blk(f, dblk_size))
+
+
+#== class EnqRec ===============================================================
+
+class EnqRec(Hdr):
+
+ format = '=QQ'
+
+ def init(self, f, foffs, xidsize, dsize):
+ self.xidsize = xidsize
+ self.dsize = dsize
+ self.transient = self.flags & transient_mask > 0
+ self.extern = self.flags & extern_mask > 0
+ self.xid = None
+ self.data = None
+ self.enq_tail = None
+ self.xid_complete = False
+ self.data_complete = False
+ self.tail_complete = False
+ self.tail_bin = None
+ self.tail_offs = 0
+ self.load(f)
+
+ def load(self, f):
+ if not self.xid_complete:
+ ret = load_file_data(f, self.xidsize, self.xid)
+ self.xid = ret[0]
+ self.xid_complete = ret[1]
+ if self.xid_complete and not self.data_complete:
+ if self.extern:
+ self.data_complete = True
+ else:
+ ret = load_file_data(f, self.dsize, self.data)
+ self.data = ret[0]
+ self.data_complete = ret[1]
+ if self.data_complete and not self.tail_complete:
+ ret = load_file_data(f, calcsize(RecTail.format), self.tail_bin)
+ self.tail_bin = ret[0]
+ if ret[1]:
+ self.enq_tail = RecTail(self.tail_offs, *unpack(RecTail.format, self.tail_bin))
+ if self.enq_tail.magic_inv != inv_str(self.magic) or self.enq_tail.rid != self.rid:
+ print " > %s" % self
+ raise Exception('Invalid enqueue record tail (magic=%s; rid=%d) at 0x%08x' % (self.enq_tail, self.enq_tail.rid, self.enq_tail.foffs))
+ self.enq_tail.skip(f)
+ self.tail_complete = ret[1]
+ return self.complete()
+
+ def complete(self):
+ return self.xid_complete and self.data_complete and self.tail_complete
+
+ def print_flags(self):
+ s = ''
+ if self.transient:
+ s = '*TRANSIENT'
+ if self.extern:
+ if len(s) > 0:
+ s += ',EXTERNAL'
+ else:
+ s = '*EXTERNAL'
+ if len(s) > 0:
+ s += '*'
+ return s
+
+ def __str__(self):
+ return '%s %s%s %s %s' % (Hdr.__str__(self), print_xid(self.xidsize, self.xid), print_data(self.dsize, self.data), self.enq_tail, self.print_flags())
+
+
+#== class Main =================================================================
+
+class Main:
+ def __init__(self, argv):
+ self.bfn = None
+ self.csvfn = None
+ self.jdir = None
+ self.aflag = False
+ self.hflag = False
+ self.qflag = False
+ self.tnum = None
+ self.num_jfiles = None
+ self.num_msgs = None
+ self.msg_len = None
+ self.auto_deq = None
+ self.xid_len = None
+ self.transient = None
+ self.extern = None
+
+ self.file_start = 0
+ self.file_num = 0
+ self.fro = 0x200
+ self.emap = {}
+ self.tmap = {}
+ self.rec_cnt = 0
+ self.msg_cnt = 0
+ self.txn_msg_cnt = 0
+ self.fhdr = None
+ self.f = None
+ self.first_rec = False
+ self.last_file = False
+ self.last_rid = -1
+ self.fhdr_owi_at_msg_start = None
+
+ self.proc_args(argv)
+ self.proc_csv()
+ self.read_jinf()
+
+ def run(self):
+ try:
+ start_info = self.analyze_files()
+ stop = self.advance_file(*start_info)
+ except Exception:
+ print 'WARNING: All journal files are empty.'
+ if self.num_msgs > 0:
+ raise Exception('All journal files are empty, but %d msgs expectd.' % self.num_msgs)
+ else:
+ stop = True
+ while not stop:
+ warn = ''
+ if file_full(self.f):
+ stop = self.advance_file()
+ if stop:
+ break
+ hdr = load(self.f, Hdr)
+ if hdr.empty():
+ stop = True;
+ break
+ if hdr.check():
+ stop = True;
+ else:
+ self.rec_cnt += 1
+ self.fhdr_owi_at_msg_start = self.fhdr.owi()
+ if self.first_rec:
+ if self.fhdr.fro != hdr.foffs:
+ raise Exception('File header first record offset mismatch: fro=0x%08x; rec_offs=0x%08x' % (self.fhdr.fro, hdr.foffs))
+ else:
+ if not self.qflag: print ' * fro ok: 0x%08x' % self.fhdr.fro
+ self.first_rec = False
+ if isinstance(hdr, EnqRec) and not stop:
+ while not hdr.complete():
+ stop = self.advance_file()
+ if stop:
+ break
+ hdr.load(self.f)
+ if self.extern != None:
+ if hdr.extern:
+ if hdr.data != None:
+ raise Exception('Message data found on external record')
+ else:
+ if self.msg_len > 0 and len(hdr.data) != self.msg_len:
+ raise Exception('Message length (%d) incorrect; expected %d' % (len(hdr.data), self.msg_len))
+ else:
+ if self.msg_len > 0 and len(hdr.data) != self.msg_len:
+ raise Exception('Message length (%d) incorrect; expected %d' % (len(hdr.data), self.msg_len))
+ if self.xid_len > 0 and len(hdr.xid) != self.xid_len:
+ print ' ERROR: XID length (%d) incorrect; expected %d' % (len(hdr.xid), self.xid_len)
+ sys.exit(1)
+ #raise Exception('XID length (%d) incorrect; expected %d' % (len(hdr.xid), self.xid_len))
+ if self.transient != None:
+ if self.transient:
+ if not hdr.transient:
+ raise Exception('Expected transient record, found persistent')
+ else:
+ if hdr.transient:
+ raise Exception('Expected persistent record, found transient')
+ stop = not self.check_owi(hdr)
+ if stop:
+ warn = ' (WARNING: OWI mismatch - could be overwrite boundary.)'
+ else:
+ self.msg_cnt += 1
+ if self.aflag or self.auto_deq:
+ if hdr.xid == None:
+ self.emap[hdr.rid] = (self.fhdr.fid, hdr, False)
+ else:
+ self.txn_msg_cnt += 1
+ if hdr.xid in self.tmap:
+ self.tmap[hdr.xid].append((self.fhdr.fid, hdr)) #Append tuple to existing list
+ else:
+ self.tmap[hdr.xid] = [(self.fhdr.fid, hdr)] # Create new list
+ elif isinstance(hdr, DeqHdr) and not stop:
+ while not hdr.complete():
+ stop = self.advance_file()
+ if stop:
+ break
+ hdr.load(self.f)
+ stop = not self.check_owi(hdr)
+ if stop:
+ warn = ' (WARNING: OWI mismatch - could be overwrite boundary.)'
+ else:
+ if self.auto_deq != None:
+ if not self.auto_deq:
+ warn = ' WARNING: Dequeue record rid=%d found in non-dequeue test - ignoring.' % hdr.rid
+ if self.aflag or self.auto_deq:
+ if hdr.xid == None:
+ if hdr.deq_rid in self.emap:
+ if self.emap[hdr.deq_rid][2]:
+ warn = ' (WARNING: dequeue rid 0x%x dequeues locked enqueue record 0x%x)' % (hdr.rid, hdr.deq_rid)
+ del self.emap[hdr.deq_rid]
+ else:
+ warn = ' (WARNING: rid being dequeued 0x%x not found in enqueued records)' % hdr.deq_rid
+ else:
+ if hdr.deq_rid in self.emap:
+ t = self.emap[hdr.deq_rid]
+ self.emap[hdr.deq_rid] = (t[0], t[1], True) # Lock enq record
+ if hdr.xid in self.tmap:
+ self.tmap[hdr.xid].append((self.fhdr.fid, hdr)) #Append to existing list
+ else:
+ self.tmap[hdr.xid] = [(self.fhdr.fid, hdr)] # Create new list
+ elif isinstance(hdr, TxnHdr) and not stop:
+ while not hdr.complete():
+ stop = self.advance_file()
+ if stop:
+ break
+ hdr.load(self.f)
+ stop = not self.check_owi(hdr)
+ if stop:
+ warn = ' (WARNING: OWI mismatch - could be overwrite boundary.)'
+ else:
+ if hdr.xid in self.tmap:
+ mismatched_rids = []
+ if hdr.magic[-1] == 'c': # commit
+ for rec in self.tmap[hdr.xid]:
+ if isinstance(rec[1], EnqRec):
+ self.emap[rec[1].rid] = (rec[0], rec[1], False) # Transfer enq to emap
+ elif isinstance(rec[1], DeqHdr):
+ if rec[1].deq_rid in self.emap:
+ del self.emap[rec[1].deq_rid] # Delete from emap
+ else:
+ mismatched_rids.append('0x%x' % rec[1].deq_rid)
+ else:
+ raise Exception('Unknown header found in txn map: %s' % rec[1])
+ elif hdr.magic[-1] == 'a': # abort
+ for rec in self.tmap[hdr.xid]:
+ if isinstance(rec[1], DeqHdr):
+ if rec[1].deq_rid in self.emap:
+ t = self.emap[rec[1].deq_rid]
+ self.emap[rec[1].deq_rid] = (t[0], t[1], False) # Unlock enq record
+ del self.tmap[hdr.xid]
+ if len(mismatched_rids) > 0:
+ warn = ' (WARNING: transactional dequeues not found in enqueue map; rids=%s)' % mismatched_rids
+ else:
+ warn = ' (WARNING: %s not found in transaction map)' % print_xid(len(hdr.xid), hdr.xid)
+ if not self.qflag: print ' > %s%s' % (hdr, warn)
+ if not stop:
+ stop = (self.last_file and hdr.check()) or hdr.empty() or self.fhdr.empty()
+
+ def analyze_files(self):
+ fname = ''
+ fnum = -1
+ rid = -1
+ fro = -1
+ tss = ''
+ if not self.qflag: print 'Analyzing journal files:'
+ owi_found = False
+ for i in range(0, self.num_jfiles):
+ jfn = self.jdir + '/' + self.bfn + '.%04d.jdat' % i
+ f = open(jfn)
+ fhdr = load(f, Hdr)
+ if fhdr.empty():
+ if not self.qflag:
+ print ' %s: file empty' % jfn
+ break
+ if i == 0:
+ init_owi = fhdr.owi()
+ fname = jfn
+ fnum = i
+ rid = fhdr.rid
+ fro = fhdr.fro
+ tss = fhdr.timestamp_str()
+ elif fhdr.owi() != init_owi and not owi_found:
+ fname = jfn
+ fnum = i
+ rid = fhdr.rid
+ fro = fhdr.fro
+ tss = fhdr.timestamp_str()
+ owi_found = True
+ if not self.qflag:
+ print ' %s: owi=%s rid=0x%x, fro=0x%08x ts=%s' % (jfn, fhdr.owi(), fhdr.rid, fhdr.fro, fhdr.timestamp_str())
+ if fnum < 0 or rid < 0 or fro < 0:
+ raise Exception('All journal files empty')
+ if not self.qflag: print ' Oldest complete file: %s: rid=%d, fro=0x%08x ts=%s' % (fname, rid, fro, tss)
+ return (fnum, rid, fro)
+
+ def advance_file(self, *start_info):
+ seek_flag = False
+ if len(start_info) == 3:
+ self.file_start = self.file_num = start_info[0]
+ self.fro = start_info[2]
+ seek_flag = True
+ if self.f != None and file_full(self.f):
+ self.file_num = self.incr_fnum()
+ if self.file_num == self.file_start:
+ return True
+ if self.file_start == 0:
+ self.last_file = self.file_num == self.num_jfiles - 1
+ else:
+ self.last_file = self.file_num == self.file_start - 1
+ if self.file_num < 0 or self.file_num >= self.num_jfiles:
+ raise Exception('Bad file number %d' % self.file_num)
+ jfn = self.jdir + '/' + self.bfn + '.%04d.jdat' % self.file_num
+ self.f = open(jfn)
+ self.fhdr = load(self.f, Hdr)
+ if seek_flag and self.f.tell() != self.fro:
+ self.f.seek(self.fro)
+ self.first_rec = True
+ if not self.qflag: print jfn, ": ", self.fhdr
+ return False
+
+ def incr_fnum(self):
+ self.file_num += 1
+ if self.file_num >= self.num_jfiles:
+ self.file_num = 0;
+ return self.file_num
+
+ def check_owi(self, hdr):
+ return self.fhdr_owi_at_msg_start == hdr.owi()
+
+ def check_rid(self, hdr):
+ if self.last_rid != -1 and hdr.rid <= self.last_rid:
+ return False
+ self.last_rid = hdr.rid
+ return True
+
+ def read_jinf(self):
+ filename = self.jdir + '/' + self.bfn + '.jinf'
+ try:
+ f = open(filename, 'r')
+ except IOError:
+ print 'ERROR: Unable to open jinf file %s' % filename
+ sys.exit(1)
+ p = xml.parsers.expat.ParserCreate()
+ p.StartElementHandler = self.handleStartElement
+ p.CharacterDataHandler = self.handleCharData
+ p.EndElementHandler = self.handleEndElement
+ p.ParseFile(f)
+ if self.num_jfiles == None:
+ print 'ERROR: number_jrnl_files not found in jinf file "%s"!' % filename
+ if jfsize == None:
+ print 'ERROR: jrnl_file_size_sblks not found in jinf file "%s"!' % filename
+ if self.num_jfiles == None or jfsize == None:
+ sys.exit(1)
+
+ def handleStartElement(self, name, attrs):
+ global jfsize
+ if name == 'number_jrnl_files':
+ self.num_jfiles = int(attrs['value'])
+ if name == 'jrnl_file_size_sblks':
+ jfsize = (int(attrs['value']) + 1) * sblk_size
+
+ def handleCharData(self, data): pass
+
+ def handleEndElement(self, name): pass
+
+ def proc_csv(self):
+ if self.csvfn != None and self.tnum != None:
+ tparams = self.get_test(self.csvfn, self.tnum)
+ if tparams == None:
+ print 'ERROR: Test %d not found in CSV file "%s"' % (self.tnum, self.csvfn)
+ sys.exit(1)
+ self.num_msgs = tparams['num_msgs']
+ if tparams['min_size'] == tparams['max_size']:
+ self.msg_len = tparams['max_size']
+ else:
+ self.msg_len = 0
+ self.auto_deq = tparams['auto_deq']
+ if tparams['xid_min_size'] == tparams['xid_max_size']:
+ self.xid_len = tparams['xid_max_size']
+ else:
+ self.xid_len = 0
+ self.transient = tparams['transient']
+ self.extern = tparams['extern']
+
+ def get_test(self, filename, tnum):
+ try:
+ f=open(filename, 'r')
+ except IOError:
+ print 'ERROR: Unable to open CSV file "%s"' % filename
+ sys.exit(1)
+ for l in f:
+ sl = l.strip().split(',')
+ if len(sl[0]) > 0 and sl[0][0] != '"':
+ try:
+ if (int(sl[TEST_NUM_COL]) == tnum):
+ return { 'num_msgs':int(sl[NUM_MSGS_COL]),
+ 'min_size':int(sl[MIN_MSG_SIZE_COL]),
+ 'max_size':int(sl[MAX_MSG_SIZE_COL]),
+ 'auto_deq':not (sl[AUTO_DEQ_COL] == 'FALSE' or sl[AUTO_DEQ_COL] == '0'),
+ 'xid_min_size':int(sl[MIN_XID_SIZE_COL]),
+ 'xid_max_size':int(sl[MAX_XID_SIZE_COL]),
+ 'transient':not (sl[TRANSIENT_COL] == 'FALSE' or sl[TRANSIENT_COL] == '0'),
+ 'extern':not (sl[EXTERN_COL] == 'FALSE' or sl[EXTERN_COL] == '0'),
+ 'comment':sl[COMMENT_COL] }
+ except Exception:
+ pass
+ return None
+
+ def proc_args(self, argv):
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "ab:c:d:hqt:", ["analyse", "base-filename=", "csv-filename=", "dir=", "help", "quiet", "test-num="])
+ except getopt.GetoptError:
+ self.usage()
+ sys.exit(2)
+ for o, a in opts:
+ if o in ("-h", "--help"):
+ self.usage()
+ sys.exit()
+ if o in ("-a", "--analyze"):
+ self.aflag = True
+ if o in ("-b", "--base-filename"):
+ self.bfn = a
+ if o in ("-c", "--csv-filename"):
+ self.csvfn = a
+ if o in ("-d", "--dir"):
+ self.jdir = a
+ if o in ("-q", "--quiet"):
+ self.qflag = True
+ if o in ("-t", "--test-num"):
+ if not a.isdigit():
+ print 'ERROR: Illegal test-num argument. Must be a non-negative number'
+ sys.exit(2)
+ self.tnum = int(a)
+ if self.bfn == None or self.jdir == None:
+ print 'ERROR: Missing requred args.'
+ self.usage()
+ sys.exit(2)
+ if self.tnum != None and self.csvfn == None:
+ print 'ERROR: Test number specified, but not CSV file'
+ self.usage()
+ sys.exit(2)
+
+ def usage(self):
+ print 'Usage: %s opts' % sys.argv[0]
+ print ' where opts are in either short or long format (*=req\'d):'
+ print ' -a --analyze Analyze enqueue/dequeue records'
+ print ' -b --base-filename [string] * Base filename for journal files'
+ print ' -c --csv-filename [string] CSV filename containing test parameters'
+ print ' -d --dir [string] * Journal directory containing journal files'
+ print ' -h --help Print help'
+ print ' -q --quiet Quiet (reduced output)'
+ print ' -t --test-num [int] Test number from CSV file - only valid if CSV file named'
+
+ def report(self):
+ if not self.qflag:
+ print
+ print ' === REPORT ===='
+ if self.num_msgs > 0 and self.msg_cnt != self.num_msgs:
+ print 'WARNING: Found %d messages; %d expected.' % (self.msg_cnt, self.num_msgs)
+ if len(self.emap) > 0:
+ print
+ print 'Remaining enqueued records (sorted by rid): '
+ keys = sorted(self.emap.keys())
+ for k in keys:
+ if self.emap[k][2] == True: # locked
+ locked = ' (locked)'
+ else:
+ locked = ''
+ print " fid=%d %s%s" % (self.emap[k][0], self.emap[k][1], locked)
+ print 'WARNING: Enqueue-Dequeue mismatch, %d enqueued records remain.' % len(self.emap)
+ if len(self.tmap) > 0:
+ txn_rec_cnt = 0
+ print
+ print 'Remaining transactions: '
+ for t in self.tmap:
+ print_xid(len(t), t)
+ for r in self.tmap[t]:
+ print " fid=%d %s" % (r[0], r[1])
+ print " Total: %d records for xid %s" % (len(self.tmap[t]), t)
+ txn_rec_cnt += len(self.tmap[t])
+ print 'WARNING: Incomplete transactions, %d xids remain containing %d records.' % (len(self.tmap), txn_rec_cnt)
+ print '%d enqueues, %d journal records processed.' % (self.msg_cnt, self.rec_cnt)
+
+
+#===============================================================================
+
+CLASSES = {
+ "a": TxnHdr,
+ "c": TxnHdr,
+ "d": DeqHdr,
+ "e": EnqRec,
+ "f": FileHdr
+}
+
+m = Main(sys.argv)
+m.run()
+m.report()
+
+sys.exit(None)
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/jrnl_init_params.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/jrnl_init_params.cpp
new file mode 100644
index 0000000000..1bc04110af
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/jrnl_init_params.cpp
@@ -0,0 +1,77 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "jrnl_init_params.h"
+
+namespace mrg
+{
+namespace jtt
+{
+
+jrnl_init_params::jrnl_init_params(const std::string& jid, const std::string& jdir, const std::string& base_filename,
+ const u_int16_t num_jfiles, const bool ae, const u_int16_t ae_max_jfiles, const u_int32_t jfsize_sblks,
+ const u_int16_t wcache_num_pages, const u_int32_t wcache_pgsize_sblks):
+ _jid(jid),
+ _jdir(jdir),
+ _base_filename(base_filename),
+ _num_jfiles(num_jfiles),
+ _ae(ae),
+ _ae_max_jfiles(ae_max_jfiles),
+ _jfsize_sblks(jfsize_sblks),
+ _wcache_num_pages(wcache_num_pages),
+ _wcache_pgsize_sblks(wcache_pgsize_sblks)
+{}
+
+jrnl_init_params::jrnl_init_params(const jrnl_init_params& jp):
+ _jid(jp._jid),
+ _jdir(jp._jdir),
+ _base_filename(jp._base_filename),
+ _num_jfiles(jp._num_jfiles),
+ _ae(jp._ae),
+ _ae_max_jfiles(jp._ae_max_jfiles),
+ _jfsize_sblks(jp._jfsize_sblks),
+ _wcache_num_pages(jp._wcache_num_pages),
+ _wcache_pgsize_sblks(jp._wcache_pgsize_sblks)
+{}
+
+jrnl_init_params::jrnl_init_params(const jrnl_init_params* const jp_ptr):
+ _jid(jp_ptr->_jid),
+ _jdir(jp_ptr->_jdir),
+ _base_filename(jp_ptr->_base_filename),
+ _num_jfiles(jp_ptr->_num_jfiles),
+ _ae(jp_ptr->_ae),
+ _ae_max_jfiles(jp_ptr->_ae_max_jfiles),
+ _jfsize_sblks(jp_ptr->_jfsize_sblks),
+ _wcache_num_pages(jp_ptr->_wcache_num_pages),
+ _wcache_pgsize_sblks(jp_ptr->_wcache_pgsize_sblks)
+{}
+
+// static initializers
+
+const u_int16_t jrnl_init_params::def_num_jfiles = 8;
+const bool jrnl_init_params::def_ae = false;
+const u_int16_t jrnl_init_params::def_ae_max_jfiles = 0;
+const u_int32_t jrnl_init_params::def_jfsize_sblks = 0xc00;
+const u_int16_t jrnl_init_params::def_wcache_num_pages = 32;
+const u_int32_t jrnl_init_params::def_wcache_pgsize_sblks = 64;
+
+} // namespace jtt
+} // namespace mrg
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/jrnl_init_params.h b/qpid/cpp/src/tests/legacystore/jrnl/jtt/jrnl_init_params.h
new file mode 100644
index 0000000000..ece87f8e03
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/jrnl_init_params.h
@@ -0,0 +1,80 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef mrg_jtt_jrnl_init_params_hpp
+#define mrg_jtt_jrnl_init_params_hpp
+
+#include <boost/shared_ptr.hpp>
+#include <string>
+#include <sys/types.h>
+
+namespace mrg
+{
+namespace jtt
+{
+
+ class jrnl_init_params
+ {
+ public:
+ static const u_int16_t def_num_jfiles;
+ static const bool def_ae;
+ static const u_int16_t def_ae_max_jfiles;
+ static const u_int32_t def_jfsize_sblks;
+ static const u_int16_t def_wcache_num_pages;
+ static const u_int32_t def_wcache_pgsize_sblks;
+
+ typedef boost::shared_ptr<jrnl_init_params> shared_ptr;
+
+ private:
+ std::string _jid;
+ std::string _jdir;
+ std::string _base_filename;
+ u_int16_t _num_jfiles;
+ bool _ae;
+ u_int16_t _ae_max_jfiles;
+ u_int32_t _jfsize_sblks;
+ u_int16_t _wcache_num_pages;
+ u_int32_t _wcache_pgsize_sblks;
+
+ public:
+ jrnl_init_params(const std::string& jid, const std::string& jdir, const std::string& base_filename,
+ const u_int16_t num_jfiles = def_num_jfiles, const bool ae = def_ae,
+ const u_int16_t ae_max_jfiles = def_ae_max_jfiles, const u_int32_t jfsize_sblks = def_jfsize_sblks,
+ const u_int16_t wcache_num_pages = def_wcache_num_pages,
+ const u_int32_t wcache_pgsize_sblks = def_wcache_pgsize_sblks);
+ jrnl_init_params(const jrnl_init_params& jp);
+ jrnl_init_params(const jrnl_init_params* const jp_ptr);
+
+ inline const std::string& jid() const { return _jid; }
+ inline const std::string& jdir() const { return _jdir; }
+ inline const std::string& base_filename() const { return _base_filename; }
+ inline u_int16_t num_jfiles() const { return _num_jfiles; }
+ inline bool is_ae() const { return _ae; }
+ inline u_int16_t ae_max_jfiles() const { return _ae_max_jfiles; }
+ inline u_int32_t jfsize_sblks() const { return _jfsize_sblks; }
+ inline u_int16_t wcache_num_pages() const { return _wcache_num_pages; }
+ inline u_int32_t wcache_pgsize_sblks() const { return _wcache_pgsize_sblks; }
+ };
+
+} // namespace jtt
+} // namespace mrg
+
+#endif // ifndef mrg_jtt_jrnl_init_params_hpp
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/jrnl_instance.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/jrnl_instance.cpp
new file mode 100644
index 0000000000..339dc1b52c
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/jrnl_instance.cpp
@@ -0,0 +1,439 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "jrnl_instance.h"
+
+#include <cstdlib>
+#include "data_src.h"
+#include "qpid/legacystore/jrnl/data_tok.h"
+#include "qpid/legacystore/jrnl/jerrno.h"
+#include "test_case_result.h"
+
+#define MAX_WR_WAIT 10 // in ms
+#define MAX_RD_WAIT 100 // in ms
+#define MAX_ENQCAPTHRESH_CNT 1000 // 10s if MAX_WR_WAIT is 10 ms
+
+namespace mrg
+{
+namespace jtt
+{
+
+jrnl_instance::jrnl_instance(const std::string& jid, const std::string& jdir, const std::string& base_filename,
+ const u_int16_t num_jfiles, const bool ae, const u_int16_t ae_max_jfiles, const u_int32_t jfsize_sblks,
+ const u_int16_t wcache_num_pages, const u_int32_t wcache_pgsize_sblks):
+ mrg::journal::jcntl(jid, jdir, base_filename),
+ _jpp(new jrnl_init_params(jid, jdir, base_filename, num_jfiles, ae, ae_max_jfiles, jfsize_sblks,
+ wcache_num_pages, wcache_pgsize_sblks)),
+ _args_ptr(0),
+ _dtok_master_enq_list(),
+ _dtok_master_txn_list(),
+ _dtok_rd_list(),
+ _dtok_deq_list(),
+ _rd_aio_cv(_rd_aio_mutex),
+ _wr_full_cv(_wr_full_mutex),
+ _rd_list_cv(_rd_list_mutex),
+ _deq_list_cv(_deq_list_mutex),
+ _tcp(),
+ _tcrp()
+{}
+
+jrnl_instance::jrnl_instance(const jrnl_init_params::shared_ptr& p):
+ mrg::journal::jcntl(p->jid(), p->jdir(), p->base_filename()),
+ _jpp(p),
+ _args_ptr(0),
+ _dtok_master_enq_list(),
+ _dtok_master_txn_list(),
+ _dtok_rd_list(),
+ _dtok_deq_list(),
+ _rd_aio_cv(_rd_aio_mutex),
+ _wr_full_cv(_wr_full_mutex),
+ _rd_list_cv(_rd_list_mutex),
+ _deq_list_cv(_deq_list_mutex),
+ _tcp(),
+ _tcrp()
+{}
+
+jrnl_instance::~jrnl_instance() {}
+
+
+void
+jrnl_instance::init_tc(test_case::shared_ptr& tcp, const args* const args_ptr) throw ()
+{
+ test_case_result::shared_ptr p(new test_case_result(_jpp->jid()));
+ _tcrp = p;
+ _args_ptr = args_ptr;
+ try
+ {
+ _tcp = tcp;
+ _dtok_master_enq_list.clear();
+ _dtok_master_txn_list.clear();
+ _dtok_rd_list.clear();
+ _dtok_deq_list.clear();
+
+ if (_args_ptr->recover_mode)
+ {
+ try
+ {
+ u_int64_t highest_rid;
+ recover(_jpp->num_jfiles(), _jpp->is_ae(), _jpp->ae_max_jfiles(), _jpp->jfsize_sblks(),
+ _jpp->wcache_num_pages(), _jpp->wcache_pgsize_sblks(), this,
+ 0, highest_rid);
+ recover_complete();
+ }
+ catch (const mrg::journal::jexception& e)
+ {
+ if (e.err_code() == mrg::journal::jerrno::JERR_JDIR_STAT)
+ initialize(_jpp->num_jfiles(), _jpp->is_ae(), _jpp->ae_max_jfiles(), _jpp->jfsize_sblks(),
+ _jpp->wcache_num_pages(), _jpp->wcache_pgsize_sblks(), this);
+ else
+ throw;
+ }
+ }
+ else
+ initialize(_jpp->num_jfiles(), _jpp->is_ae(), _jpp->ae_max_jfiles(), _jpp->jfsize_sblks(),
+ _jpp->wcache_num_pages(), _jpp->wcache_pgsize_sblks(), this);
+ }
+ catch (const mrg::journal::jexception& e) { _tcrp->add_exception(e); }
+ catch (const std::exception& e) { _tcrp->add_exception(e.what()); }
+ catch (...) { _tcrp->add_exception("Unknown exception"); }
+}
+
+void
+jrnl_instance::run_tc() throw ()
+{
+ _tcrp->set_start_time();
+ ::pthread_create(&_enq_thread, 0, run_enq, this);
+ ::pthread_create(&_read_thread, 0, run_read, this);
+ ::pthread_create(&_deq_thread, 0, run_deq, this);
+}
+
+void
+jrnl_instance::tc_wait_compl() throw ()
+{
+ try
+ {
+ ::pthread_join(_deq_thread, 0);
+ ::pthread_join(_read_thread, 0);
+ ::pthread_join(_enq_thread, 0);
+ stop(true);
+ }
+ catch (const mrg::journal::jexception& e) { _tcrp->add_exception(e); panic(); }
+ catch (const std::exception& e) { _tcrp->add_exception(e.what()); panic(); }
+ catch (...) { _tcrp->add_exception("Unknown exception"); panic(); }
+ _lpmgr.finalize();
+ _tcrp->set_stop_time();
+ _tcp->add_result(_tcrp);
+}
+
+void
+jrnl_instance::run_enq() throw ()
+{
+ try
+ {
+ unsigned sleep_cnt = 0U;
+ while(_tcrp->num_enq() < _tcp->num_msgs() && !_tcrp->exception())
+ {
+ dtok_ptr p(new mrg::journal::data_tok);
+ _dtok_master_enq_list.push_back(p);
+ const char* msgp = data_src::get_data(_tcrp->num_enq() % 10);
+ const std::size_t msg_size = _tcp->this_data_size();
+ const std::size_t xid_size = _tcp->this_xid_size();
+ const std::string xid(data_src::get_xid(xid_size));
+ const bool external = _tcp->this_external();
+ const bool transient = _tcp->this_transience();
+ mrg::journal::iores res;
+ if (xid_size)
+ {
+ if (external)
+ res = enqueue_extern_txn_data_record(msg_size, p.get(), xid, transient);
+ else
+ res = enqueue_txn_data_record(msgp, msg_size, msg_size, p.get(), xid,
+ transient);
+ }
+ else
+ {
+ if (external)
+ res = enqueue_extern_data_record(msg_size, p.get(), transient);
+ else
+ res = enqueue_data_record(msgp, msg_size, msg_size, p.get(), transient);
+ }
+ switch (res)
+ {
+ case mrg::journal::RHM_IORES_SUCCESS:
+ sleep_cnt = 0U;
+ _tcrp->incr_num_enq();
+ if (p->has_xid() && !_tcp->auto_deq())
+ commit(p.get());
+ break;
+ case mrg::journal::RHM_IORES_ENQCAPTHRESH:
+ if (++sleep_cnt > MAX_ENQCAPTHRESH_CNT)
+ {
+ _tcrp->add_exception("Timeout waiting for RHM_IORES_ENQCAPTHRESH to clear.");
+ panic();
+ }
+ else if (get_wr_events(0) == 0) // *** GEV2
+ {
+ mrg::journal::slock sl(_wr_full_mutex);
+ _wr_full_cv.waitintvl(MAX_WR_WAIT * 1000000); // MAX_WR_WAIT in ms
+ }
+ break;
+ default:
+ std::ostringstream oss;
+ oss << "ERROR: enqueue operation in journal \"" << _jid << "\" returned ";
+ oss << mrg::journal::iores_str(res) << ".";
+ _tcrp->add_exception(oss.str());
+ }
+ }
+ flush(true);
+ }
+ catch (const mrg::journal::jexception& e) { _tcrp->add_exception(e); panic(); }
+ catch (const std::exception& e) { _tcrp->add_exception(e.what()); panic(); }
+ catch (...) { _tcrp->add_exception("Unknown exception"); panic(); }
+}
+
+void
+jrnl_instance::run_read() throw ()
+{
+ try
+ {
+ read_arg::read_mode_t rd_mode = _args_ptr->read_mode.val();
+ if (rd_mode != read_arg::NONE)
+ {
+ while (_tcrp->num_rproc() < _tcp->num_msgs() && !_tcrp->exception())
+ {
+ journal::data_tok* dtokp = 0;
+ {
+ mrg::journal::slock sl(_rd_list_mutex);
+ if (_dtok_rd_list.empty())
+ _rd_list_cv.wait();
+ if (!_dtok_rd_list.empty())
+ {
+ dtokp = _dtok_rd_list.front();
+ _dtok_rd_list.pop_front();
+ }
+ }
+ if (dtokp)
+ {
+ _tcrp->incr_num_rproc();
+
+ bool do_read = true;
+ if (rd_mode == read_arg::RANDOM)
+ do_read = 1.0 * std::rand() / RAND_MAX < _args_ptr->read_prob / 100.0;
+ else if (rd_mode == read_arg::LAZYLOAD)
+ do_read = _tcrp->num_rproc() >= _args_ptr->lld_skip_num &&
+ _tcrp->num_read() < _args_ptr->lld_rd_num;
+ bool read_compl = false;
+ while (do_read && !read_compl && !_tcrp->exception())
+ {
+ void* dptr = 0;
+ std::size_t dsize = 0;
+ void* xptr = 0;
+ std::size_t xsize = 0;
+ bool tr = false;
+ bool ext = false;
+ mrg::journal::iores res = read_data_record(&dptr, dsize, &xptr, xsize, tr,
+ ext, dtokp);
+ switch (res)
+ {
+ case mrg::journal::RHM_IORES_SUCCESS:
+ {
+ mrg::journal::slock sl(_deq_list_mutex);
+ _dtok_deq_list.push_back(dtokp);
+ _deq_list_cv.broadcast();
+ }
+ read_compl = true;
+ _tcrp->incr_num_read();
+
+ // clean up
+ if (xsize)
+ std::free(xptr);
+ else if (dsize)
+ std::free(dptr);
+ dptr = 0;
+ xptr = 0;
+ break;
+ case mrg::journal::RHM_IORES_PAGE_AIOWAIT:
+ if (get_rd_events(0) == 0)
+ {
+ mrg::journal::slock sl(_rd_aio_mutex);
+ _rd_aio_cv.waitintvl(MAX_RD_WAIT * 1000000); // MAX_RD_WAIT in ms
+ }
+ break;
+ default:
+ std::ostringstream oss;
+ oss << "ERROR: read operation in journal \"" << _jid;
+ oss << "\" returned " << mrg::journal::iores_str(res) << ".";
+ _tcrp->add_exception(oss.str());
+ {
+ mrg::journal::slock sl(_deq_list_mutex);
+ _deq_list_cv.broadcast(); // wake up deq thread
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ catch (const mrg::journal::jexception& e) { _tcrp->add_exception(e); panic(); }
+ catch (const std::exception& e) { _tcrp->add_exception(e.what()); panic(); }
+ catch (...) { _tcrp->add_exception("Unknown exception"); panic(); }
+}
+
+void
+jrnl_instance::run_deq() throw ()
+{
+ try
+ {
+ if (_tcp->auto_deq())
+ {
+ while(_tcrp->num_deq() < _tcp->num_msgs() && !_tcrp->exception())
+ {
+ journal::data_tok* dtokp = 0;
+ {
+ mrg::journal::slock sl(_deq_list_mutex);
+ if (_dtok_deq_list.empty())
+ _deq_list_cv.wait();
+ if (!_dtok_deq_list.empty())
+ {
+ dtokp = _dtok_deq_list.front();
+ _dtok_deq_list.pop_front();
+ }
+ }
+ if (dtokp)
+ {
+ mrg::journal::iores res;
+ if (dtokp->has_xid())
+ res = dequeue_txn_data_record(dtokp, dtokp->xid());
+ else
+ res = dequeue_data_record(dtokp);
+ if (res == mrg::journal::RHM_IORES_SUCCESS)
+ {
+ _tcrp->incr_num_deq();
+ commit(dtokp);
+ }
+ else
+ {
+ std::ostringstream oss;
+ oss << "ERROR: dequeue operation in journal \"" << _jid;
+ oss << "\" returned " << mrg::journal::iores_str(res) << ".";
+ _tcrp->add_exception(oss.str());
+ }
+ }
+ }
+ flush(true);
+ }
+ }
+ catch (const mrg::journal::jexception& e) { _tcrp->add_exception(e); panic(); }
+ catch (const std::exception& e) { _tcrp->add_exception(e.what()); panic(); }
+ catch (...) { _tcrp->add_exception("Unknown exception"); panic(); }
+}
+
+void
+jrnl_instance::abort(const mrg::journal::data_tok* dtokp)
+{
+ txn(dtokp, false);
+}
+
+void
+jrnl_instance::commit(const mrg::journal::data_tok* dtokp)
+{
+ txn(dtokp, true);
+}
+
+void
+jrnl_instance::txn(const mrg::journal::data_tok* dtokp, const bool commit)
+{
+ if (dtokp->has_xid())
+ {
+ mrg::journal::data_tok* p = prep_txn_dtok(dtokp);
+ mrg::journal::iores res = commit ? txn_commit(p, p->xid()) : txn_abort(p, p->xid());
+ if (res != mrg::journal::RHM_IORES_SUCCESS)
+ {
+ std::ostringstream oss;
+ oss << "ERROR: " << (commit ? "commit" : "abort") << " operation in journal \"";
+ oss << _jid << "\" returned " << mrg::journal::iores_str(res) << ".";
+ _tcrp->add_exception(oss.str());
+ }
+ }
+}
+
+mrg::journal::data_tok*
+jrnl_instance::prep_txn_dtok(const mrg::journal::data_tok* dtokp)
+{
+ dtok_ptr p(new mrg::journal::data_tok);
+ _dtok_master_txn_list.push_back(p);
+ p->set_xid(dtokp->xid());
+ return p.get();
+}
+
+void
+jrnl_instance::panic()
+{
+ // In the event of a panic or exception condition, release all waiting CVs
+ _rd_aio_cv.broadcast();
+ _wr_full_cv.broadcast();
+ _rd_list_cv.broadcast();
+ _deq_list_cv.broadcast();
+}
+
+// AIO callbacks
+
+void
+jrnl_instance::wr_aio_cb(std::vector<journal::data_tok*>& dtokl)
+{
+ for (std::vector<journal::data_tok*>::const_iterator i=dtokl.begin(); i!=dtokl.end(); i++)
+ {
+ if ((*i)->wstate() == journal::data_tok::ENQ || (*i)->wstate() == journal::data_tok::DEQ)
+ {
+ journal::data_tok* dtokp = *i;
+ if (dtokp->wstate() == journal::data_tok::ENQ)
+ {
+ if (_args_ptr->read_mode.val() == read_arg::NONE)
+ {
+ mrg::journal::slock sl(_deq_list_mutex);
+ _dtok_deq_list.push_back(dtokp);
+ _deq_list_cv.broadcast();
+ }
+ else
+ {
+ mrg::journal::slock sl(_rd_list_mutex);
+ _dtok_rd_list.push_back(dtokp);
+ _rd_list_cv.broadcast();
+ }
+ }
+ else // DEQ
+ {
+ mrg::journal::slock sl(_wr_full_mutex);
+ _wr_full_cv.broadcast();
+ }
+ }
+ }
+}
+
+void
+jrnl_instance::rd_aio_cb(std::vector<u_int16_t>& /*pil*/)
+{
+ mrg::journal::slock sl(_rd_aio_mutex);
+ _rd_aio_cv.broadcast();
+}
+
+} // namespace jtt
+} // namespace mrg
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/jrnl_instance.h b/qpid/cpp/src/tests/legacystore/jrnl/jtt/jrnl_instance.h
new file mode 100644
index 0000000000..5003f39b24
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/jrnl_instance.h
@@ -0,0 +1,121 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef mrg_jtt_jrnl_instance_hpp
+#define mrg_jtt_jrnl_instance_hpp
+
+#include "args.h"
+#include "jrnl_init_params.h"
+#include "test_case.h"
+
+#include <boost/shared_ptr.hpp>
+#include "qpid/legacystore/jrnl/cvar.h"
+#include "qpid/legacystore/jrnl/data_tok.h"
+#include "qpid/legacystore/jrnl/jcntl.h"
+#include "qpid/legacystore/jrnl/slock.h"
+#include "qpid/legacystore/jrnl/smutex.h"
+#include <list>
+#include <vector>
+
+namespace mrg
+{
+namespace jtt
+{
+
+ class jrnl_instance : public mrg::journal::jcntl, public virtual mrg::journal::aio_callback
+ {
+ public:
+ typedef boost::shared_ptr<jrnl_instance> shared_ptr;
+ typedef boost::shared_ptr<journal::data_tok> dtok_ptr;
+
+ private:
+ jrnl_init_params::shared_ptr _jpp;
+ const args* _args_ptr;
+ std::vector<dtok_ptr> _dtok_master_enq_list;
+ std::vector<dtok_ptr> _dtok_master_txn_list;
+ std::list<journal::data_tok*> _dtok_rd_list;
+ std::list<journal::data_tok*> _dtok_deq_list;
+ mrg::journal::smutex _rd_aio_mutex; ///< Mutex for read aio wait conditions
+ mrg::journal::cvar _rd_aio_cv; ///< Condition var for read aio wait conditions
+ mrg::journal::smutex _wr_full_mutex; ///< Mutex for write full conditions
+ mrg::journal::cvar _wr_full_cv; ///< Condition var for write full conditions
+ mrg::journal::smutex _rd_list_mutex; ///< Mutex for _dtok_rd_list
+ mrg::journal::cvar _rd_list_cv; ///< Condition var for _dtok_rd_list
+ mrg::journal::smutex _deq_list_mutex; ///< Mutex for _dtok_deq_list
+ mrg::journal::cvar _deq_list_cv; ///< Condition var for _dtok_deq_list
+ pthread_t _enq_thread;
+ pthread_t _deq_thread;
+ pthread_t _read_thread;
+ test_case::shared_ptr _tcp;
+ test_case_result::shared_ptr _tcrp;
+
+ public:
+ jrnl_instance(const std::string& jid, const std::string& jdir,
+ const std::string& base_filename,
+ const u_int16_t num_jfiles = jrnl_init_params::def_num_jfiles,
+ const bool ae = jrnl_init_params::def_ae,
+ const u_int16_t ae_max_jfiles = jrnl_init_params::def_ae_max_jfiles,
+ const u_int32_t jfsize_sblks = jrnl_init_params::def_jfsize_sblks,
+ const u_int16_t wcache_num_pages = jrnl_init_params::def_wcache_num_pages,
+ const u_int32_t wcache_pgsize_sblks = jrnl_init_params::def_wcache_pgsize_sblks);
+ jrnl_instance(const jrnl_init_params::shared_ptr& params);
+ virtual ~jrnl_instance();
+
+ inline const jrnl_init_params::shared_ptr& params() const { return _jpp; }
+ inline const std::string& jid() const { return _jpp->jid(); }
+
+ void init_tc(test_case::shared_ptr& tcp, const args* const args_ptr) throw ();
+ void run_tc() throw ();
+ void tc_wait_compl() throw ();
+
+ // AIO callbacks
+ virtual void wr_aio_cb(std::vector<journal::data_tok*>& dtokl);
+ virtual void rd_aio_cb(std::vector<u_int16_t>& pil);
+
+ private:
+ void run_enq() throw ();
+ inline static void* run_enq(void* p)
+ { static_cast<jrnl_instance*>(p)->run_enq(); return 0; }
+
+ void run_read() throw ();
+ inline static void* run_read(void* p)
+ { static_cast<jrnl_instance*>(p)->run_read(); return 0; }
+
+ void run_deq() throw ();
+ inline static void* run_deq(void* p)
+ { static_cast<jrnl_instance*>(p)->run_deq(); return 0; }
+
+ void abort(const mrg::journal::data_tok* dtokp);
+ void commit(const mrg::journal::data_tok* dtokp);
+ void txn(const mrg::journal::data_tok* dtokp, const bool commit);
+ mrg::journal::data_tok* prep_txn_dtok(const mrg::journal::data_tok* dtokp);
+
+ void panic();
+
+// // static callbacks
+// static void aio_rd_callback(jcntl* journal, std::vector<u_int16_t>& pil);
+// static void aio_wr_callback(jcntl* journal, std::vector<journal::data_tok*>& dtokl);
+ };
+
+} // namespace jtt
+} // namespace mrg
+
+#endif // ifndef mrg_jtt_jrnl_instance_hpp
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/jtt.csv b/qpid/cpp/src/tests/legacystore/jrnl/jtt/jtt.csv
new file mode 100644
index 0000000000..df523e3f97
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/jtt.csv
@@ -0,0 +1,234 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+,,,,,,,"Msg size",,"Xid size",,,,,"enq-size",,"deq-size",,"txn-size",,
+"Test #","tf","pf","amn","mn incr","#msgs","ms incr","Min","Max","Min","Max","auto-deq","transient","extern","bytes","dblks","bytes","dblks","bytes","dblks","comment"
+,,,,,,,,,,,,,,,,,,,,
+"Initialize only",,,,,,,,,,,,,,,,,,,,
+0,"L",0,0,0,0,0,0,0,0,0,FALSE,FALSE,FALSE,44,1,0,0,0,0,"No messages - journal creation/initialization only"
+,,,,,,,,,,,,,,,,,,,,
+"Simple message combinations of persistent/deq transientueued/non-dequeued, transactional/non-transactional",,,,,,,,,,,,,,,,,,,,
+1,"L",1,1,0,1,0,10,10,0,0,FALSE,FALSE,FALSE,54,1,0,0,0,0,"1 * 10-byte message"
+2,"L",1,10,0,10,0,10,10,0,0,FALSE,FALSE,FALSE,54,1,0,0,0,0,"10 * 10-byte message"
+3,"L",1,1,0,1,0,10,10,0,0,FALSE,TRUE,FALSE,54,1,0,0,0,0,"1 * 10-byte message [transient]"
+4,"L",1,10,0,10,0,10,10,0,0,FALSE,TRUE,FALSE,54,1,0,0,0,0,"10 * 10-byte message [transient]"
+5,"L",1,1,0,1,0,10,10,10,10,FALSE,FALSE,FALSE,64,1,0,0,0,0,"1 * 10-byte message [txn]"
+6,"L",1,10,0,10,0,10,10,10,10,FALSE,FALSE,FALSE,64,1,0,0,0,0,"10 * 10-byte message [txn]"
+7,"L",1,1,0,1,0,10,10,10,10,FALSE,TRUE,FALSE,64,1,0,0,0,0,"1 * 10-byte message [txn transient]"
+8,"L",1,10,0,10,0,10,10,10,10,FALSE,TRUE,FALSE,64,1,0,0,0,0,"10 * 10-byte message [txn transient]"
+9,"L",1,1,0,1,0,10,10,0,0,TRUE,FALSE,FALSE,54,1,32,1,0,0,"1 * 10-byte message [deq]"
+10,"L",1,10,0,10,0,10,10,0,0,TRUE,FALSE,FALSE,54,1,32,1,0,0,"10 * 10-byte message [deq]"
+11,"L",1,1,0,1,0,10,10,0,0,TRUE,TRUE,FALSE,54,1,32,1,0,0,"1 * 10-byte message [deq transient]"
+12,"L",1,10,0,10,0,10,10,0,0,TRUE,TRUE,FALSE,54,1,32,1,0,0,"10 * 10-byte message [deq transient]"
+13,"L",1,1,0,1,0,10,10,10,10,TRUE,FALSE,FALSE,64,1,54,1,46,1,"1 * 10-byte message [deq txn]"
+14,"L",1,10,0,10,0,10,10,10,10,TRUE,FALSE,FALSE,64,1,54,1,46,1,"10 * 10-byte message [deq txn]"
+15,"L",1,1,0,1,0,10,10,10,10,TRUE,TRUE,FALSE,64,1,54,1,46,1,"1 * 10-byte message [txn deq transient]"
+16,"L",1,10,0,10,0,10,10,10,10,TRUE,TRUE,FALSE,64,1,54,1,46,1,"10 * 10-byte message [txn deq transient]"
+17,"L",1,1,0,1,0,10,10,0,0,FALSE,FALSE,TRUE,54,1,0,0,0,0,"1 * 10-byte message [extern]"
+18,"L",1,10,0,10,0,10,10,0,0,FALSE,FALSE,TRUE,54,1,0,0,0,0,"10 * 10-byte message [extern]"
+19,"L",1,1,0,1,0,10,10,0,0,FALSE,TRUE,TRUE,54,1,0,0,0,0,"1 * 10-byte message [transient extern]"
+20,"L",1,10,0,10,0,10,10,0,0,FALSE,TRUE,TRUE,54,1,0,0,0,0,"10 * 10-byte message [transient extern]"
+21,"L",1,1,0,1,0,10,10,10,10,FALSE,FALSE,TRUE,64,1,0,0,0,0,"1 * 10-byte message [txn extern]"
+22,"L",1,10,0,10,0,10,10,10,10,FALSE,FALSE,TRUE,64,1,0,0,0,0,"10 * 10-byte message [txn extern]"
+23,"L",1,1,0,1,0,10,10,10,10,FALSE,TRUE,TRUE,64,1,0,0,0,0,"1 * 10-byte message [txn transient extern]"
+24,"L",1,10,0,10,0,10,10,10,10,FALSE,TRUE,TRUE,64,1,0,0,0,0,"10 * 10-byte message [txn transient extern]"
+25,"L",1,1,0,1,0,10,10,0,0,TRUE,FALSE,TRUE,54,1,32,1,0,0,"1 * 10-byte message [deq extern]"
+26,"L",1,10,0,10,0,10,10,0,0,TRUE,FALSE,TRUE,54,1,32,1,0,0,"10 * 10-byte message [deq extern]"
+27,"L",1,1,0,1,0,10,10,0,0,TRUE,TRUE,TRUE,54,1,32,1,0,0,"1 * 10-byte message [deq transient extern]"
+28,"L",1,10,0,10,0,10,10,0,0,TRUE,TRUE,TRUE,54,1,32,1,0,0,"10 * 10-byte message [deq transient extern]"
+29,"L",1,1,0,1,0,10,10,10,10,TRUE,FALSE,TRUE,64,1,54,1,46,1,"1 * 10-byte message [deq txn extern]"
+30,"L",1,10,0,10,0,10,10,10,10,TRUE,FALSE,TRUE,64,1,54,1,46,1,"10 * 10-byte message [deq txn extern]"
+31,"L",1,1,0,1,0,10,10,10,10,TRUE,TRUE,TRUE,64,1,54,1,46,1,"1 * 10-byte message [txn deq transient extern]"
+32,"L",1,10,0,10,0,10,10,10,10,TRUE,TRUE,TRUE,64,1,54,1,46,1,"10 * 10-byte message [txn deq transient extern]"
+,,,,,,,,,,,,,,,,,,,,
+"Transition from one d-block to two per message",,,,,,,,,,,,,,,,,,,,
+33,"L",1,10,0,10,0,84,84,0,0,FALSE,FALSE,FALSE,128,1,0,0,0,0,"1 dblk exact fit"
+34,"L",1,10,0,10,1,85,85,0,0,FALSE,FALSE,FALSE,129,2,0,0,0,0,"1 dblk + 1 byte"
+35,"L",1,10,0,10,0,58,58,26,26,FALSE,FALSE,FALSE,128,1,0,0,0,0,"1 dblk exact fit [txn]"
+36,"L",1,10,0,10,1,59,59,26,26,FALSE,FALSE,FALSE,129,2,0,0,0,0,"1 dblk + 1 byte [txn]"
+,,,,,,,,,,,,,,,,,,,,
+"Transition from one s-block to two per message",,,,,,,,,,,,,,,,,,,,
+37,"L",1,10,0,10,0,468,468,0,0,FALSE,FALSE,FALSE,512,4,0,0,0,0,"1 sblk exact fit"
+38,"L",1,10,0,10,1,469,469,0,0,FALSE,FALSE,FALSE,513,5,0,0,0,0,"1 sblk + 1 byte"
+39,"L",1,10,0,10,0,442,442,26,26,FALSE,FALSE,FALSE,512,4,0,0,0,0,"1 sblk exact fit [txn]"
+40,"L",1,10,0,10,1,443,443,26,26,FALSE,FALSE,FALSE,513,5,0,0,0,0,"1 sblk + 1 byte [txn]"
+,,,,,,,,,,,,,,,,,,,,
+"Transition from first page to second",,,,,,,,,,,,,,,,,,,,
+41,"L",1,8,0,8,0,4052,4052,0,0,FALSE,FALSE,FALSE,4096,32,0,0,0,0,"1/8 page"
+42,"L",1,8,1,9,0,4052,4052,0,0,FALSE,FALSE,FALSE,4096,32,0,0,0,0,"1/8 page"
+43,"L",1,8,0,8,1,4053,4053,0,0,FALSE,FALSE,FALSE,4097,33,0,0,0,0,"1/8 page + 1 byte"
+44,"L",1,8,0,8,0,3796,3796,256,256,FALSE,FALSE,FALSE,4096,32,0,0,0,0,"1/8 page [txn]"
+45,"L",1,8,1,9,0,3796,3796,256,256,FALSE,FALSE,FALSE,4096,32,0,0,0,0,"1/8 page [txn]"
+46,"L",1,8,0,8,1,3797,3797,256,256,FALSE,FALSE,FALSE,4097,33,0,0,0,0,"1/8 page + 1 byte [txn]"
+47,"L",1,8,0,8,0,3924,3924,0,0,TRUE,FALSE,FALSE,3968,31,32,1,0,0,"1/8 page incl deq [deq]"
+48,"L",1,8,1,9,0,3924,3924,0,0,TRUE,FALSE,FALSE,3968,31,32,1,0,0,"1/8 page incl deq [deq]"
+49,"L",1,8,0,8,1,3925,3925,0,0,TRUE,FALSE,FALSE,3969,32,32,1,0,0,"1/8 page incl deq + 1 byte [deq]"
+50,"L",1,8,0,8,0,3028,3028,256,256,TRUE,FALSE,FALSE,3328,26,300,3,292,3,"1/8 page incl deq & txn [deq txn]"
+51,"L",1,8,1,9,0,3028,3028,256,256,TRUE,FALSE,FALSE,3328,26,300,3,292,3,"1/8 page incl deq & txn [deq txn]"
+52,"L",1,8,0,8,1,3029,3029,256,256,TRUE,FALSE,FALSE,3329,27,300,3,292,3,"1/8 page incl deq & txn + 1 byte [deq txn]"
+,,,,,,,,,,,,,,,,,,,,
+"Page cache rollover (from page 32 back to page 0)",,,,,,,,,,,,,,,,,,,,
+53,"L",1,32,0,32,0,32724,32724,0,0,FALSE,FALSE,FALSE,32768,256,0,0,0,0,"1 page"
+54,"L",1,32,1,33,0,32724,32724,0,0,FALSE,FALSE,FALSE,32768,256,0,0,0,0,"1 page"
+55,"L",1,32,0,32,1,32725,32725,0,0,FALSE,FALSE,FALSE,32769,257,0,0,0,0,"1 page + 1 byte"
+56,"L",1.5,22,0,22,0,49108,49108,0,0,FALSE,FALSE,FALSE,49152,384,0,0,0,0,"1.5 pages"
+57,"L",1,32,0,32,0,32468,32468,256,256,FALSE,FALSE,FALSE,32768,256,0,0,0,0,"1 page [txn]"
+58,"L",1,32,1,33,0,32468,32468,256,256,FALSE,FALSE,FALSE,32768,256,0,0,0,0,"1 page [txn]"
+59,"L",1,32,0,32,1,32469,32469,256,256,FALSE,FALSE,FALSE,32769,257,0,0,0,0,"1 page + 1 byte [txn]"
+60,"L",1.5,22,0,22,0,48852,48852,256,256,FALSE,FALSE,FALSE,49152,384,0,0,0,0,"1.5 pages [txn]"
+61,"L",1,32,0,32,0,32596,32596,0,0,TRUE,FALSE,FALSE,32640,255,32,1,0,0,"1 page incl deq [deq]"
+62,"L",1,32,1,33,0,32596,32596,0,0,TRUE,FALSE,FALSE,32640,255,32,1,0,0,"1 page incl deq [deq]"
+63,"L",1,32,0,32,1,32597,32597,0,0,TRUE,FALSE,FALSE,32641,256,32,1,0,0,"1 page incl deq + 1 byte [deq]"
+64,"L",1.5,22,0,22,0,48980,48980,0,0,TRUE,FALSE,FALSE,49024,383,32,1,0,0,"1.5 pages incl deq [deq]"
+65,"L",1,32,0,32,0,31700,31700,256,256,TRUE,FALSE,FALSE,32000,250,300,3,292,3,"1 page incl deq & txn [deq txn]"
+66,"L",1,32,1,33,0,31700,31700,256,256,TRUE,FALSE,FALSE,32000,250,300,3,292,3,"1 page incl deq & txn [deq txn]"
+67,"L",1,32,0,32,1,31701,31701,256,256,TRUE,FALSE,FALSE,32001,251,300,3,292,3,"1 page incl deq & txn + 1 byte [deq txn]"
+68,"L",1.5,22,0,22,0,48084,48084,256,256,TRUE,FALSE,FALSE,48384,378,300,3,292,3,"1.5 pages incl deq & txn [deq txn]"
+,,,,,,,,,,,,,,,,,,,,
+"File transition (from file 0000 to 0001)",,,,,,,,,,,,,,,,,,,,
+69,"L",1,48,0,48,0,32724,32724,0,0,FALSE,FALSE,FALSE,32768,256,0,0,0,0,"1 page"
+70,"L",1,48,1,49,0,32724,32724,0,0,FALSE,FALSE,FALSE,32768,256,0,0,0,0,"1 page"
+71,"L",1,48,0,48,1,32725,32725,0,0,FALSE,FALSE,FALSE,32769,257,0,0,0,0,"1 page + 1 byte"
+72,"L",2.5,20,0,20,0,81876,81876,0,0,FALSE,FALSE,FALSE,81920,640,0,0,0,0,"2.5 pages"
+73,"L",1,48,0,48,0,32468,32468,256,256,FALSE,FALSE,FALSE,32768,256,0,0,0,0,"1 page [txn]"
+74,"L",1,48,1,49,0,32468,32468,256,256,FALSE,FALSE,FALSE,32768,256,0,0,0,0,"1 page [txn]"
+75,"L",1,48,0,48,1,32469,32469,256,256,FALSE,FALSE,FALSE,32769,257,0,0,0,0,"1 page + 1 byte [txn]"
+76,"L",2.5,20,0,20,0,81620,81620,256,256,FALSE,FALSE,FALSE,81920,640,0,0,0,0,"2.5 pages [txn]"
+77,"L",1,48,0,48,0,32596,32596,0,0,TRUE,FALSE,FALSE,32640,255,32,1,0,0,"1 page incl deq [deq]"
+78,"L",1,48,1,49,0,32596,32596,0,0,TRUE,FALSE,FALSE,32640,255,32,1,0,0,"1 page incl deq [deq]"
+79,"L",1,48,0,48,1,32597,32597,0,0,TRUE,FALSE,FALSE,32641,256,32,1,0,0,"1 page incl deq + 1 byte [deq]"
+80,"L",2.5,20,0,20,0,81748,81748,0,0,TRUE,FALSE,FALSE,81792,639,32,1,0,0,"2.5 pages incl deq [deq]"
+81,"L",1,48,0,48,0,31700,31700,256,256,TRUE,FALSE,FALSE,32000,250,300,3,292,3,"1 page incl deq & txn [deq txn]"
+82,"L",1,48,1,49,0,31700,31700,256,256,TRUE,FALSE,FALSE,32000,250,300,3,292,3,"1 page incl deq & txn [deq txn]"
+83,"L",1,48,0,48,1,31701,31701,256,256,TRUE,FALSE,FALSE,32001,251,300,3,292,3,"1 page incl deq & txn + 1 byte [deq txn]"
+84,"L",2.5,20,0,20,0,80852,80852,256,256,TRUE,FALSE,FALSE,81152,634,300,3,292,3,"2.5 pages incl deq & txn [deq txn]"
+,,,,,,,,,,,,,,,,,,,,
+"File rollover (from file 0007 to 0000) - RHM_WRONLY req'd for auto-dequeue == FALSE",,,,,,,,,,,,,,,,,,,,
+85,"L",0.5,16,0,16,0,786260,786260,0,0,TRUE,FALSE,FALSE,786304,6143,32,1,0,0,"24 pages incl deq = ½ file [deq]"
+86,"L",0.5,16,1,17,0,786260,786260,0,0,TRUE,FALSE,FALSE,786304,6143,32,1,0,0,"24 pages incl deq = ½ file [deq]"
+87,"L",0.5,16,0,16,1,786261,786261,0,0,TRUE,FALSE,FALSE,786305,6144,32,1,0,0,"24 pages incl deq + 1 byte [deq]"
+88,"L",0.5,16,0,16,0,785364,785364,256,256,TRUE,FALSE,FALSE,785664,6138,300,3,292,3,"24 pages incl deq & txn = ½ file [deq txn]"
+89,"L",0.5,16,1,17,0,785364,785364,256,256,TRUE,FALSE,FALSE,785664,6138,300,3,292,3,"24 pages incl deq & txn = ½ file [deq txn]"
+90,"L",0.5,16,0,16,1,785365,785365,256,256,TRUE,FALSE,FALSE,785665,6139,300,3,292,3,"24 pages incl deq & txn + 1 byte [deq txn]"
+91,"L",0.25,32,0,32,0,786260,786260,0,0,TRUE,FALSE,FALSE,786304,6143,32,1,0,0,"24 pages incl deq = ½ file [deq]"
+92,"L",0.25,32,1,33,0,786260,786260,0,0,TRUE,FALSE,FALSE,786304,6143,32,1,0,0,"24 pages incl deq = ½ file [deq]"
+93,"L",0.25,32,0,32,1,786261,786261,0,0,TRUE,FALSE,FALSE,786305,6144,32,1,0,0,"24 pages incl deq + 1 byte [deq]"
+94,"L",0.25,32,0,32,0,785364,785364,256,256,TRUE,FALSE,FALSE,785664,6138,300,3,292,3,"24 pages incl deq & txn = ½ file [deq txn]"
+95,"L",0.25,32,1,33,0,785364,785364,256,256,TRUE,FALSE,FALSE,785664,6138,300,3,292,3,"24 pages incl deq & txn = ½ file [deq txn]"
+96,"L",0.25,32,0,32,1,785365,785365,256,256,TRUE,FALSE,FALSE,785665,6139,300,3,292,3,"24 pages incl deq & txn + 1 byte [deq txn]"
+,,,,,,,,,,,,,,,,,,,,
+"Multi-page messages (large messages) - tests various paths in encoder.",,,,,,,,,,,,,,,,,,,,
+97,"L",1,16,0,16,0,32724,32724,0,0,FALSE,FALSE,FALSE,32768,256,0,0,0,0,"data 1 page"
+98,"L",1,16,0,16,1,32725,32725,0,0,FALSE,FALSE,FALSE,32769,257,0,0,0,0,"data 1 page + 1 byte (tail split; 1 byte over page boundary)"
+99,"L",1,16,0,16,11,32735,32735,0,0,FALSE,FALSE,FALSE,32779,257,0,0,0,0,"data 1 page + 11 bytes (tail split; 11 bytes over page boundary)"
+100,"L",1,16,0,16,12,32736,32736,0,0,FALSE,FALSE,FALSE,32780,257,0,0,0,0,"data 1 page + 12 bytes (tail separated exactly onto next page)"
+101,"L",1,16,0,16,13,32737,32737,0,0,FALSE,FALSE,FALSE,32781,257,0,0,0,0,"data 1 page + 13 bytes (data split; 1 byte over page boundary)"
+102,"L",1,16,0,16,0,32468,32468,256,256,FALSE,FALSE,FALSE,32768,256,0,0,0,0,"data 1 page [txn]"
+103,"L",1,16,0,16,1,32469,32469,256,256,FALSE,FALSE,FALSE,32769,257,0,0,0,0,"data 1 page + 1 byte (tail split; 1 byte over page boundary) [txn]"
+104,"L",1,16,0,16,11,32479,32479,256,256,FALSE,FALSE,FALSE,32779,257,0,0,0,0,"data 1 page + 11 bytes (tail split; 11 bytes over page boundary) [txn]"
+105,"L",1,16,0,16,12,32480,32480,256,256,FALSE,FALSE,FALSE,32780,257,0,0,0,0,"data 1 page + 12 bytes (tail separated exactly onto next page) [txn]"
+106,"L",1,16,0,16,13,32481,32481,256,256,FALSE,FALSE,FALSE,32781,257,0,0,0,0,"data 1 page + 13 bytes (data split; 1 byte over page boundary) [txn]"
+107,"L",2,16,0,16,0,65492,65492,0,0,FALSE,FALSE,FALSE,65536,512,0,0,0,0,"data 2 pages"
+108,"L",2,16,0,16,1,65493,65493,0,0,FALSE,FALSE,FALSE,65537,513,0,0,0,0,"data 2 pages + 1 byte (tail split; 1 byte over page boundary)"
+109,"L",2,16,0,16,11,65503,65503,0,0,FALSE,FALSE,FALSE,65547,513,0,0,0,0,"data 2 pages + 11 bytes (tail split; 11 bytes over page boundary)"
+110,"L",2,16,0,16,12,65504,65504,0,0,FALSE,FALSE,FALSE,65548,513,0,0,0,0,"data 2 pages + 12 bytes (tail separated exactly onto next page)"
+111,"L",2,16,0,16,13,65505,65505,0,0,FALSE,FALSE,FALSE,65549,513,0,0,0,0,"data 2 pages + 13 bytes (data split; 1 byte over page boundary)"
+112,"L",2,16,0,16,0,65236,65236,256,256,FALSE,FALSE,FALSE,65536,512,0,0,0,0,"data 2 pages [txn]"
+113,"L",2,16,0,16,1,65237,65237,256,256,FALSE,FALSE,FALSE,65537,513,0,0,0,0,"data 2 pages + 1 byte (tail split; 1 byte over page boundary) [txn]"
+114,"L",2,16,0,16,11,65247,65247,256,256,FALSE,FALSE,FALSE,65547,513,0,0,0,0,"data 2 pages + 11 bytes (tail split; 11 bytes over page boundary) [txn]"
+115,"L",2,16,0,16,12,65248,65248,256,256,FALSE,FALSE,FALSE,65548,513,0,0,0,0,"data 2 pages + 12 bytes (tail separated exactly onto next page) [txn]"
+116,"L",2,16,0,16,13,65249,65249,256,256,FALSE,FALSE,FALSE,65549,513,0,0,0,0,"data 2 pages + 13 bytes (data split; 1 byte over page boundary) [txn]"
+117,"L",4,16,0,16,0,131028,131028,0,0,FALSE,FALSE,FALSE,131072,1024,0,0,0,0,"data 4 pages"
+118,"L",4,16,0,16,1,131029,131029,0,0,FALSE,FALSE,FALSE,131073,1025,0,0,0,0,"data 4 pages + 1 byte (tail split; 1 byte over page boundary)"
+119,"L",4,16,0,16,11,131039,131039,0,0,FALSE,FALSE,FALSE,131083,1025,0,0,0,0,"data 4 pages + 11 bytes (tail split; 11 bytes over page boundary)"
+120,"L",4,16,0,16,12,131040,131040,0,0,FALSE,FALSE,FALSE,131084,1025,0,0,0,0,"data 4 pages + 12 bytes (tail separated exactly onto next page)"
+121,"L",4,16,0,16,13,131041,131041,0,0,FALSE,FALSE,FALSE,131085,1025,0,0,0,0,"data 4 pages + 13 bytes (data split; 1 byte over page boundary)"
+122,"L",4,16,0,16,0,130772,130772,256,256,FALSE,FALSE,FALSE,131072,1024,0,0,0,0,"data 4 pages [txn]"
+123,"L",4,16,0,16,1,130773,130773,256,256,FALSE,FALSE,FALSE,131073,1025,0,0,0,0,"data 4 pages + 1 byte (tail split; 1 byte over page boundary) [txn]"
+124,"L",4,16,0,16,11,130783,130783,256,256,FALSE,FALSE,FALSE,131083,1025,0,0,0,0,"data 4 pages + 11 bytes (tail split; 11 bytes over page boundary) [txn]"
+125,"L",4,16,0,16,12,130784,130784,256,256,FALSE,FALSE,FALSE,131084,1025,0,0,0,0,"data 4 pages + 12 bytes (tail separated exactly onto next page) [txn]"
+126,"L",4,16,0,16,13,130785,130785,256,256,FALSE,FALSE,FALSE,131085,1025,0,0,0,0,"data 4 pages + 13 bytes (data split; 1 byte over page boundary) [txn]"
+127,"L",3.5,16,0,16,0,114644,114644,0,0,FALSE,FALSE,FALSE,114688,896,0,0,0,0,"data 3.5 pages"
+128,"L",3.5,16,0,16,1,114645,114645,0,0,FALSE,FALSE,FALSE,114689,897,0,0,0,0,"data 3.5 pages + 1 byte"
+129,"L",3.5,16,0,16,0,114388,114388,256,256,FALSE,FALSE,FALSE,114688,896,0,0,0,0,"data 3.5 pages [txn]"
+130,"L",3.5,16,0,16,1,114389,114389,256,256,FALSE,FALSE,FALSE,114689,897,0,0,0,0,"data 3.5 pages + 1 byte [txn]"
+131,"L",1,16,0,16,-1,10,10,32735,32735,FALSE,FALSE,FALSE,32789,257,0,0,0,0,"xid 1 page – 1 byte; data 10 bytes (exact fit) [txn]"
+132,"L",1,16,0,16,0,10,10,32736,32736,FALSE,FALSE,FALSE,32790,257,0,0,0,0,"xid 1 page; data 10 bytes (exact fit) [txn]"
+133,"L",1,16,0,16,1,10,10,32737,32737,FALSE,FALSE,FALSE,32791,257,0,0,0,0,"xid 1 page + 1 byte; data 10 bytes (exact fit) [txn]"
+134,"L",2,16,0,16,-1,10,10,65503,65503,FALSE,FALSE,FALSE,65557,513,0,0,0,0,"xid 2 pages – 1 byte; data 10 bytes (exact fit) [txn]"
+135,"L",2,16,0,16,0,10,10,65504,65504,FALSE,FALSE,FALSE,65558,513,0,0,0,0,"xid 2 pages; data 10 bytes (exact fit) [txn]"
+136,"L",2,16,0,16,1,10,10,65505,65505,FALSE,FALSE,FALSE,65559,513,0,0,0,0,"xid 2 pages + 1 byte; data 10 bytes (exact fit) [txn]"
+137,"L",4,16,0,16,-1,10,10,131039,131039,FALSE,FALSE,FALSE,131093,1025,0,0,0,0,"xid 4 pages – 1 byte; data 10 bytes (exact fit) [txn]"
+138,"L",4,16,0,16,0,10,10,131040,131040,FALSE,FALSE,FALSE,131094,1025,0,0,0,0,"xid 4 pages; data 10 bytes (exact fit) [txn]"
+139,"L",4,16,0,16,1,10,10,131041,131041,FALSE,FALSE,FALSE,131095,1025,0,0,0,0,"xid 4 pages + 1 byte; data 10 bytes (exact fit) [txn]"
+140,"L",3.5,16,0,16,0,10,10,114656,114656,FALSE,FALSE,FALSE,114710,897,0,0,0,0,"xid 3.5 pages; data 10 bytes (exact fit) [txn]"
+141,"L",3.5,16,0,16,1,10,10,114657,114657,FALSE,FALSE,FALSE,114711,897,0,0,0,0,"xid 3.5 pages + 1 byte; data 10 bytes (exact fit) [txn]"
+142,"L",1,16,0,16,-1,10,10,32735,32735,TRUE,FALSE,FALSE,32789,257,32779,257,32771,257,"xid 1 page – 1 byte for enq rec; data 10 bytes (exact fit) [deq, txn]"
+143,"L",1,16,0,16,0,10,10,32736,32736,TRUE,FALSE,FALSE,32790,257,32780,257,32772,257,"xid 1 page for enq rec; data 10 bytes (exact fit) [deq, txn]"
+144,"L",1,16,0,16,1,10,10,32737,32737,TRUE,FALSE,FALSE,32791,257,32781,257,32773,257,"xid 1 page + 1 byte for enq rec; data 10 bytes (exact fit) [deq, txn]"
+145,"L",2,16,0,16,-1,10,10,65503,65503,TRUE,FALSE,FALSE,65557,513,65547,513,65539,513,"xid 2 pages – 1 byte for enq rec; data 10 bytes (exact fit) [deq, txn]"
+146,"L",2,16,0,16,0,10,10,65504,65504,TRUE,FALSE,FALSE,65558,513,65548,513,65540,513,"xid 2 pages for enq rec; data 10 bytes (exact fit) [deq, txn]"
+147,"L",2,16,0,16,1,10,10,65505,65505,TRUE,FALSE,FALSE,65559,513,65549,513,65541,513,"xid 2 pages + 1 byte for enq rec; data 10 bytes (exact fit) [deq, txn]"
+148,"L",4,16,0,16,-1,10,10,131039,131039,TRUE,FALSE,FALSE,131093,1025,131083,1025,131075,1025,"xid 4 pages – 1 byte for enq rec; data 10 bytes (exact fit) [deq, txn]"
+149,"L",4,16,0,16,0,10,10,131040,131040,TRUE,FALSE,FALSE,131094,1025,131084,1025,131076,1025,"xid 4 pages for enq rec; data 10 bytes (exact fit) [deq, txn]"
+150,"L",4,16,0,16,1,10,10,131041,131041,TRUE,FALSE,FALSE,131095,1025,131085,1025,131077,1025,"xid 4 pages + 1 byte for enq rec; data 10 bytes (exact fit) [deq, txn]"
+151,"L",3.5,16,0,16,0,10,10,114656,114656,TRUE,FALSE,FALSE,114710,897,114700,897,114692,897,"xid 3.5 pages for enq rec; data 10 bytes (exact fit) [deq, txn]"
+152,"L",3.5,16,0,16,1,10,10,114657,114657,TRUE,FALSE,FALSE,114711,897,114701,897,114693,897,"xid 3.5 pages + 1 byte for enq rec; data 10 bytes (exact fit) [deq, txn]"
+153,"L",1,16,0,16,-1,10,10,32735,32735,TRUE,FALSE,FALSE,32789,257,32779,257,32771,257,"xid 1 page – 1 byte for deq rec; data 10 bytes (exact fit) [deq, txn]"
+154,"L",1,16,0,16,0,10,10,32736,32736,TRUE,FALSE,FALSE,32790,257,32780,257,32772,257,"xid 1 page for deq rec; data 10 bytes (exact fit) [deq, txn]"
+155,"L",1,16,0,16,1,10,10,32737,32737,TRUE,FALSE,FALSE,32791,257,32781,257,32773,257,"xid 1 page + 1 byte for deq rec; data 10 bytes (exact fit) [deq, txn]"
+156,"L",2,16,0,16,-1,10,10,65503,65503,TRUE,FALSE,FALSE,65557,513,65547,513,65539,513,"xid 2 pages – 1 byte for deq rec; data 10 bytes (exact fit) [deq, txn]"
+157,"L",2,16,0,16,0,10,10,65504,65504,TRUE,FALSE,FALSE,65558,513,65548,513,65540,513,"xid 2 pages for deq rec; data 10 bytes (exact fit) [deq, txn]"
+158,"L",2,16,0,16,1,10,10,65505,65505,TRUE,FALSE,FALSE,65559,513,65549,513,65541,513,"xid 2 pages + 1 byte for deq rec; data 10 bytes (exact fit) [deq, txn]"
+159,"L",4,16,0,16,-1,10,10,131039,131039,TRUE,FALSE,FALSE,131093,1025,131083,1025,131075,1025,"xid 4 pages – 1 byte for deq rec; data 10 bytes (exact fit) [deq, txn]"
+160,"L",4,16,0,16,0,10,10,131040,131040,TRUE,FALSE,FALSE,131094,1025,131084,1025,131076,1025,"xid 4 pages for deq rec; data 10 bytes (exact fit) [deq, txn]"
+161,"L",4,16,0,16,1,10,10,131041,131041,TRUE,FALSE,FALSE,131095,1025,131085,1025,131077,1025,"xid 4 pages + 1 byte for deq rec; data 10 bytes (exact fit) [deq, txn]"
+162,"L",3.5,16,0,16,0,10,10,114656,114656,TRUE,FALSE,FALSE,114710,897,114700,897,114692,897,"xid 3.5 pages for deq rec; data 10 bytes (exact fit) [deq, txn]"
+163,"L",3.5,16,0,16,1,10,10,114657,114657,TRUE,FALSE,FALSE,114711,897,114701,897,114693,897,"xid 3.5 pages + 1 byte for deq rec; data 10 bytes (exact fit) [deq, txn]"
+164,"L",1,16,0,16,-1,10,10,32743,32743,TRUE,FALSE,FALSE,32797,257,32787,257,32779,257,"xid 1 page – 1 byte for txn rec; data 10 bytes (exact fit) [deq, txn]"
+165,"L",1,16,0,16,0,10,10,32744,32744,TRUE,FALSE,FALSE,32798,257,32788,257,32780,257,"xid 1 page for txn rec; data 10 bytes (exact fit) [deq, txn]"
+166,"L",1,16,0,16,1,10,10,32745,32745,TRUE,FALSE,FALSE,32799,257,32789,257,32781,257,"xid 1 page + 1 byte for txn rec; data 10 bytes (exact fit) [deq, txn]"
+167,"L",2,16,0,16,-1,10,10,65511,65511,TRUE,FALSE,FALSE,65565,513,65555,513,65547,513,"xid 2 pages – 1 byte for txn rec; data 10 bytes (exact fit) [deq, txn]"
+168,"L",2,16,0,16,0,10,10,65512,65512,TRUE,FALSE,FALSE,65566,513,65556,513,65548,513,"xid 2 pages for txn rec; data 10 bytes (exact fit) [deq, txn]"
+169,"L",2,16,0,16,1,10,10,65513,65513,TRUE,FALSE,FALSE,65567,513,65557,513,65549,513,"xid 2 pages + 1 byte for txn rec; data 10 bytes (exact fit) [deq, txn]"
+170,"L",4,16,0,16,-1,10,10,131047,131047,TRUE,FALSE,FALSE,131101,1025,131091,1025,131083,1025,"xid 4 pages – 1 byte for txn rec; data 10 bytes (exact fit) [deq, txn]"
+171,"L",4,16,0,16,0,10,10,131048,131048,TRUE,FALSE,FALSE,131102,1025,131092,1025,131084,1025,"xid 4 pages for txn rec; data 10 bytes (exact fit) [deq, txn]"
+172,"L",4,16,0,16,1,10,10,131049,131049,TRUE,FALSE,FALSE,131103,1025,131093,1025,131085,1025,"xid 4 pages + 1 byte for txn rec; data 10 bytes (exact fit) [deq, txn]"
+173,"L",3.5,16,0,16,0,10,10,114664,114664,TRUE,FALSE,FALSE,114718,897,114708,897,114700,897,"xid 3.5 pages for txn rec; data 10 bytes (exact fit) [deq, txn]"
+174,"L",3.5,16,0,16,1,10,10,114665,114665,TRUE,FALSE,FALSE,114719,897,114709,897,114701,897,"xid 3.5 pages + 1 byte for txn rec; data 10 bytes (exact fit) [deq, txn]"
+,,,,,,,,,,,,,,,,,,,,
+"High volume tests of random message lengths - RHM_WRONLY req'd for auto-dequeue == FALSE",,,,,,,,,,,,,,,,,,,,
+#175,"M",1,5000000,0,5000000,0,0,84,0,0,TRUE,FALSE,FALSE,128,1,32,1,0,0,"1 dblk max [deq]"
+#176,"M",3,3000000,0,3000000,0,0,340,0,0,TRUE,FALSE,FALSE,384,3,32,1,0,0,"3 dblks max [deq]"
+#177,"M",10,1600000,0,1600000,0,0,1236,0,0,TRUE,FALSE,FALSE,1280,10,32,1,0,0,"10 dblks max [deq]"
+#178,"M",30,600000,0,600000,0,0,3796,0,0,TRUE,FALSE,FALSE,3840,30,32,1,0,0,"30 dblks max [deq]"
+#179,"M",100,200000,0,200000,0,0,12756,0,0,TRUE,FALSE,FALSE,12800,100,32,1,0,0,"100 dblks max [deq]"
+#180,"M",300,60000,0,60000,0,0,38356,0,0,TRUE,FALSE,FALSE,38400,300,32,1,0,0,"300 dblks max [deq]"
+#181,"M",1000,20000,0,20000,0,0,127956,0,0,TRUE,FALSE,FALSE,128000,1000,32,1,0,0,"1000 dblks max [deq]"
+#182,"M",1,5000000,0,5000000,0,0,100,1,100,TRUE,FALSE,FALSE,244,2,144,2,136,2,"100 bytes xid max + 100 bytes data max [deq txn]"
+#183,"M",3,3000000,0,3000000,0,0,300,1,300,TRUE,FALSE,FALSE,644,6,344,3,336,3,"300 bytes xid max + 300 bytes data max [deq txn]"
+#184,"M",10,1600000,0,1600000,0,0,1000,1,1000,TRUE,FALSE,FALSE,2044,16,1044,9,1036,9,"1000 bytes xid max + 1000 bytes data max [deq txn]"
+#185,"M",30,600000,0,600000,0,0,3000,1,3000,TRUE,FALSE,FALSE,6044,48,3044,24,3036,24,"3000 bytes xid max + 3000 bytes data max [deq txn]"
+#186,"M",100,200000,0,200000,0,0,10000,1,10000,TRUE,FALSE,FALSE,20044,157,10044,79,10036,79,"10000 bytes xid max + 10000 bytes data max [deq txn]"
+#187,"M",300,60000,0,60000,0,0,30000,1,30000,TRUE,FALSE,FALSE,60044,470,30044,235,30036,235,"30000 bytes xid max + 30000 bytes data max [deq txn]"
+#188,"M",1000,20000,0,20000,0,0,100000,1,100000,TRUE,FALSE,FALSE,200044,1563,100044,782,100036,782,"100000 bytes xid max + 100000 bytes data max [deq txn]"
+,,,,,,,,,,,,,,,,,,,,
+"STANDARD PERFORMANCE BENCHMARK: 10,000,000 writes, data=212b (2 dblks)",,,,,,,,,,,,,,,,,,,,
+#189,"M",1,10000000,0,10000000,0,212,212,0,0,TRUE,FALSE,FALSE,256,2,32,1,0,0,"212 bytes data (2 dblks enq + 1 dblk deq)"
+#190,"M",1,10000000,0,10000000,0,148,148,64,64,TRUE,FALSE,FALSE,256,2,108,1,100,1,"148 bytes data + 64 bytes xid (2 dblks enq + 1 dblks deq + 1 dblks txn)"
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/main.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/main.cpp
new file mode 100644
index 0000000000..c8a4642b1c
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/main.cpp
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "test_mgr.h"
+
+#include "args.h"
+#include <csignal>
+#include <iostream>
+
+#define PACKAGE_NAME "Journal Test Tool"
+#define VERSION "0.1"
+
+namespace po = boost::program_options;
+
+int main(int argc, char** argv)
+{
+ std::signal(SIGINT, mrg::jtt::test_mgr::signal_handler);
+ std::signal(SIGTERM, mrg::jtt::test_mgr::signal_handler);
+
+ std::cout << PACKAGE_NAME << " v." << VERSION << std::endl;
+
+ std::ostringstream oss;
+ oss << PACKAGE_NAME << " options";
+ mrg::jtt::args args(oss.str());
+ if (args.parse(argc, argv)) return 1;
+
+ try
+ {
+ mrg::jtt::test_mgr tm(args);
+ tm.run();
+ if (tm.error()) return 2; // One or more tests threw exceptions
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what() << std::endl;
+ return 3;
+ }
+ return 0;
+}
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/read_arg.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/read_arg.cpp
new file mode 100644
index 0000000000..94a07c7005
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/read_arg.cpp
@@ -0,0 +1,93 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "read_arg.h"
+
+#include <cassert>
+#include <boost/program_options.hpp>
+namespace po = boost::program_options;
+
+namespace mrg
+{
+namespace jtt
+{
+std::map<std::string, read_arg::read_mode_t> read_arg::_map;
+std::string read_arg::_description;
+const bool read_arg::init = __init();
+
+// static init fn
+bool
+read_arg::__init()
+{
+ // Set string versions of each enum option here
+ _map["NONE"] = NONE;
+ _map["ALL"] = ALL;
+ _map["RANDOM"] = RANDOM;
+ _map["LAZYLOAD"] = LAZYLOAD;
+ _description = "Determines if and when messages will be read prior to dequeueing. "
+ "Values: (NONE | ALL | RANDOM | LAZYLOAD)";
+ return true;
+}
+
+void
+read_arg::parse(const std::string& str)
+{
+ std::map<std::string, read_arg::read_mode_t>::const_iterator i = _map.find(str);
+ if (i == _map.end())
+ throw po::invalid_option_value(str);
+ _rm = i->second;
+}
+
+// static fn
+const std::string&
+read_arg::str(const read_mode_t rm)
+{
+ std::map<std::string, read_mode_t>::const_iterator i = _map.begin();
+ while (i->second != rm && i != _map.end()) i++;
+ assert(i != _map.end());
+ return i->first;
+}
+
+// static fn
+const std::string&
+read_arg::descr()
+{
+ return _description;
+}
+
+std::ostream&
+operator<<(std::ostream& os, const read_arg& ra)
+{
+ os << ra.str();
+ return os;
+}
+
+std::istream&
+operator>>(std::istream& is, read_arg& ra)
+{
+ std::string s;
+ is >> s;
+ ra.parse(s);
+ return is;
+}
+
+} // namespace jtt
+} // namespace mrg
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/read_arg.h b/qpid/cpp/src/tests/legacystore/jrnl/jtt/read_arg.h
new file mode 100644
index 0000000000..a8fd6f198e
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/read_arg.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef mrg_jtt_read_arg_hpp
+#define mrg_jtt_read_arg_hpp
+
+#include <string>
+#include <map>
+
+namespace mrg
+{
+namespace jtt
+{
+
+class read_arg
+{
+ public:
+ enum read_mode_t { NONE, ALL, RANDOM, LAZYLOAD};
+ private:
+ static std::map<std::string, read_mode_t> _map;
+ static std::string _description;
+ static const bool init;
+ static bool __init();
+ read_mode_t _rm;
+ public:
+ inline read_arg() : _rm(NONE) {}
+ inline read_arg(read_mode_t rm) : _rm(rm) {}
+
+ inline read_mode_t val() const { return _rm; }
+ inline void set_val(const read_mode_t rm) { _rm = rm; }
+ void parse(const std::string& str);
+
+ inline const std::string& str() const { return str(_rm); }
+ static const std::string& str(const read_mode_t rm);
+ static const std::string& descr();
+
+ friend std::ostream& operator<<(std::ostream& os, const read_arg& ra);
+ friend std::istream& operator>>(std::istream& is, read_arg& ra);
+};
+
+} // namespace jtt
+} // namespace mrg
+
+#endif // ifndef mrg_jtt_read_arg_hpp
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case.cpp
new file mode 100644
index 0000000000..e06e053504
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case.cpp
@@ -0,0 +1,179 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "test_case.h"
+
+#include <cstdlib>
+#include <iomanip>
+#include <sstream>
+
+namespace mrg
+{
+namespace jtt
+{
+
+test_case::test_case(const unsigned test_case_num, const u_int32_t num_msgs,
+ const std::size_t min_data_size, const std::size_t max_data_size, const bool auto_deq,
+ const std::size_t min_xid_size, const std::size_t max_xid_size, const transient_t transient,
+ const external_t external, const std::string& comment):
+ _test_case_num(test_case_num),
+ _num_msgs(num_msgs),
+ _min_data_size(min_data_size),
+ _max_data_size(max_data_size),
+ _auto_dequeue(auto_deq),
+ _min_xid_size(min_xid_size),
+ _max_xid_size(max_xid_size),
+ _transient(transient),
+ _external(external),
+ _comment(comment),
+ _result_average(),
+ _result_jmap()
+{}
+
+test_case::~test_case()
+{}
+
+std::size_t
+test_case::this_data_size() const
+{
+ if (_min_data_size == _max_data_size)
+ return _max_data_size;
+ std::size_t size_diff = _max_data_size - _min_data_size;
+ return _min_data_size + std::size_t(1.0 * std::rand() * size_diff/(RAND_MAX + 1.0));
+}
+
+std::size_t
+test_case::this_xid_size() const
+{
+ // TODO: rework when probabilities are introduced. Assume 50% if _min_xid_size = 0
+ if (_max_xid_size == 0)
+ return std::size_t(0);
+ if (_min_xid_size == 0)
+ {
+ if (1.0 * std::rand() / RAND_MAX < 0.5)
+ return std::size_t(0);
+ }
+ std::size_t size_diff = _max_xid_size - _min_xid_size;
+ return _min_xid_size + std::size_t(1.0 * std::rand() * size_diff/(RAND_MAX + 1.0));
+}
+
+bool
+test_case::this_transience() const
+{
+ // TODO: rework when probabilities are introduced. Assume 50% if JTT_RANDOM
+ if (_transient == JTT_TRANSIENT)
+ return false;
+ if (_transient == JTT_PERSISTNET)
+ return true;
+ return 1.0 * std::rand() / RAND_MAX < 0.5;
+}
+
+bool
+test_case::this_external() const
+{
+ // TODO: rework when probabilities are introduced. Assume 50% if JDL_RANDOM
+ if (_external == JDL_INTERNAL)
+ return false;
+ if (_external == JDL_EXTERNAL)
+ return true;
+ return 1.0 * std::rand() / RAND_MAX < 0.5;
+}
+
+void
+test_case::add_result(test_case_result::shared_ptr& tcrp)
+{
+ _result_average.add_test_result(tcrp);
+ res_map_citr ari = _result_jmap.find(tcrp->jid());
+ if (ari == _result_jmap.end())
+ {
+ test_case_result_agregation::shared_ptr p(new test_case_result_agregation(tcrp->jid()));
+ p->add_test_result(tcrp);
+ _result_jmap.insert(res_map_pair(tcrp->jid(), p));
+ }
+ else
+ ari->second->add_test_result(tcrp);
+}
+
+void
+test_case::set_fmt_chk_res(const bool res, const std::string& jid)
+{
+ _result_average.set_fmt_chk_res(res);
+ res_map_citr ari = _result_jmap.find(jid);
+ if (ari != _result_jmap.end())
+ ari->second->set_fmt_chk_res(res);
+}
+
+const test_case_result::shared_ptr
+test_case::jmap_last(std::string& jid) const
+{
+ res_map_citr i = _result_jmap.find(jid);
+ if (i == _result_jmap.end())
+ return test_case_result::shared_ptr();
+ u_int32_t num_res = (*i).second->num_results();
+ if (num_res)
+ return (*(*i).second)[num_res - 1];
+ return test_case_result::shared_ptr();
+}
+
+void
+test_case::clear()
+{
+ _result_average.clear();
+ _result_jmap.clear();
+}
+
+const std::string
+test_case::str() const
+{
+ std::ostringstream oss;
+ oss << "Test Parameters: Test case no. " << _test_case_num << ":" << std::endl;
+ oss << " Comment: " << _comment << std::endl;
+ oss << " Number of messages: " << _num_msgs << std::endl;
+ oss << " Data size: " << _min_data_size;
+ if (_min_data_size == _max_data_size)
+ oss << " bytes (fixed)" << std::endl;
+ else
+ oss << " - " << _max_data_size << " bytes" << std::endl;
+ oss << " XID size: " << _min_xid_size;
+ if (_min_xid_size == _max_xid_size)
+ oss << " bytes (fixed)" << std::endl;
+ else
+ oss << " - " << _max_xid_size << " bytes" << std::endl;
+ oss << " Auto-dequeue: " << (_auto_dequeue ? "true" : "false") << std::endl;
+ oss << " Persistence: ";
+ switch (_transient)
+ {
+ case JTT_TRANSIENT: oss << "TRANSIENT" << std::endl; break;
+ case JTT_PERSISTNET: oss << "PERSISTNET" << std::endl; break;
+ case JTT_RANDOM: oss << "RANDOM" << std::endl; break;
+ }
+ oss << " Message Data: ";
+ switch (_external)
+ {
+ case JDL_INTERNAL: oss << "INTERNAL"; break;
+ case JDL_EXTERNAL: oss << "EXTERNAL"; break;
+ case JDL_RANDOM: oss << "RANDOM"; break;
+ }
+ return oss.str();
+}
+
+} // namespace jtt
+} // namespace mrg
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case.h b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case.h
new file mode 100644
index 0000000000..f72dd05f0c
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case.h
@@ -0,0 +1,110 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef mrg_jtt_test_case_hpp
+#define mrg_jtt_test_case_hpp
+
+#include <boost/shared_ptr.hpp>
+#include <cstddef>
+#include <map>
+#include "test_case_result.h"
+#include "test_case_result_agregation.h"
+#include <vector>
+
+namespace mrg
+{
+namespace jtt
+{
+
+ class test_case
+ {
+ public:
+ enum transient_type { JTT_TRANSIENT = 0, JTT_PERSISTNET, JTT_RANDOM };
+ typedef transient_type transient_t;
+
+ enum data_location { JDL_INTERNAL = 0, JDL_EXTERNAL, JDL_RANDOM };
+ typedef data_location external_t;
+
+ typedef boost::shared_ptr<test_case> shared_ptr;
+
+ typedef std::map<std::string, test_case_result_agregation::shared_ptr> res_map;
+ typedef std::pair<std::string, test_case_result_agregation::shared_ptr> res_map_pair;
+ typedef res_map::const_iterator res_map_citr;
+
+ private:
+ unsigned _test_case_num;
+ u_int32_t _num_msgs;
+ std::size_t _min_data_size;
+ std::size_t _max_data_size;
+ bool _auto_dequeue;
+ // TODO: add probability of transaction to these params
+ std::size_t _min_xid_size;
+ std::size_t _max_xid_size;
+ // TODO: change these enums (transient_t & external_t) to probabilities
+ transient_t _transient;
+ external_t _external;
+ std::string _comment;
+
+ test_case_result_agregation _result_average; // overall average result
+ res_map _result_jmap; // map of per-journal averages
+
+ public:
+ test_case(const unsigned test_case_num, const u_int32_t num_msgs,
+ const std::size_t min_data_size, const std::size_t max_data_size,
+ const bool auto_deq, const std::size_t min_xid_size,
+ const std::size_t max_xid_size, const transient_t transient,
+ const external_t external, const std::string& comment);
+ virtual ~test_case();
+
+ inline unsigned test_case_num() const { return _test_case_num; }
+ inline u_int32_t num_msgs() const { return _num_msgs; }
+ inline std::size_t min_data_size() const { return _min_data_size; }
+ inline std::size_t max_data_size() const { return _max_data_size; }
+ std::size_t this_data_size() const;
+ inline bool auto_deq() const { return _auto_dequeue; }
+ inline std::size_t min_xid_size() const { return _min_xid_size; }
+ inline std::size_t max_xid_size() const { return _max_xid_size; }
+ std::size_t this_xid_size() const;
+ inline transient_t transient() const { return _transient; }
+ bool this_transience() const;
+ inline external_t external() const { return _external; }
+ bool this_external() const;
+ inline const std::string& comment() const { return _comment; }
+
+ void add_result(test_case_result::shared_ptr& p);
+ void set_fmt_chk_res(const bool res, const std::string& jid);
+
+ inline const test_case_result_agregation& average() const { return _result_average; }
+ inline u_int32_t num_results() const { return _result_average.num_results(); }
+ inline unsigned num_jrnls() const { return _result_jmap.size(); }
+ inline res_map_citr jrnl_average(std::string& jid) const { return _result_jmap.find(jid); }
+ inline res_map_citr jmap_begin() const { return _result_jmap.begin(); }
+ inline res_map_citr jmap_end() const { return _result_jmap.end(); }
+ const test_case_result::shared_ptr jmap_last(std::string& jid) const;
+
+ void clear();
+ const std::string str() const;
+ };
+
+} // namespace jtt
+} // namespace mrg
+
+#endif // ifndef mrg_jtt_test_case_hpp
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_result.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_result.cpp
new file mode 100644
index 0000000000..2f88f265a5
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_result.cpp
@@ -0,0 +1,201 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "test_case_result.h"
+
+#include <iomanip>
+#include <sstream>
+
+namespace mrg
+{
+namespace jtt
+{
+
+test_case_result::test_case_result(const std::string& jid):
+ _jid(jid),
+ _num_enq(0),
+ _num_deq(0),
+ _num_read(0),
+ _num_rproc(0),
+ _start_time(),
+ _stop_time(),
+ _stopped(false),
+ _test_time(),
+ _exception_list()
+{}
+
+test_case_result::~test_case_result()
+{}
+
+const std::string
+test_case_result::test_time_str() const
+{
+ return _test_time.str(9);
+}
+
+void
+test_case_result::add_exception(const journal::jexception& e, const bool set_stop_time_flag)
+{
+ if (!_stopped && set_stop_time_flag)
+ {
+ set_stop_time();
+ _stopped = true;
+ }
+ _exception_list.push_back(e.what());
+}
+
+void
+test_case_result::add_exception(const std::string& err_str, const bool set_stop_time_flag)
+{
+ if (!_stopped && set_stop_time_flag)
+ {
+ set_stop_time();
+ _stopped = true;
+ }
+ _exception_list.push_back(err_str);
+}
+
+void
+test_case_result::add_exception(const char* err_str, const bool set_stop_time_flag)
+{
+ if (!_stopped && set_stop_time_flag)
+ {
+ set_stop_time();
+ _stopped = true;
+ }
+ _exception_list.push_back(err_str);
+}
+
+void
+test_case_result::clear()
+{
+ _num_enq = 0;
+ _num_deq = 0;
+ _num_read = 0;
+ _start_time.set_zero();
+ _stop_time.set_zero();
+ _test_time.set_zero();
+ _exception_list.clear();
+}
+
+const std::string
+test_case_result::str(const bool summary) const
+{
+ std::ostringstream oss;
+ if (summary)
+ {
+ oss << _jid << ":";
+ oss << str_summary();
+ if (_exception_list.size())
+ oss << "; fail: " << _exception_list[0] << std::endl;
+ else
+ oss << "; ok" << std::endl;
+ }
+ else
+ {
+ oss << "--- Journal instance: jid=\"" << _jid << "\" ---" << std::endl;
+ oss << str_full();
+ if (_exception_list.size())
+ oss << " exception/error:" << _exception_list[0] << std::endl;
+ }
+ return oss.str();
+}
+
+const std::string
+test_case_result::str_full() const
+{
+ const double t = _test_time.tv_sec + (_test_time.tv_nsec/1e9);
+ const bool no_exception = _exception_list.empty();
+ std::ostringstream oss;
+ oss.setf(std::ios::fixed, std::ios::floatfield);
+ oss.precision(2);
+ if (no_exception)
+ {
+ oss.precision(6);
+ oss << " total test time: " << t << "s" << std::endl;
+ }
+ oss.precision(3);
+ oss << " total number enqueues: " << _num_enq;
+ if (no_exception)
+ oss << " (" << (_num_enq / t) << " enq/sec)";
+ oss << std::endl;
+ oss << " total number dequeues: " << _num_deq;
+ if (no_exception)
+ oss << " (" << (_num_deq / t) << " deq/sec)";
+ oss << std::endl;
+ oss << "total write operations: " << (_num_enq + _num_deq);
+ if (no_exception)
+ oss << " (" << ((_num_enq + _num_deq) / t) << " wrops/sec)";
+ oss << std::endl;
+ oss << " total number reads: " << _num_read;
+ if (no_exception)
+ oss << " (" << (_num_read / t) << " rd/sec)";
+ oss << std::endl;
+ oss << " total operations: " << (_num_enq + _num_deq + _num_read);
+ if (no_exception)
+ oss << " (" << ((_num_enq + _num_deq + _num_read) / t) << " ops/sec)";
+ oss << std::endl;
+ oss << " overall result: " << (no_exception ? "PASS" : "*** FAIL ***") << std::endl;
+ return oss.str();
+}
+
+const std::string
+test_case_result::str_summary() const
+{
+ const double t = _test_time.tv_sec + (_test_time.tv_nsec/1e9);
+ const bool no_exception = _exception_list.empty();
+ std::ostringstream oss;
+ oss.setf(std::ios::fixed, std::ios::floatfield);
+ if (no_exception)
+ {
+ oss.precision(6);
+ oss << " t=" << t << "s;";
+ }
+ else
+ oss << " exception";
+ oss.precision(3);
+ oss << " enq=" << _num_enq;
+ if (no_exception)
+ oss << " (" << (_num_enq / t) << ")";
+ oss << "; deq=" << _num_deq;
+ if (no_exception)
+ oss << " (" << (_num_deq / t) << ")";
+ oss << "; wr=" << (_num_enq + _num_deq);
+ if (no_exception)
+ oss << " (" << ((_num_enq + _num_deq) / t) << ")";
+ oss << "; rd=" << _num_read;
+ if (no_exception)
+ oss << " (" << (_num_read / t) << ")";
+ oss << "; tot=" << (_num_enq + _num_deq + _num_read);
+ if (no_exception)
+ oss << " (" << ((_num_enq + _num_deq + _num_read) / t) << ")";
+ return oss.str();
+}
+
+void
+test_case_result::calc_test_time()
+{
+ if (!_start_time.is_zero() && _stop_time >= _start_time)
+ _test_time = _stop_time - _start_time;
+}
+
+} // namespace jtt
+} // namespace mrg
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_result.h b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_result.h
new file mode 100644
index 0000000000..d15f9d021d
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_result.h
@@ -0,0 +1,100 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef mrg_jtt_test_case_result_hpp
+#define mrg_jtt_test_case_result_hpp
+
+#include <boost/shared_ptr.hpp>
+#include <deque>
+#include "qpid/legacystore/jrnl/jexception.h"
+#include "qpid/legacystore/jrnl/time_ns.h"
+#include <string>
+
+namespace mrg
+{
+namespace jtt
+{
+
+ class test_case_result
+ {
+ public:
+ typedef boost::shared_ptr<test_case_result> shared_ptr;
+
+ typedef std::deque<std::string> elist;
+ typedef elist::const_iterator elist_citr;
+
+ protected:
+ std::string _jid;
+ u_int32_t _num_enq;
+ u_int32_t _num_deq;
+ u_int32_t _num_read; // Messages actually read
+ u_int32_t _num_rproc; // Messages handled by read thread (not all are read)
+ journal::time_ns _start_time;
+ journal::time_ns _stop_time;
+ bool _stopped;
+ journal::time_ns _test_time;
+ elist _exception_list;
+
+ public:
+ test_case_result(const std::string& jid);
+ virtual ~test_case_result();
+
+ inline const std::string& jid() const { return _jid; }
+ inline u_int32_t num_enq() const { return _num_enq; }
+ inline u_int32_t incr_num_enq() { return ++_num_enq; }
+ inline u_int32_t num_deq() const { return _num_deq; }
+ inline u_int32_t incr_num_deq() { return ++_num_deq; }
+ inline u_int32_t num_read() const { return _num_read; }
+ inline u_int32_t incr_num_read() { return ++_num_read; }
+ inline u_int32_t num_rproc() const { return _num_rproc; }
+ inline u_int32_t incr_num_rproc() { return ++_num_rproc; }
+
+ inline const journal::time_ns& start_time() const { return _start_time; }
+ inline void set_start_time() { ::clock_gettime(CLOCK_REALTIME, &_start_time); }
+ inline const journal::time_ns& stop_time() const { return _stop_time; }
+ inline void set_stop_time()
+ { ::clock_gettime(CLOCK_REALTIME, &_stop_time); calc_test_time(); }
+ inline void set_test_time(const journal::time_ns& ts) { _test_time = ts; }
+ inline const journal::time_ns& test_time() const { return _test_time; }
+ const std::string test_time_str() const;
+
+ void add_exception(const journal::jexception& e, const bool set_stop_time_flag = true);
+ void add_exception(const std::string& err_str, const bool set_stop_time_flag = true);
+ void add_exception(const char* err_str, const bool set_stop_time_flag = true);
+ inline bool exception() const { return _exception_list.size() > 0; }
+ inline unsigned exception_count() const { return _exception_list.size(); }
+ inline elist_citr begin() { return _exception_list.begin(); }
+ inline elist_citr end() { return _exception_list.end(); }
+ inline const std::string& operator[](unsigned i) { return _exception_list[i]; }
+
+ void clear();
+ const std::string str(const bool summary) const;
+
+ protected:
+ const std::string str_full() const;
+ const std::string str_summary() const;
+ void calc_test_time();
+ };
+
+} // namespace jtt
+} // namespace mrg
+
+#endif // ifndef mrg_jtt_test_case_result_hpp
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_result_agregation.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_result_agregation.cpp
new file mode 100644
index 0000000000..da439e71e8
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_result_agregation.cpp
@@ -0,0 +1,185 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "test_case_result_agregation.h"
+
+#include <iomanip>
+#include <sstream>
+
+namespace mrg
+{
+namespace jtt
+{
+
+test_case_result_agregation::test_case_result_agregation():
+ test_case_result("Average"),
+ _tc_average(true),
+ _fmt_chk_done(false),
+ _fmt_chk_err(false),
+ _res_list()
+{
+}
+
+test_case_result_agregation::test_case_result_agregation(const std::string& jid):
+ test_case_result(jid),
+ _tc_average(false),
+ _fmt_chk_done(false),
+ _fmt_chk_err(false),
+ _res_list()
+{}
+
+test_case_result_agregation::~test_case_result_agregation()
+{}
+
+void
+test_case_result_agregation::add_test_result(const test_case_result::shared_ptr& tcrp)
+{
+ if (_tc_average || _jid.compare(tcrp->jid()) == 0)
+ {
+ _num_enq += tcrp->num_enq();
+ _num_deq += tcrp->num_deq();
+ _num_read += tcrp->num_read();
+ add_test_time(tcrp->test_time());
+ _exception_list.insert(_exception_list.end(), tcrp->begin(), tcrp->end());
+ _res_list.push_back(tcrp);
+ }
+}
+
+bool
+test_case_result_agregation::exception() const
+{
+ for (tcrp_list_citr i = _res_list.begin(); i < _res_list.end(); i++)
+ if ((*i)->exception())
+ return true;
+ return false;
+}
+
+unsigned
+test_case_result_agregation::exception_count() const
+{
+ unsigned cnt = 0;
+ for (tcrp_list_citr i = _res_list.begin(); i < _res_list.end(); i++)
+ cnt += (*i)->exception_count();
+ return cnt;
+}
+
+void
+test_case_result_agregation::clear()
+{
+ test_case_result::clear();
+ _res_list.clear();
+}
+
+const std::string
+test_case_result_agregation::str(const bool last_only, const bool summary) const
+{
+ std::ostringstream oss;
+ if (last_only)
+ oss << " " << _res_list.at(_res_list.size()-1)->str(summary);
+ else
+ {
+ for (tcrp_list_citr i=_res_list.begin(); i!=_res_list.end(); i++)
+ oss << " " << (*i)->str(summary);
+ }
+ if (_res_list.size() > 1)
+ oss << " " << (summary ? str_summary(last_only) : str_full(last_only));
+ return oss.str();
+}
+
+const std::string
+test_case_result_agregation::str_full(const bool /*last_only*/) const
+{
+ std::ostringstream oss;
+ oss.precision(2);
+ if (_tc_average)
+ oss << "Average across all journal instances:" << std::endl;
+ else
+ oss << "Average for jid=\"" << _jid << "\":" << std::endl;
+ oss << " total number results: " << _res_list.size() << std::endl;
+ oss << " number exceptions: " << _exception_list.size() << " (" <<
+ (100.0 * _res_list.size() / _exception_list.size()) << "%)" << std::endl;
+
+ oss << test_case_result::str_full();
+
+ if (_exception_list.size())
+ {
+ unsigned n = 0;
+ oss << "List of exceptions/errors:" << std::endl;
+ for (elist_citr i = _exception_list.begin(); i != _exception_list.end(); i++, n++)
+ oss << " " << n << ". " << (*i) << std::endl;
+ }
+
+ if (!_tc_average && _res_list.size() > 1)
+ {
+ oss << "Individual results:" << std::endl;
+ for (tcrp_list_citr i=_res_list.begin(); i!=_res_list.end(); i++)
+ oss << " " << (*i)->str(false) << std::endl;
+ oss << std::endl;
+ }
+
+ return oss.str();
+}
+
+const std::string
+test_case_result_agregation::str_summary(const bool /*last_only*/) const
+{
+ std::ostringstream oss;
+ if (_tc_average)
+ oss << "overall average [" << _res_list.size() << "]:";
+ else
+ oss << "average (" << _res_list.size() << "):";
+
+ oss << test_case_result::str_summary();
+ if (_fmt_chk_done)
+ oss << " fmt-chk=" << (_fmt_chk_err ? "fail" : "ok");
+
+ if (_exception_list.size())
+ {
+ if (_tc_average)
+ oss << " fail: " << _exception_list.size() << " exception"
+ << (_exception_list.size()>1?"s":"") << std::endl;
+ else
+ {
+ if (_exception_list.size() == 1)
+ oss << " fail: " << *_exception_list.begin() << std::endl;
+ else
+ {
+ oss << std::endl;
+ unsigned n = 0;
+ for (elist_citr i = _exception_list.begin(); i != _exception_list.end(); i++, n++)
+ oss << " " << n << ". " << (*i) << std::endl;
+ }
+ }
+ }
+ else
+ oss << " ok" << std::endl;
+ return oss.str();
+}
+
+const journal::time_ns&
+test_case_result_agregation::add_test_time(const journal::time_ns& t)
+{
+ _test_time += t;
+ return _test_time;
+}
+
+} // namespace jtt
+} // namespace mrg
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_result_agregation.h b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_result_agregation.h
new file mode 100644
index 0000000000..0b3998176c
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_result_agregation.h
@@ -0,0 +1,81 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef mrg_jtt_test_case_result_agregation_hpp
+#define mrg_jtt_test_case_result_agregation_hpp
+
+#include "test_case_result.h"
+
+#include <iostream>
+#include <vector>
+
+namespace mrg
+{
+namespace jtt
+{
+
+ class test_case_result_agregation : public test_case_result
+ {
+ public:
+ typedef boost::shared_ptr<test_case_result_agregation> shared_ptr;
+
+ typedef std::vector<test_case_result::shared_ptr> tcrp_list;
+ typedef tcrp_list::const_iterator tcrp_list_citr;
+
+ private:
+ bool _tc_average;
+ bool _fmt_chk_done;
+ bool _fmt_chk_err;
+ tcrp_list _res_list;
+
+ public:
+ test_case_result_agregation(); // used for average across jrnl instances
+ test_case_result_agregation(const std::string& jid);
+ virtual ~test_case_result_agregation();
+
+ void add_test_result(const test_case_result::shared_ptr& tcrp);
+
+ inline bool tc_average_mode() const { return _tc_average; }
+ inline bool fmt_chk_done() const { return _fmt_chk_done; }
+ inline bool fmt_chk_res() const { return _fmt_chk_err; }
+ inline void set_fmt_chk_res(const bool err)
+ { _fmt_chk_done = true; _fmt_chk_err |= err; if (err) add_exception("Journal format error"); }
+ inline u_int32_t num_results() const { return _res_list.size(); }
+ inline tcrp_list_citr rlist_begin() const { return _res_list.begin(); }
+ inline tcrp_list_citr rlist_end() const { return _res_list.end(); }
+ inline const test_case_result::shared_ptr& operator[](unsigned i) const
+ { return _res_list[i]; }
+ bool exception() const;
+ unsigned exception_count() const;
+
+ void clear();
+ const std::string str(const bool last_only, const bool summary) const;
+
+ private:
+ const std::string str_full(const bool last_only) const;
+ const std::string str_summary(const bool last_only) const;
+ const journal::time_ns& add_test_time(const journal::time_ns& t);
+ };
+
+} // namespace jtt
+} // namespace mrg
+
+#endif // ifndef mrg_jtt_test_case_result_agregation_hpp
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_set.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_set.cpp
new file mode 100644
index 0000000000..b818d6c7ae
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_set.cpp
@@ -0,0 +1,169 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "test_case_set.h"
+
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+
+namespace mrg
+{
+namespace jtt
+{
+
+test_case_set::test_case_set():
+ _tc_list(),
+ _csv_ignored(0)
+{}
+
+test_case_set::test_case_set(const std::string& csv_filename, const bool recover_mode,
+ const csv_map& cols):
+ _tc_list(),
+ _csv_ignored(0)
+{
+ append_from_csv(csv_filename, recover_mode, cols);
+}
+
+test_case_set::~test_case_set()
+{}
+
+void
+test_case_set::append(const unsigned test_case_num, const u_int32_t num_msgs,
+ const std::size_t min_data_size, const std::size_t max_data_size, const bool auto_deq,
+ const std::size_t min_xid_size, const std::size_t max_xid_size,
+ const test_case::transient_t transient, const test_case::external_t external,
+ const std::string& comment)
+{
+ test_case::shared_ptr tcp(new test_case(test_case_num, num_msgs, min_data_size,
+ max_data_size, auto_deq, min_xid_size, max_xid_size, transient, external, comment));
+ append(tcp);
+}
+
+
+#define CSV_BUFF_SIZE 2048
+void
+test_case_set::append_from_csv(const std::string& csv_filename, const bool recover_mode,
+ const csv_map& cols)
+{
+ char buff[CSV_BUFF_SIZE];
+ std::ifstream ifs(csv_filename.c_str());
+ while (ifs.good())
+ {
+ ifs.getline(buff, (std::streamsize)CSV_BUFF_SIZE);
+ if (ifs.gcount())
+ {
+ test_case::shared_ptr tcp = get_tc_from_csv(buff, cols);
+ if (tcp.get())
+ {
+ if (!recover_mode || tcp->auto_deq())
+ append(tcp);
+ else
+ _csv_ignored++;
+ }
+ }
+ }
+}
+
+test_case::shared_ptr
+test_case_set::get_tc_from_csv(const std::string& csv_line, const csv_map& cols)
+{
+ unsigned test_case_num = 0;
+ u_int32_t num_msgs = 0;
+ std::size_t min_data_size = 0;
+ std::size_t max_data_size = 0;
+ bool auto_deq = false;
+ std::size_t min_xid_size = 0;
+ std::size_t max_xid_size = 0;
+ test_case::transient_t transient = test_case::JTT_TRANSIENT;
+ test_case::external_t external = test_case::JDL_INTERNAL;
+ std::string comment;
+
+ csv_tok t(csv_line);
+ unsigned col_num = 0;
+ for (csv_tok_citr t_itr = t.begin(); t_itr != t.end(); ++t_itr, ++col_num)
+ {
+ const std::string& tok = *t_itr;
+ csv_map_citr m_citr = cols.find(col_num);
+ if (m_citr != cols.end())
+ {
+ switch (m_citr->second)
+ {
+ case CSV_TC_NUM:
+ if (!tok.size() || tok[0] < '0' || tok[0] > '9')
+ return test_case::shared_ptr();
+ test_case_num = unsigned(std::atol(tok.c_str()));
+ break;
+ case CSV_TC_NUM_MSGS: num_msgs = u_int32_t(std::atol(tok.c_str())); break;
+ case CSV_TC_MIN_DATA_SIZE: min_data_size = std::size_t(std::atol(tok.c_str())); break;
+ case CSV_TC_MAX_DATA_SIZE: max_data_size = std::size_t(std::atol(tok.c_str())); break;
+ case CSV_TC_AUTO_DEQ:
+ if (tok == "TRUE" || tok == "1")
+ auto_deq = true;
+ break;
+ case CSV_TC_MIN_XID_SIZE: min_xid_size = std::size_t(std::atol(tok.c_str())); break;
+ case CSV_TC_MAX_XID_SIZE: max_xid_size = std::size_t(std::atol(tok.c_str())); break;
+ case CSV_TC_TRANSIENT:
+ if (tok == "TRUE" || tok == "1")
+ transient = test_case::JTT_PERSISTNET;
+ else if (tok == "RANDOM" || tok == "-1")
+ transient = test_case::JTT_RANDOM;
+ break;
+ case CSV_TC_EXTERNAL:
+ if (tok == "TRUE" || tok == "1")
+ external = test_case::JDL_EXTERNAL;
+ else if (tok == "RANDOM" || tok == "-1")
+ external = test_case::JDL_RANDOM;
+ break;
+ case CSV_TC_COMMENT: comment = *t_itr; break;
+ }
+ }
+ }
+ if (col_num)
+ return test_case::shared_ptr(new test_case(test_case_num, num_msgs, min_data_size,
+ max_data_size, auto_deq, min_xid_size, max_xid_size, transient, external, comment));
+ else
+ return test_case::shared_ptr();
+}
+
+// Static member initializations
+// This csv_map is for use on the standard spreadsheet-derived test case csv files.
+test_case_set::csv_map test_case_set::std_csv_map;
+const bool test_case_set::_map_init = __init();
+
+bool
+test_case_set::__init()
+{
+ std_csv_map.insert(test_case_set::csv_pair(0, test_case_set::CSV_TC_NUM));
+ std_csv_map.insert(test_case_set::csv_pair(5, test_case_set::CSV_TC_NUM_MSGS));
+ std_csv_map.insert(test_case_set::csv_pair(7, test_case_set::CSV_TC_MIN_DATA_SIZE));
+ std_csv_map.insert(test_case_set::csv_pair(8, test_case_set::CSV_TC_MAX_DATA_SIZE));
+ std_csv_map.insert(test_case_set::csv_pair(11, test_case_set::CSV_TC_AUTO_DEQ));
+ std_csv_map.insert(test_case_set::csv_pair(9, test_case_set::CSV_TC_MIN_XID_SIZE));
+ std_csv_map.insert(test_case_set::csv_pair(10, test_case_set::CSV_TC_MAX_XID_SIZE));
+ std_csv_map.insert(test_case_set::csv_pair(12, test_case_set::CSV_TC_TRANSIENT));
+ std_csv_map.insert(test_case_set::csv_pair(13, test_case_set::CSV_TC_EXTERNAL));
+ std_csv_map.insert(test_case_set::csv_pair(20, test_case_set::CSV_TC_COMMENT));
+ return true;
+}
+
+} // namespace jtt
+} // namespace mrg
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_set.h b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_set.h
new file mode 100644
index 0000000000..94a1ee3172
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_case_set.h
@@ -0,0 +1,99 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef mrg_jtt_test_case_set_hpp
+#define mrg_jtt_test_case_set_hpp
+
+#include "test_case.h"
+
+#include <cstddef>
+#include <boost/tokenizer.hpp>
+#include <map>
+#include <vector>
+
+namespace mrg
+{
+namespace jtt
+{
+
+ class test_case_set
+ {
+ public:
+ enum csv_col_enum {
+ CSV_TC_NUM = 0,
+ CSV_TC_NUM_MSGS,
+ CSV_TC_MIN_DATA_SIZE,
+ CSV_TC_MAX_DATA_SIZE,
+ CSV_TC_AUTO_DEQ,
+ CSV_TC_MIN_XID_SIZE,
+ CSV_TC_MAX_XID_SIZE,
+ CSV_TC_TRANSIENT,
+ CSV_TC_EXTERNAL,
+ CSV_TC_COMMENT };
+ typedef std::pair<unsigned, csv_col_enum> csv_pair;
+ typedef std::map<unsigned, csv_col_enum> csv_map;
+ typedef csv_map::const_iterator csv_map_citr;
+ static csv_map std_csv_map;
+
+ typedef std::vector<test_case::shared_ptr> tcl;
+ typedef tcl::iterator tcl_itr;
+ typedef tcl::const_iterator tcl_citr;
+
+ typedef boost::tokenizer<boost::escaped_list_separator<char> > csv_tok;
+ typedef csv_tok::const_iterator csv_tok_citr;
+
+ private:
+ tcl _tc_list;
+ static const bool _map_init;
+ unsigned _csv_ignored;
+
+ public:
+ test_case_set();
+ test_case_set(const std::string& csv_filename, const bool recover_mode,
+ const csv_map& cols = std_csv_map);
+ virtual ~test_case_set();
+
+ inline unsigned size() const { return _tc_list.size(); }
+ inline unsigned ignored() const { return _csv_ignored; }
+ inline bool empty() const { return _tc_list.empty(); }
+
+ inline void append(const test_case::shared_ptr& tc) { _tc_list.push_back(tc); }
+ void append(const unsigned test_case_num, const u_int32_t num_msgs,
+ const std::size_t min_data_size, const std::size_t max_data_size,
+ const bool auto_deq, const std::size_t min_xid_size,
+ const std::size_t max_xid_size, const test_case::transient_t transient,
+ const test_case::external_t external, const std::string& comment);
+ void append_from_csv(const std::string& csv_filename, const bool recover_mode,
+ const csv_map& cols = std_csv_map);
+ inline tcl_itr begin() { return _tc_list.begin(); }
+ inline tcl_itr end() { return _tc_list.end(); }
+ inline const test_case::shared_ptr& operator[](unsigned i) { return _tc_list[i]; }
+ inline void clear() { _tc_list.clear(); }
+
+ private:
+ test_case::shared_ptr get_tc_from_csv(const std::string& csv_line, const csv_map& cols);
+ static bool __init();
+ };
+
+} // namespace jtt
+} // namespace mrg
+
+#endif // ifndef mrg_jtt_test_case_set_hpp
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_mgr.cpp b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_mgr.cpp
new file mode 100644
index 0000000000..de0b5dbfb9
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_mgr.cpp
@@ -0,0 +1,218 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "test_mgr.h"
+
+#include <cstdlib>
+#include <iostream>
+#include <sys/stat.h>
+#include "test_case_set.h"
+
+namespace mrg
+{
+namespace jtt
+{
+
+test_mgr::test_mgr(args& args):
+ _ji_list(),
+ _args(args),
+ _err_flag(false),
+ _random_fn_ptr(random_fn)
+{
+ if (_args.seed)
+ std::srand(_args.seed);
+}
+
+test_mgr::~test_mgr()
+{}
+
+void
+test_mgr::run()
+{
+ // TODO: complete tidy-up of non-summary (verbose) results, then pull through
+ // a command-line summary to control this.
+ // Idea: --summary: prints short results afterwards
+ // --verbose: prints long version as test progresses
+ // defualt: none of these, similar to current summary = true version.
+ const bool summary = true;
+
+ std::cout << "CSV file: \"" << _args.test_case_csv_file_name << "\"";
+ test_case_set tcs(_args.test_case_csv_file_name, _args.recover_mode);
+
+ if (tcs.size())
+ {
+ std::cout << " (found " << tcs.size() << " test case" << (tcs.size() != 1 ? "s" : "") <<
+ ")" << std::endl;
+ if (tcs.ignored())
+ std::cout << "WARNING: " << tcs.ignored() << " test cases were ignored. (All test "
+ "cases without auto-dequeue are ignored when recover-mode is selected.)" <<
+ std::endl;
+ _args.print_args();
+ }
+ else if(tcs.ignored())
+ {
+ std::cout << " WARNING: All " << tcs.ignored() << " test case(s) were ignored. (All test "
+ "cases without auto-dequeue are ignored when recover-mode is selected.)" <<
+ std::endl;
+ }
+ else
+ std::cout << " (WARNING: This CSV file is empty or does not exist.)" << std::endl;
+
+ do
+ {
+ unsigned u = 0;
+ if (_args.randomize)
+ random_shuffle(tcs.begin(), tcs.end(), _random_fn_ptr);
+ for (test_case_set::tcl_itr tci = tcs.begin(); tci != tcs.end(); tci++, u++)
+ {
+ if (summary)
+ std::cout << "Test case " << (*tci)->test_case_num() << ": \"" <<
+ (*tci)->comment() << "\"" << std::endl;
+ else
+ std::cout << (*tci)->str() << std::endl;
+ if (!_args.reuse_instance || _ji_list.empty())
+ initialize_jrnls();
+ for (ji_list_citr jii=_ji_list.begin(); jii!=_ji_list.end(); jii++)
+ (*jii)->init_tc(*tci, &_args);
+ for (ji_list_citr jii=_ji_list.begin(); jii!=_ji_list.end(); jii++)
+ (*jii)->run_tc();
+ for (ji_list_citr jii=_ji_list.begin(); jii!=_ji_list.end(); jii++)
+ (*jii)->tc_wait_compl();
+
+ if (_args.format_chk)
+ {
+ for (ji_list_citr jii=_ji_list.begin(); jii!=_ji_list.end(); jii++)
+ {
+ jrnl_init_params::shared_ptr jpp = (*jii)->params();
+ std::string ja = _args.jfile_analyzer;
+ if (ja.empty()) ja = "./jfile_chk.py";
+ if (!exists(ja))
+ {
+ std::ostringstream oss;
+ oss << "ERROR: Validation program \"" << ja << "\" does not exist" << std::endl;
+ throw std::runtime_error(oss.str());
+ }
+ std::ostringstream oss;
+ oss << ja << " -b " << jpp->base_filename();
+ // TODO: When jfile_check.py can handle previously recovered journals for
+ // specific tests, then remove this exclusion.
+ if (!_args.recover_mode)
+ {
+ oss << " -c " << _args.test_case_csv_file_name;
+ oss << " -t " << (*tci)->test_case_num();
+ }
+ oss << " -q " << jpp->jdir();
+ bool res = system(oss.str().c_str()) != 0;
+ (*tci)->set_fmt_chk_res(res, jpp->jid());
+ if (res) _err_flag = true;
+ }
+ }
+
+ if (!_args.recover_mode && !_args.keep_jrnls)
+ for (ji_list_citr jii=_ji_list.begin(); jii!=_ji_list.end(); jii++)
+ try { mrg::journal::jdir::delete_dir((*jii)->jrnl_dir()); }
+ catch (...) {} // TODO - work out exception strategy for failure here...
+
+ print_results(*tci, summary);
+ if ((*tci)->average().exception())
+ _err_flag = true;
+ if (_abort || (!_args.repeat_flag && _signal))
+ break;
+ if (_args.pause_secs && tci != tcs.end())
+ ::usleep(_args.pause_secs * 1000000);
+ }
+ }
+ while (_args.repeat_flag && !_signal);
+}
+
+// static fn:
+void
+test_mgr::signal_handler(int sig)
+{
+ if (_signal)
+ _abort = true;
+ _signal = sig;
+ std::cout << std::endl;
+ std::cout << "********************************" << std::endl;
+ std::cout << "Caught signal " << sig << std::endl;
+ if (_abort)
+ std::cout << "Aborting..." << std::endl;
+ else
+ std::cout << "Completing current test cycle..." << std::endl;
+ std::cout << "********************************" << std::endl << std::endl;
+}
+
+bool
+test_mgr::exists(std::string fname)
+{
+ struct stat s;
+ if (::stat(fname.c_str(), &s))
+ {
+ if (errno == ENOENT) // No such dir or file
+ return false;
+ // Throw for any other condition
+ std::ostringstream oss;
+ oss << "ERROR: test_mgr::exists(): file=\"" << fname << "\": " << FORMAT_SYSERR(errno);
+ throw std::runtime_error(oss.str());
+ }
+ return true;
+}
+
+void
+test_mgr::initialize_jrnls()
+{
+ _ji_list.clear();
+ for (unsigned i=0; i<_args.num_jrnls; i++)
+ {
+ std::ostringstream jid;
+ jid << std::hex << std::setfill('0');
+ jid << "test_" << std::setw(4) << std::hex << i;
+ std::ostringstream jdir;
+ jdir << _args.journal_dir << "/" << jid.str();
+ jrnl_init_params::shared_ptr jpp(new jrnl_init_params(jid.str(), jdir.str(), jid.str()));
+ jrnl_instance::shared_ptr jip(new jrnl_instance(jpp));
+ _ji_list.push_back(jip);
+ }
+}
+
+void
+test_mgr::print_results(test_case::shared_ptr tcp, const bool summary)
+{
+ if (!summary)
+ std::cout << " === Results ===" << std::endl;
+
+// TODO - the reporting is broken when --repeat is used. The following commented-out
+// section was an attempt to fix it, but there are too many side-effects.
+// for (test_case::res_map_citr i=tcp->jmap_begin(); i!=tcp->jmap_end(); i++)
+// std::cout << (*i).second->str(summary, summary);
+// if (tcp->num_jrnls() > 1)
+ std::cout << tcp->average().str(false, summary);
+
+ if (!summary)
+ std::cout << std::endl;
+}
+
+// static instances
+volatile sig_atomic_t test_mgr::_signal = 0;
+volatile bool test_mgr::_abort = false;
+
+} // namespace jtt
+} // namespace mrg
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_mgr.h b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_mgr.h
new file mode 100644
index 0000000000..e608ac6280
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/jtt/test_mgr.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef mrg_jtt_test_mgr_hpp
+#define mrg_jtt_test_mgr_hpp
+
+#include "args.h"
+#include <csignal>
+#include <cstdlib>
+#include "jrnl_instance.h"
+
+namespace mrg
+{
+namespace jtt
+{
+ class test_mgr
+ {
+ public:
+ typedef std::vector<jrnl_instance::shared_ptr> ji_list;
+ typedef ji_list::iterator ji_list_itr;
+ typedef ji_list::const_iterator ji_list_citr;
+
+ private:
+ ji_list _ji_list;
+ args& _args;
+ bool _err_flag;
+ ptrdiff_t (*_random_fn_ptr)(const ptrdiff_t i);
+ static volatile std::sig_atomic_t _signal;
+ static volatile bool _abort;
+
+ public:
+ test_mgr(args& args);
+ virtual ~test_mgr();
+ void run();
+ inline bool error() const { return _err_flag; }
+
+ static void signal_handler(int signal);
+
+ private:
+ static bool exists(std::string file_name);
+ void initialize_jrnls();
+ void print_results(test_case::shared_ptr tcp, const bool summary);
+ inline static ptrdiff_t random_fn(const ptrdiff_t i)
+ { return static_cast<ptrdiff_t>(1.0 * i * std::rand() / RAND_MAX); }
+ };
+
+} // namespace jtt
+} // namespace mrg
+
+#endif // ifndef mrg_jtt_test_mgr_hpp
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/prof b/qpid/cpp/src/tests/legacystore/jrnl/prof
new file mode 100755
index 0000000000..2abe7baa4a
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/prof
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+mkdir -p profile
+opcontrol --setup --no-vmlinux --separate=library
+opcontrol --start
+# -- Do stuff here --
+./jtest wtests.csv 264
+# -- End of stuff --
+opcontrol --stop
+opcontrol --dump
+opcontrol --shutdown
+opreport -l ./jtest
+opannotate --source --output-dir=profile ./jtest
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/run-journal-tests b/qpid/cpp/src/tests/legacystore/jrnl/run-journal-tests
new file mode 100755
index 0000000000..e169e39c60
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/run-journal-tests
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if test x${TMP_DATA_DIR} == x; then
+ export TMP_DATA_DIR=/tmp
+fi
+fail=0
+num_jrnls=3
+
+# Run jtt using default test set
+echo
+echo "===== Mode 1: New journal instance, no recover ====="
+jtt/jtt --analyzer ../../tools/store_chk --jrnl-dir ${TMP_DATA_DIR} --csv jtt/jtt.csv --format-chk --num-jrnls ${num_jrnls} || fail=1
+rm -rf ${TMP_DATA_DIR}/test_0*
+echo
+echo "===== Mode 2: Re-use journal instance, no recover ====="
+jtt/jtt --analyzer ../../tools/store_chk --jrnl-dir ${TMP_DATA_DIR} --csv jtt/jtt.csv --reuse-instance --format-chk --num-jrnls ${num_jrnls} || fail=1
+rm -rf ${TMP_DATA_DIR}/test_0*
+echo
+echo "===== Mode 3: New journal instance, recover previous test journal ====="
+jtt/jtt --analyzer ../../tools/store_chk --jrnl-dir ${TMP_DATA_DIR} --csv jtt/jtt.csv --recover-mode --format-chk --num-jrnls ${num_jrnls} || fail=1
+rm -rf ${TMP_DATA_DIR}/test_0*
+echo
+echo "===== Mode 4: Re-use journal instance, recover previous test journal ====="
+jtt/jtt --analyzer ../../tools/store_chk --jrnl-dir ${TMP_DATA_DIR} --csv jtt/jtt.csv --reuse-instance --recover-mode --format-chk --num-jrnls ${num_jrnls} || fail=1
+rm -rf ${TMP_DATA_DIR}/test_0*
+echo
+
+exit $fail
diff --git a/qpid/cpp/src/tests/legacystore/jrnl/tests.ods b/qpid/cpp/src/tests/legacystore/jrnl/tests.ods
new file mode 100644
index 0000000000..d900374321
--- /dev/null
+++ b/qpid/cpp/src/tests/legacystore/jrnl/tests.ods
Binary files differ