summaryrefslogtreecommitdiffstats
path: root/src/test/objectstore/test_idempotent_sequence.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/objectstore/test_idempotent_sequence.cc')
-rw-r--r--src/test/objectstore/test_idempotent_sequence.cc258
1 files changed, 258 insertions, 0 deletions
diff --git a/src/test/objectstore/test_idempotent_sequence.cc b/src/test/objectstore/test_idempotent_sequence.cc
new file mode 100644
index 000000000..7cf31fa92
--- /dev/null
+++ b/src/test/objectstore/test_idempotent_sequence.cc
@@ -0,0 +1,258 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+* Ceph - scalable distributed file system
+*
+* Copyright (C) 2012 New Dream Network
+*
+* This is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License version 2.1, as published by the Free Software
+* Foundation. See file COPYING.
+*/
+#include <stdio.h>
+#include <string.h>
+#include <iostream>
+#include <sstream>
+#include <time.h>
+#include <stdlib.h>
+#include "common/ceph_argparse.h"
+#include "global/global_init.h"
+#include "common/debug.h"
+#include "os/filestore/FileStore.h"
+
+#include "DeterministicOpSequence.h"
+#include "FileStoreDiff.h"
+
+#include "common/config.h"
+#include "include/ceph_assert.h"
+
+#define dout_context g_ceph_context
+#define dout_subsys ceph_subsys_
+#undef dout_prefix
+#define dout_prefix *_dout << "test_idempotent_sequence "
+
+void usage(const char *name, std::string command = "") {
+ ceph_assert(name != NULL);
+
+ std::string more = "cmd <args...>";
+ std::string diff = "diff <filestoreA> <journalA> <filestoreB> <journalB>";
+ std::string get_last_op = "get-last-op <filestore> <journal>";
+ std::string run_seq_to = "run-sequence-to <num-ops> <filestore> <journal>";
+
+ if (!command.empty()) {
+ if (command == "diff")
+ more = diff;
+ else if (command == "get-last-op")
+ more = get_last_op;
+ else if (command == "run-sequence-to")
+ more = run_seq_to;
+ }
+ std::cout << "usage: " << name << " " << more << " [options]" << std::endl;
+
+ std::cout << "\n\
+Commands:\n\
+ " << diff << "\n\
+ " << get_last_op << "\n\
+ " << run_seq_to << "\n\
+\n\
+Global Options:\n\
+ -c FILE Read configuration from FILE\n\
+ --osd-data PATH Set OSD Data path\n\
+ --osd-journal PATH Set OSD Journal path\n\
+ --osd-journal-size VAL Set Journal size\n\
+ --help This message\n\
+\n\
+Test-specific Options:\n\
+ --test-seed VAL Seed to run the test\n\
+ --test-status-file PATH Path to keep the status file\n\
+ --test-num-colls VAL Number of collections to create on init\n\
+ --test-num-objs VAL Number of objects to create on init\n\
+" << std::endl;
+}
+
+const char *our_name = NULL;
+int seed = 0, num_txs = 100, num_colls = 30, num_objs = 0;
+bool is_seed_set = false;
+int verify_at = 0;
+std::string status_file;
+
+int run_diff(std::string& a_path, std::string& a_journal,
+ std::string& b_path, std::string& b_journal)
+{
+ FileStore *a = new FileStore(g_ceph_context, a_path, a_journal, 0, "a");
+ FileStore *b = new FileStore(g_ceph_context, b_path, b_journal, 0, "b");
+
+ int ret = 0;
+ {
+ FileStoreDiff fsd(a, b);
+ if (fsd.diff()) {
+ dout(0) << "diff found an difference" << dendl;
+ ret = -1;
+ } else {
+ dout(0) << "no diff" << dendl;
+ }
+ }
+
+ delete a;
+ delete b;
+ return ret;
+}
+
+int run_get_last_op(std::string& filestore_path, std::string& journal_path)
+{
+ FileStore *store = new FileStore(g_ceph_context, filestore_path,
+ journal_path);
+
+ int err = store->mount();
+ if (err) {
+ store->umount();
+ delete store;
+ return err;
+ }
+
+ vector<coll_t> cls;
+ store->list_collections(cls);
+
+ int32_t txn = 0;
+ for (auto cid : cls) {
+ ghobject_t txn_object = DeterministicOpSequence::get_txn_object(cid);
+ bufferlist bl;
+ auto ch = store->open_collection(cid);
+ store->read(ch, txn_object, 0, 100, bl);
+ int32_t t = 0;
+ if (bl.length()) {
+ auto p = bl.cbegin();
+ decode(t, p);
+ }
+ if (t > txn) {
+ txn = t;
+ }
+ }
+
+ store->umount();
+ delete store;
+
+ cout << txn << std::endl;
+ return 0;
+}
+
+int run_sequence_to(int val, std::string& filestore_path,
+ std::string& journal_path)
+{
+ num_txs = val;
+
+ if (!is_seed_set)
+ seed = (int) time(NULL);
+
+ FileStore *store = new FileStore(g_ceph_context, filestore_path,
+ journal_path);
+
+ int err;
+
+ // mkfs iff directory dne
+ err = ::mkdir(filestore_path.c_str(), 0755);
+ if (err) {
+ cerr << filestore_path << " already exists" << std::endl;
+ store->umount();
+ delete store;
+ return err;
+ }
+
+ err = store->mkfs();
+ ceph_assert(err == 0);
+
+ err = store->mount();
+ ceph_assert(err == 0);
+
+ DeterministicOpSequence op_sequence(store, status_file);
+ op_sequence.init(num_colls, num_objs);
+ op_sequence.generate(seed, num_txs);
+ store->umount();
+ return 0;
+}
+
+int run_command(std::string& command, std::vector<std::string>& args)
+{
+ if (command.empty()) {
+ usage(our_name);
+ exit(0);
+ }
+
+ /* We'll have a class that will handle the options, the command
+ * and its arguments. For the time being, and so we can move on, let's
+ * tolerate this big, ugly code.
+ */
+ if (command == "diff") {
+ /* expect 4 arguments: (filestore path + journal path)*2 */
+ if (args.size() == 4) {
+ return run_diff(args[0], args[1], args[2], args[3]);
+ }
+ } else if (command == "get-last-op") {
+ /* expect 2 arguments: a filestore path + journal */
+ if (args.size() == 2) {
+ return run_get_last_op(args[0], args[1]);
+ }
+ } else if (command == "run-sequence-to") {
+ /* expect 3 arguments: # of operations and a filestore path + journal. */
+ if (args.size() == 3) {
+ return run_sequence_to(strtoll(args[0].c_str(), NULL, 10), args[1], args[2]);
+ }
+ } else {
+ std::cout << "unknown command " << command << std::endl;
+ usage(our_name);
+ exit(1);
+ }
+
+ usage(our_name, command);
+ exit(1);
+}
+
+int main(int argc, const char *argv[])
+{
+ vector<const char*> args;
+ our_name = argv[0];
+ argv_to_vec(argc, argv, args);
+
+ auto cct = global_init(NULL, args,
+ CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY,
+ CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
+ common_init_finish(g_ceph_context);
+ g_ceph_context->_conf.apply_changes(nullptr);
+
+ std::string command;
+ std::vector<std::string> command_args;
+
+ for (std::vector<const char*>::iterator i = args.begin(); i != args.end();) {
+ string val;
+
+ if (ceph_argparse_double_dash(args, i)) {
+ break;
+ } else if (ceph_argparse_witharg(args, i, &val,
+ "--test-seed", (char*) NULL)) {
+ seed = strtoll(val.c_str(), NULL, 10);
+ is_seed_set = true;
+ } else if (ceph_argparse_witharg(args, i, &val,
+ "--test-num-colls", (char*) NULL)) {
+ num_colls = strtoll(val.c_str(), NULL, 10);
+ } else if (ceph_argparse_witharg(args, i, &val,
+ "--test-num-objs", (char*) NULL)) {
+ num_objs = strtoll(val.c_str(), NULL, 10);
+ } else if (ceph_argparse_witharg(args, i, &val,
+ "--test-status-file", (char*) NULL)) {
+ status_file = val;
+ } else if (ceph_argparse_flag(args, i, "--help", (char*) NULL)) {
+ usage(our_name);
+ exit(0);
+ } else {
+ if (command.empty())
+ command = *i++;
+ else
+ command_args.push_back(string(*i++));
+ }
+ }
+
+ int ret = run_command(command, command_args);
+
+ return ret;
+}