// -*- 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 #include #include #include #include #include #include "os/ObjectStore.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include "common/debug.h" #include #include #include "TestObjectStoreState.h" #include "include/assert.h" #define dout_context g_ceph_context #define dout_subsys ceph_subsys_filestore #undef dout_prefix #define dout_prefix *_dout << "ceph_test_objectstore_state " void TestObjectStoreState::init(int colls, int objs) { dout(5) << "init " << colls << " colls " << objs << " objs" << dendl; ObjectStore::Sequencer osr(__func__); ObjectStore::Transaction t; t.create_collection(coll_t::meta(), 0); m_store->apply_transaction(&osr, std::move(t)); wait_for_ready(); int baseid = 0; 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 << dendl; ObjectStore::Transaction *t = new ObjectStore::Transaction; t->create_collection(entry->m_coll, 32); bufferlist hint; uint32_t pg_num = colls; uint64_t num_objs = uint64_t(objs / colls); ::encode(pg_num, hint); ::encode(num_objs, hint); t->collection_hint(entry->m_coll, ObjectStore::Transaction::COLL_HINT_EXPECTED_NUM_OBJECTS, hint); dout(5) << "give collection hint, number of objects per collection: " << num_objs << dendl; t->touch(coll_t::meta(), entry->m_meta_obj); for (int i = 0; i < objs; i++) { hobject_t *obj = entry->touch_obj(i + baseid); t->touch(entry->m_coll, ghobject_t(*obj)); ceph_assert(i + baseid == m_num_objects); m_num_objects++; } baseid += objs; m_store->queue_transaction(&(entry->m_osr), std::move(*t), new C_OnFinished(this)); delete t; inc_in_flight(); m_collections.insert(make_pair(coll_id, entry)); m_collections_ids.push_back(coll_id); m_next_coll_nr++; } dout(5) << "init has " << m_in_flight.load() << "in-flight transactions" << dendl; wait_for_done(); dout(5) << "init finished" << dendl; } TestObjectStoreState::coll_entry_t *TestObjectStoreState::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)); } TestObjectStoreState::coll_entry_t* TestObjectStoreState::get_coll(int key, bool erase) { dout(5) << "get_coll id " << key << dendl; coll_entry_t *entry = NULL; map::iterator it = m_collections.find(key); if (it != m_collections.end()) { entry = it->second; if (erase) { m_collections.erase(it); vector::iterator cid_it = m_collections_ids.begin()+(entry->m_id); dout(20) << __func__ << " removing key " << key << " coll_id " << entry->m_id << " iterator's entry id " << (*cid_it) << dendl; m_collections_ids.erase(cid_it); } } dout(5) << "get_coll id " << key; if (!entry) *_dout << " non-existent"; else *_dout << " name " << entry->m_coll.to_str(); *_dout << dendl; return entry; } TestObjectStoreState::coll_entry_t* TestObjectStoreState::get_coll_at(int pos, bool erase) { dout(5) << "get_coll_at pos " << pos << dendl; if (m_collections.empty()) return NULL; assert((size_t) pos < m_collections_ids.size()); int coll_id = m_collections_ids[pos]; coll_entry_t *entry = m_collections[coll_id]; if (entry == NULL) { dout(5) << "get_coll_at pos " << pos << " non-existent" << dendl; return NULL; } if (erase) { m_collections.erase(coll_id); vector::iterator it = m_collections_ids.begin()+(pos); dout(20) << __func__ << " removing pos " << pos << " coll_id " << coll_id << " iterator's entry id " << (*it) << dendl; m_collections_ids.erase(it); } dout(5) << "get_coll_at pos " << pos << ": " << entry->m_coll << "(removed: " << erase << ")" << dendl; return entry; } TestObjectStoreState::coll_entry_t::~coll_entry_t() { if (m_objects.size() > 0) { map::iterator it = m_objects.begin(); for (; it != m_objects.end(); ++it) { hobject_t *obj = it->second; if (obj) { delete obj; } } m_objects.clear(); } } bool TestObjectStoreState::coll_entry_t::check_for_obj(int id) { if (m_objects.count(id)) return true; return false; } hobject_t *TestObjectStoreState::coll_entry_t::touch_obj(int id) { map::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, "obj%d", 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 *TestObjectStoreState::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 *TestObjectStoreState::coll_entry_t::remove_obj(int id) { return get_obj(id, true); } hobject_t *TestObjectStoreState::coll_entry_t::get_obj(int id, bool remove) { map::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 *TestObjectStoreState::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 *TestObjectStoreState::coll_entry_t::remove_obj_at(int pos, int *key) { return get_obj_at(pos, true, key); } hobject_t *TestObjectStoreState::coll_entry_t::get_obj_at(int pos, bool remove, int *key) { if (m_objects.empty()) { dout(5) << "get_obj_at coll " << m_coll.to_str() << " pos " << pos << " in an empty collection" << dendl; return NULL; } hobject_t *ret = NULL; map::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* TestObjectStoreState::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; } int TestObjectStoreState::coll_entry_t::get_random_obj_id(rngen_t& gen) { ceph_assert(!m_objects.empty()); boost::uniform_int<> orig_obj_rng(0, m_objects.size()-1); int pos = orig_obj_rng(gen); map::iterator it = m_objects.begin(); for (int i = 0; it != m_objects.end(); ++it, i++) { if (i == pos) { return it->first; } } ceph_assert(0 == "INTERNAL ERROR"); }