diff options
Diffstat (limited to 'qpid/cpp/src/tests/legacystore/jrnl/jtt')
32 files changed, 5205 insertions, 0 deletions
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 |