--- /dev/null
+// -*- 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 <assert.h>
+#include <time.h>
+#include <stdlib.h>
+#include <signal.h>
+#include "os/FileStore.h"
+#include "common/ceph_argparse.h"
+#include "global/global_init.h"
+#include "common/debug.h"
+#include <boost/scoped_ptr.hpp>
+#include <boost/lexical_cast.hpp>
+#include "TestFileStoreState.h"
+
+#define dout_subsys ceph_subsys_filestore
+#undef dout_prefix
+#define dout_prefix *_dout << "test_filestore_state "
+
+const coll_t TestFileStoreState::META_COLL("meta");
+const coll_t TestFileStoreState::TEMP_COLL("temp");
+
+void TestFileStoreState::init(int colls, int objs) {
+ dout(5) << "init " << colls << " colls " << objs << " objs" << dendl;
+
+ ObjectStore::Transaction *t;
+ t = new ObjectStore::Transaction;
+
+ t->create_collection(META_COLL);
+ t->create_collection(TEMP_COLL);
+ m_store->apply_transaction(*t);
+
+ wait_for_ready();
+
+ for (int i = 0; i < colls; i++) {
+ int coll_id = i;
+ coll_entry_t *entry = coll_create(coll_id);
+ dout(5) << "init create collection " << entry->m_coll.to_str()
+ << " meta " << entry->m_meta_obj.oid.name << dendl;
+
+ t = new ObjectStore::Transaction;
+ t->create_collection(entry->m_coll);
+ t->touch(META_COLL, entry->m_meta_obj);
+
+ for (int i = 0; i < objs; i++) {
+ hobject_t *obj = entry->touch_obj(i);
+ t->touch(entry->m_coll, *obj);
+ }
+
+ m_store->queue_transaction(&(entry->m_osr), t,
+ new C_OnFinished(this, t));
+ m_in_flight++;
+
+ m_collections.insert(make_pair(coll_id, entry));
+ m_next_coll_nr++;
+ }
+ dout(5) << "init has " << m_in_flight << "in-flight transactions" << dendl;
+ wait_for_done();
+ dout(5) << "init finished" << dendl;
+}
+
+TestFileStoreState::coll_entry_t *TestFileStoreState::coll_create(int id) {
+ char buf[100];
+ char meta_buf[100];
+ memset(buf, 0, 100);
+ memset(meta_buf, 0, 100);
+ snprintf(buf, 100, "0.%d_head", id);
+ snprintf(meta_buf, 100, "pglog_0.%d_head", id);
+ return (new coll_entry_t(id, buf, meta_buf));
+}
+
+TestFileStoreState::coll_entry_t *TestFileStoreState::get_coll_at(int pos) {
+ dout(5) << "get_coll_at pos " << pos << dendl;
+
+ coll_entry_t *entry = NULL;
+ map<int, coll_entry_t*>::iterator it = m_collections.find(pos);
+ if (it != m_collections.end())
+ entry = it->second;
+
+ dout(5) << "get_coll_at pos " << pos;
+ if (!entry)
+ *_dout << " non-existent";
+ else
+ *_dout << " name " << entry->m_coll.to_str();
+ *_dout << dendl;
+ return entry;
+}
+
+TestFileStoreState::coll_entry_t::~coll_entry_t()
+{
+ /*
+ if (m_objects.size() > 0) {
+ for (set<hobject_t*>::iterator it = m_objects.begin();
+ it != m_objects.end(); it++) {
+ hobject_t *obj = *it;
+ m_objects.erase(it);
+ if (obj) {
+ delete obj;
+ }
+ }
+ }
+ */
+}
+
+hobject_t *TestFileStoreState::coll_entry_t::touch_obj(int id)
+{
+ map<int, hobject_t*>::iterator it = m_objects.find(id);
+ if (it != m_objects.end()) {
+ dout(5) << "touch_obj coll id " << m_id
+ << " name " << it->second->oid.name << dendl;
+ return it->second;
+ }
+
+ char buf[100];
+ memset(buf, 0, 100);
+ snprintf(buf, 100, "%d_%d", m_id, id);
+
+ hobject_t *obj = new hobject_t(sobject_t(object_t(buf), CEPH_NOSNAP));
+ m_objects.insert(make_pair(id, obj));
+
+ dout(5) << "touch_obj coll id " << m_id << " name " << buf << dendl;
+ return obj;
+}
+
+hobject_t *TestFileStoreState::coll_entry_t::get_obj(int id)
+{
+ return get_obj(id, false);
+}
+
+/**
+ * remove_obj - Removes object without freeing it.
+ * @param id Object's id in the map.
+ * @return The object or NULL in case of error.
+ */
+hobject_t *TestFileStoreState::coll_entry_t::remove_obj(int id)
+{
+ return get_obj(id, true);
+}
+
+hobject_t *TestFileStoreState::coll_entry_t::get_obj(int id, bool remove)
+{
+ map<int, hobject_t*>::iterator it = m_objects.find(id);
+ if (it == m_objects.end()) {
+ dout(5) << "get_obj coll " << m_coll.to_str()
+ << " obj #" << id << " non-existent" << dendl;
+ return NULL;
+ }
+
+ hobject_t *obj = it->second;
+ if (remove)
+ m_objects.erase(it);
+
+ dout(5) << "get_obj coll " << m_coll.to_str() << " id " << id
+ << ": " << obj->oid.name << "(removed: " << remove << ")" << dendl;
+
+ return obj;
+}
+
+hobject_t *TestFileStoreState::coll_entry_t::get_obj_at(int pos, int *key)
+{
+ return get_obj_at(pos, false, key);
+}
+
+/**
+ * remove_obj_at - Removes object without freeing it.
+ * @param pos The map's position in which the object lies.
+ * @return The object or NULL in case of error.
+ */
+hobject_t *TestFileStoreState::coll_entry_t::remove_obj_at(int pos, int *key)
+{
+ return get_obj_at(pos, true, key);
+}
+
+hobject_t *TestFileStoreState::coll_entry_t::get_obj_at(int pos,
+ bool remove, int *key)
+{
+ if (!m_objects.size()) {
+ dout(5) << "get_obj_at coll " << m_coll.to_str() << " pos " << pos
+ << " in an empty collection" << dendl;
+ return NULL;
+ }
+
+ hobject_t *ret = NULL;
+ map<int, hobject_t*>::iterator it = m_objects.begin();
+ for (int i = 0; it != m_objects.end(); it++, i++) {
+ if (i == pos) {
+ ret = it->second;
+ break;
+ }
+ }
+
+ if (ret == NULL) {
+ dout(5) << "get_obj_at coll " << m_coll.to_str() << " pos " << pos
+ << " non-existent" << dendl;
+ return NULL;
+ }
+
+ if (key != NULL)
+ *key = it->first;
+
+ if (remove)
+ m_objects.erase(it);
+
+ dout(5) << "get_obj_at coll id " << m_id << " pos " << pos
+ << ": " << ret->oid.name << "(removed: " << remove << ")" << dendl;
+
+ return ret;
+}
+
+hobject_t*
+TestFileStoreState::coll_entry_t::replace_obj(int id, hobject_t *obj) {
+ hobject_t *old_obj = remove_obj(id);
+ m_objects.insert(make_pair(id, obj));
+ return old_obj;
+}
--- /dev/null
+// -*- 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.
+*/
+#ifndef TEST_FILESTORE_STATE_H_
+#define TEST_FILESTORE_STATE_H_
+
+#include "os/FileStore.h"
+#include <boost/scoped_ptr.hpp>
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_int.hpp>
+#include <map>
+
+class TestFileStoreState {
+public:
+ struct coll_entry_t {
+ int m_id;
+ coll_t m_coll;
+ hobject_t m_meta_obj;
+ ObjectStore::Sequencer m_osr;
+ map<int, hobject_t*> m_objects;
+ int m_next_object_id;
+
+ coll_entry_t(int i, char *coll_buf, char *meta_obj_buf)
+ : m_id(i), m_coll(coll_buf),
+ m_meta_obj(sobject_t(object_t(meta_obj_buf), CEPH_NOSNAP)),
+ m_osr(coll_buf), m_next_object_id(0) {
+ }
+ ~coll_entry_t();
+
+ hobject_t *touch_obj(int id);
+ hobject_t *get_obj(int id);
+ hobject_t *remove_obj(int id);
+ hobject_t *get_obj_at(int pos, int *key = NULL);
+ hobject_t *remove_obj_at(int pos, int *key = NULL);
+ hobject_t *replace_obj(int id, hobject_t *obj);
+
+ private:
+ hobject_t *get_obj(int id, bool remove);
+ hobject_t *get_obj_at(int pos, bool remove, int *key = NULL);
+ };
+
+ /* kept in upper case for consistency with coll_t's */
+ static const coll_t META_COLL;
+ static const coll_t TEMP_COLL;
+
+ protected:
+ boost::shared_ptr<ObjectStore> m_store;
+ map<int, coll_entry_t*> m_collections;
+ int m_next_coll_nr;
+ int m_num_objs_per_coll;
+
+ int m_max_in_flight;
+ int m_in_flight;
+ Mutex m_finished_lock;
+ Cond m_finished_cond;
+
+ void wait_for_ready() {
+ while ((m_max_in_flight > 0) && (m_in_flight >= m_max_in_flight))
+ m_finished_cond.Wait(m_finished_lock);
+ }
+
+ void wait_for_done() {
+ Mutex::Locker locker(m_finished_lock);
+ while (m_in_flight)
+ m_finished_cond.Wait(m_finished_lock);
+ }
+
+ void set_max_in_flight(int max) {
+ m_max_in_flight = max;
+ }
+ void set_num_objs_per_coll(int val) {
+ m_num_objs_per_coll = val;
+ }
+
+ coll_entry_t *get_coll_at(int pos);
+
+ private:
+ static const int m_default_num_colls = 30;
+
+ public:
+ TestFileStoreState(FileStore *store) :
+ m_next_coll_nr(0), m_num_objs_per_coll(6000),
+ m_max_in_flight(0), m_in_flight(0), m_finished_lock("Finished Lock") {
+ m_store.reset(store);
+ }
+ ~TestFileStoreState() { }
+
+ void init(int colls, int objs);
+ void init() {
+ init(m_default_num_colls, 0);
+ }
+
+ coll_entry_t *coll_create(int id);
+
+ class C_OnFinished: public Context {
+ TestFileStoreState *m_state;
+ ObjectStore::Transaction *m_tx;
+
+ public:
+ C_OnFinished(TestFileStoreState *state,
+ ObjectStore::Transaction *t) : m_state(state), m_tx(t) { }
+
+ void finish(int r) {
+ Mutex::Locker locker(m_state->m_finished_lock);
+ m_state->m_in_flight--;
+ m_state->m_finished_cond.Signal();
+
+ delete m_tx;
+ }
+ };
+};
+
+#endif /* TEST_FILESTORE_STATE_H_ */