From: Sage Weil Date: Mon, 20 Jan 2014 18:29:55 +0000 (-0800) Subject: osd: rename test/test_osd_types.cc -> test/osd/types.cc X-Git-Tag: v0.78~166^2~36 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=bc945248ec2daee9ab049a484a1ceb5a2d192192;p=ceph.git osd: rename test/test_osd_types.cc -> test/osd/types.cc Signed-off-by: Sage Weil --- diff --git a/src/test/Makefile.am b/src/test/Makefile.am index a5d47597d1c..32a36e3426e 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -361,7 +361,7 @@ unittest_ceph_compatset_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_ceph_compatset_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_ceph_compatset -unittest_osd_types_SOURCES = test/test_osd_types.cc +unittest_osd_types_SOURCES = test/osd/types.cc unittest_osd_types_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_osd_types_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) check_PROGRAMS += unittest_osd_types diff --git a/src/test/osd/types.cc b/src/test/osd/types.cc new file mode 100644 index 00000000000..d1e62b8fcea --- /dev/null +++ b/src/test/osd/types.cc @@ -0,0 +1,1197 @@ +// -*- 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) 2011 New Dream Network + * Copyright (C) 2013 Cloudwatt + * + * Author: Loic Dachary + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License version 2, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "include/types.h" +#include "osd/osd_types.h" +#include "osd/OSDMap.h" +#include "gtest/gtest.h" +#include "common/Thread.h" + +#include + +TEST(hobject, prefixes0) +{ + uint32_t mask = 0xE947FA20; + uint32_t bits = 12; + int64_t pool = 0; + + set prefixes_correct; + prefixes_correct.insert(string("0000000000000000.02A")); + + set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); + ASSERT_EQ(prefixes_out, prefixes_correct); +} + +TEST(hobject, prefixes1) +{ + uint32_t mask = 0x0000000F; + uint32_t bits = 6; + int64_t pool = 20; + + set prefixes_correct; + prefixes_correct.insert(string("0000000000000014.F0")); + prefixes_correct.insert(string("0000000000000014.F4")); + prefixes_correct.insert(string("0000000000000014.F8")); + prefixes_correct.insert(string("0000000000000014.FC")); + + set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); + ASSERT_EQ(prefixes_out, prefixes_correct); +} + +TEST(hobject, prefixes2) +{ + uint32_t mask = 0xDEADBEAF; + uint32_t bits = 25; + int64_t pool = 0; + + set prefixes_correct; + prefixes_correct.insert(string("0000000000000000.FAEBDA0")); + prefixes_correct.insert(string("0000000000000000.FAEBDA2")); + prefixes_correct.insert(string("0000000000000000.FAEBDA4")); + prefixes_correct.insert(string("0000000000000000.FAEBDA6")); + prefixes_correct.insert(string("0000000000000000.FAEBDA8")); + prefixes_correct.insert(string("0000000000000000.FAEBDAA")); + prefixes_correct.insert(string("0000000000000000.FAEBDAC")); + prefixes_correct.insert(string("0000000000000000.FAEBDAE")); + + set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); + ASSERT_EQ(prefixes_out, prefixes_correct); +} + +TEST(hobject, prefixes3) +{ + uint32_t mask = 0xE947FA20; + uint32_t bits = 32; + int64_t pool = 0x23; + + set prefixes_correct; + prefixes_correct.insert(string("0000000000000023.02AF749E")); + + set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); + ASSERT_EQ(prefixes_out, prefixes_correct); +} + +TEST(hobject, prefixes4) +{ + uint32_t mask = 0xE947FA20; + uint32_t bits = 0; + int64_t pool = 0x23; + + set prefixes_correct; + prefixes_correct.insert(string("0000000000000023.")); + + set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); + ASSERT_EQ(prefixes_out, prefixes_correct); +} + +TEST(hobject, prefixes5) +{ + uint32_t mask = 0xDEADBEAF; + uint32_t bits = 1; + int64_t pool = 0x34AC5D00; + + set prefixes_correct; + prefixes_correct.insert(string("0000000034AC5D00.1")); + prefixes_correct.insert(string("0000000034AC5D00.3")); + prefixes_correct.insert(string("0000000034AC5D00.5")); + prefixes_correct.insert(string("0000000034AC5D00.7")); + prefixes_correct.insert(string("0000000034AC5D00.9")); + prefixes_correct.insert(string("0000000034AC5D00.B")); + prefixes_correct.insert(string("0000000034AC5D00.D")); + prefixes_correct.insert(string("0000000034AC5D00.F")); + + set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); + ASSERT_EQ(prefixes_out, prefixes_correct); +} + +TEST(pg_interval_t, check_new_interval) +{ + // + // Create a situation where osdmaps are the same so that + // each test case can diverge from it using minimal code. + // + int osd_id = 1; + epoch_t epoch = 40; + ceph::shared_ptr osdmap(new OSDMap()); + osdmap->set_max_osd(10); + osdmap->set_state(osd_id, CEPH_OSD_EXISTS); + osdmap->set_epoch(epoch); + ceph::shared_ptr lastmap(new OSDMap()); + lastmap->set_max_osd(10); + lastmap->set_state(osd_id, CEPH_OSD_EXISTS); + lastmap->set_epoch(epoch); + epoch_t same_interval_since = epoch; + epoch_t last_epoch_clean = same_interval_since; + int64_t pool_id = 200; + int pg_num = 4; + __u8 min_size = 2; + { + OSDMap::Incremental inc(epoch + 1); + inc.new_pools[pool_id].min_size = min_size; + inc.new_pools[pool_id].set_pg_num(pg_num); + inc.new_up_thru[osd_id] = epoch + 1; + osdmap->apply_incremental(inc); + lastmap->apply_incremental(inc); + } + vector new_acting; + new_acting.push_back(osd_id); + new_acting.push_back(osd_id + 1); + vector old_acting = new_acting; + vector new_up; + new_up.push_back(osd_id); + vector old_up = new_up; + pg_t pgid; + pgid.set_pool(pool_id); + + // + // Do nothing if there are no modifications in + // acting, up or pool size and that the pool is not + // being split + // + { + map past_intervals; + + ASSERT_TRUE(past_intervals.empty()); + ASSERT_FALSE(pg_interval_t::check_new_interval(old_acting, + new_acting, + old_up, + new_up, + same_interval_since, + last_epoch_clean, + osdmap, + lastmap, + pool_id, + pgid, + &past_intervals)); + ASSERT_TRUE(past_intervals.empty()); + } + + // + // pool did not exist in the old osdmap + // + { + ceph::shared_ptr lastmap(new OSDMap()); + lastmap->set_max_osd(10); + lastmap->set_state(osd_id, CEPH_OSD_EXISTS); + lastmap->set_epoch(epoch); + + map past_intervals; + + ASSERT_TRUE(past_intervals.empty()); + ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, + new_acting, + old_up, + new_up, + same_interval_since, + last_epoch_clean, + osdmap, + lastmap, + pool_id, + pgid, + &past_intervals)); + ASSERT_EQ((unsigned int)1, past_intervals.size()); + ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first); + ASSERT_EQ(osdmap->get_epoch() - 1, past_intervals[same_interval_since].last); + ASSERT_EQ(osd_id, past_intervals[same_interval_since].acting[0]); + ASSERT_EQ(osd_id, past_intervals[same_interval_since].up[0]); + } + + // + // The acting set has changed + // + { + vector new_acting; + int new_primary = osd_id + 1; + new_acting.push_back(new_primary); + + map past_intervals; + + ASSERT_TRUE(past_intervals.empty()); + ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, + new_acting, + old_up, + new_up, + same_interval_since, + last_epoch_clean, + osdmap, + lastmap, + pool_id, + pgid, + &past_intervals)); + ASSERT_EQ((unsigned int)1, past_intervals.size()); + ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first); + ASSERT_EQ(osdmap->get_epoch() - 1, past_intervals[same_interval_since].last); + ASSERT_EQ(osd_id, past_intervals[same_interval_since].acting[0]); + ASSERT_EQ(osd_id, past_intervals[same_interval_since].up[0]); + } + + // + // The up set has changed + // + { + vector new_up; + int new_primary = osd_id + 1; + new_up.push_back(new_primary); + + map past_intervals; + + ASSERT_TRUE(past_intervals.empty()); + ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, + new_acting, + old_up, + new_up, + same_interval_since, + last_epoch_clean, + osdmap, + lastmap, + pool_id, + pgid, + &past_intervals)); + ASSERT_EQ((unsigned int)1, past_intervals.size()); + ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first); + ASSERT_EQ(osdmap->get_epoch() - 1, past_intervals[same_interval_since].last); + ASSERT_EQ(osd_id, past_intervals[same_interval_since].acting[0]); + ASSERT_EQ(osd_id, past_intervals[same_interval_since].up[0]); + } + + // + // PG is splitting + // + { + ceph::shared_ptr osdmap(new OSDMap()); + osdmap->set_max_osd(10); + osdmap->set_state(osd_id, CEPH_OSD_EXISTS); + osdmap->set_epoch(epoch); + int new_pg_num = pg_num ^ 2; + OSDMap::Incremental inc(epoch + 1); + inc.new_pools[pool_id].min_size = min_size; + inc.new_pools[pool_id].set_pg_num(new_pg_num); + osdmap->apply_incremental(inc); + + map past_intervals; + + ASSERT_TRUE(past_intervals.empty()); + ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, + new_acting, + old_up, + new_up, + same_interval_since, + last_epoch_clean, + osdmap, + lastmap, + pool_id, + pgid, + &past_intervals)); + ASSERT_EQ((unsigned int)1, past_intervals.size()); + ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first); + ASSERT_EQ(osdmap->get_epoch() - 1, past_intervals[same_interval_since].last); + ASSERT_EQ(osd_id, past_intervals[same_interval_since].acting[0]); + ASSERT_EQ(osd_id, past_intervals[same_interval_since].up[0]); + } + + // + // PG size has changed + // + { + ceph::shared_ptr osdmap(new OSDMap()); + osdmap->set_max_osd(10); + osdmap->set_state(osd_id, CEPH_OSD_EXISTS); + osdmap->set_epoch(epoch); + OSDMap::Incremental inc(epoch + 1); + __u8 new_min_size = min_size + 1; + inc.new_pools[pool_id].min_size = new_min_size; + inc.new_pools[pool_id].set_pg_num(pg_num); + osdmap->apply_incremental(inc); + + map past_intervals; + + ASSERT_TRUE(past_intervals.empty()); + ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, + new_acting, + old_up, + new_up, + same_interval_since, + last_epoch_clean, + osdmap, + lastmap, + pool_id, + pgid, + &past_intervals)); + ASSERT_EQ((unsigned int)1, past_intervals.size()); + ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first); + ASSERT_EQ(osdmap->get_epoch() - 1, past_intervals[same_interval_since].last); + ASSERT_EQ(osd_id, past_intervals[same_interval_since].acting[0]); + ASSERT_EQ(osd_id, past_intervals[same_interval_since].up[0]); + } + + // + // The old acting set was empty : the previous interval could not + // have been rw + // + { + vector old_acting; + + map past_intervals; + + ostringstream out; + + ASSERT_TRUE(past_intervals.empty()); + ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, + new_acting, + old_up, + new_up, + same_interval_since, + last_epoch_clean, + osdmap, + lastmap, + pool_id, + pgid, + &past_intervals, + &out)); + ASSERT_EQ((unsigned int)1, past_intervals.size()); + ASSERT_FALSE(past_intervals[same_interval_since].maybe_went_rw); + ASSERT_NE(string::npos, out.str().find("acting set is too small")); + } + + // + // The old acting set did not have enough osd : it could + // not have been rw + // + { + vector old_acting; + old_acting.push_back(osd_id); + + // + // see http://tracker.ceph.com/issues/5780 + // the size of the old acting set should be compared + // with the min_size of the old osdmap + // + // The new osdmap is created so that it triggers the + // bug. + // + ceph::shared_ptr osdmap(new OSDMap()); + osdmap->set_max_osd(10); + osdmap->set_state(osd_id, CEPH_OSD_EXISTS); + osdmap->set_epoch(epoch); + OSDMap::Incremental inc(epoch + 1); + __u8 new_min_size = old_acting.size(); + inc.new_pools[pool_id].min_size = new_min_size; + inc.new_pools[pool_id].set_pg_num(pg_num); + osdmap->apply_incremental(inc); + + ostringstream out; + + map past_intervals; + + ASSERT_TRUE(past_intervals.empty()); + ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, + new_acting, + old_up, + new_up, + same_interval_since, + last_epoch_clean, + osdmap, + lastmap, + pool_id, + pgid, + &past_intervals, + &out)); + ASSERT_EQ((unsigned int)1, past_intervals.size()); + ASSERT_FALSE(past_intervals[same_interval_since].maybe_went_rw); + ASSERT_NE(string::npos, out.str().find("acting set is too small")); + } + + // + // The acting set changes. The old acting set primary was up during the + // previous interval and may have been rw. + // + { + vector new_acting; + new_acting.push_back(osd_id + 4); + new_acting.push_back(osd_id + 5); + + ostringstream out; + + map past_intervals; + + ASSERT_TRUE(past_intervals.empty()); + ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, + new_acting, + old_up, + new_up, + same_interval_since, + last_epoch_clean, + osdmap, + lastmap, + pool_id, + pgid, + &past_intervals, + &out)); + ASSERT_EQ((unsigned int)1, past_intervals.size()); + ASSERT_TRUE(past_intervals[same_interval_since].maybe_went_rw); + ASSERT_NE(string::npos, out.str().find("includes interval")); + } + // + // The acting set changes. The old acting set primary was not up + // during the old interval but last_epoch_clean is in the + // old interval and it may have been rw. + // + { + vector new_acting; + new_acting.push_back(osd_id + 4); + new_acting.push_back(osd_id + 5); + + ceph::shared_ptr lastmap(new OSDMap()); + lastmap->set_max_osd(10); + lastmap->set_state(osd_id, CEPH_OSD_EXISTS); + lastmap->set_epoch(epoch); + OSDMap::Incremental inc(epoch + 1); + inc.new_pools[pool_id].min_size = min_size; + inc.new_pools[pool_id].set_pg_num(pg_num); + inc.new_up_thru[osd_id] = epoch - 10; + lastmap->apply_incremental(inc); + + ostringstream out; + + map past_intervals; + + ASSERT_TRUE(past_intervals.empty()); + ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, + new_acting, + old_up, + new_up, + same_interval_since, + last_epoch_clean, + osdmap, + lastmap, + pool_id, + pgid, + &past_intervals, + &out)); + ASSERT_EQ((unsigned int)1, past_intervals.size()); + ASSERT_TRUE(past_intervals[same_interval_since].maybe_went_rw); + ASSERT_NE(string::npos, out.str().find("presumed to have been rw")); + } + + // + // The acting set changes. The old acting set primary was not up + // during the old interval and last_epoch_clean is before the + // old interval : the previous interval could not possibly have + // been rw. + // + { + vector new_acting; + new_acting.push_back(osd_id + 4); + new_acting.push_back(osd_id + 5); + + epoch_t last_epoch_clean = epoch - 10; + + ceph::shared_ptr lastmap(new OSDMap()); + lastmap->set_max_osd(10); + lastmap->set_state(osd_id, CEPH_OSD_EXISTS); + lastmap->set_epoch(epoch); + OSDMap::Incremental inc(epoch + 1); + inc.new_pools[pool_id].min_size = min_size; + inc.new_pools[pool_id].set_pg_num(pg_num); + inc.new_up_thru[osd_id] = last_epoch_clean; + lastmap->apply_incremental(inc); + + ostringstream out; + + map past_intervals; + + ASSERT_TRUE(past_intervals.empty()); + ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, + new_acting, + old_up, + new_up, + same_interval_since, + last_epoch_clean, + osdmap, + lastmap, + pool_id, + pgid, + &past_intervals, + &out)); + ASSERT_EQ((unsigned int)1, past_intervals.size()); + ASSERT_FALSE(past_intervals[same_interval_since].maybe_went_rw); + ASSERT_NE(string::npos, out.str().find("does not include interval")); + } +} + +TEST(pg_t, split) +{ + pg_t pgid(0, 0, -1); + set s; + bool b; + + s.clear(); + b = pgid.is_split(1, 1, &s); + ASSERT_TRUE(!b); + + s.clear(); + b = pgid.is_split(2, 4, NULL); + ASSERT_TRUE(b); + b = pgid.is_split(2, 4, &s); + ASSERT_TRUE(b); + ASSERT_EQ(1u, s.size()); + ASSERT_TRUE(s.count(pg_t(2, 0, -1))); + + s.clear(); + b = pgid.is_split(2, 8, &s); + ASSERT_TRUE(b); + ASSERT_EQ(3u, s.size()); + ASSERT_TRUE(s.count(pg_t(2, 0, -1))); + ASSERT_TRUE(s.count(pg_t(4, 0, -1))); + ASSERT_TRUE(s.count(pg_t(6, 0, -1))); + + s.clear(); + b = pgid.is_split(3, 8, &s); + ASSERT_TRUE(b); + ASSERT_EQ(1u, s.size()); + ASSERT_TRUE(s.count(pg_t(4, 0, -1))); + + s.clear(); + b = pgid.is_split(6, 8, NULL); + ASSERT_TRUE(!b); + b = pgid.is_split(6, 8, &s); + ASSERT_TRUE(!b); + ASSERT_EQ(0u, s.size()); + + pgid = pg_t(1, 0, -1); + + s.clear(); + b = pgid.is_split(2, 4, &s); + ASSERT_TRUE(b); + ASSERT_EQ(1u, s.size()); + ASSERT_TRUE(s.count(pg_t(3, 0, -1))); + + s.clear(); + b = pgid.is_split(2, 6, &s); + ASSERT_TRUE(b); + ASSERT_EQ(2u, s.size()); + ASSERT_TRUE(s.count(pg_t(3, 0, -1))); + ASSERT_TRUE(s.count(pg_t(5, 0, -1))); + + s.clear(); + b = pgid.is_split(2, 8, &s); + ASSERT_TRUE(b); + ASSERT_EQ(3u, s.size()); + ASSERT_TRUE(s.count(pg_t(3, 0, -1))); + ASSERT_TRUE(s.count(pg_t(5, 0, -1))); + ASSERT_TRUE(s.count(pg_t(7, 0, -1))); + + s.clear(); + b = pgid.is_split(4, 8, &s); + ASSERT_TRUE(b); + ASSERT_EQ(1u, s.size()); + ASSERT_TRUE(s.count(pg_t(5, 0, -1))); + + s.clear(); + b = pgid.is_split(3, 8, &s); + ASSERT_TRUE(b); + ASSERT_EQ(3u, s.size()); + ASSERT_TRUE(s.count(pg_t(3, 0, -1))); + ASSERT_TRUE(s.count(pg_t(5, 0, -1))); + ASSERT_TRUE(s.count(pg_t(7, 0, -1))); + + s.clear(); + b = pgid.is_split(6, 8, &s); + ASSERT_TRUE(!b); + ASSERT_EQ(0u, s.size()); + + pgid = pg_t(3, 0, -1); + + s.clear(); + b = pgid.is_split(7, 8, &s); + ASSERT_TRUE(b); + ASSERT_EQ(1u, s.size()); + ASSERT_TRUE(s.count(pg_t(7, 0, -1))); + + s.clear(); + b = pgid.is_split(7, 12, &s); + ASSERT_TRUE(b); + ASSERT_EQ(2u, s.size()); + ASSERT_TRUE(s.count(pg_t(7, 0, -1))); + ASSERT_TRUE(s.count(pg_t(11, 0, -1))); + + s.clear(); + b = pgid.is_split(7, 11, &s); + ASSERT_TRUE(b); + ASSERT_EQ(1u, s.size()); + ASSERT_TRUE(s.count(pg_t(7, 0, -1))); + +} + +TEST(pg_missing_t, constructor) +{ + pg_missing_t missing; + EXPECT_EQ((unsigned int)0, missing.num_missing()); + EXPECT_FALSE(missing.have_missing()); +} + +TEST(pg_missing_t, have_missing) +{ + hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); + pg_missing_t missing; + EXPECT_FALSE(missing.have_missing()); + missing.add(oid, eversion_t(), eversion_t()); + EXPECT_TRUE(missing.have_missing()); +} + +TEST(pg_missing_t, swap) +{ + hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); + pg_missing_t missing; + EXPECT_FALSE(missing.have_missing()); + missing.add(oid, eversion_t(), eversion_t()); + EXPECT_TRUE(missing.have_missing()); + + pg_missing_t other; + EXPECT_FALSE(other.have_missing()); + + other.swap(missing); + EXPECT_FALSE(missing.have_missing()); + EXPECT_TRUE(other.have_missing()); +} + +TEST(pg_missing_t, is_missing) +{ + // pg_missing_t::is_missing(const hobject_t& oid) const + { + hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); + pg_missing_t missing; + EXPECT_FALSE(missing.is_missing(oid)); + missing.add(oid, eversion_t(), eversion_t()); + EXPECT_TRUE(missing.is_missing(oid)); + } + + // bool pg_missing_t::is_missing(const hobject_t& oid, eversion_t v) const + { + hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); + pg_missing_t missing; + eversion_t need(10,5); + EXPECT_FALSE(missing.is_missing(oid, eversion_t())); + missing.add(oid, need, eversion_t()); + EXPECT_TRUE(missing.is_missing(oid)); + EXPECT_FALSE(missing.is_missing(oid, eversion_t())); + EXPECT_TRUE(missing.is_missing(oid, need)); + } +} + +TEST(pg_missing_t, have_old) +{ + hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); + pg_missing_t missing; + EXPECT_EQ(eversion_t(), missing.have_old(oid)); + missing.add(oid, eversion_t(), eversion_t()); + EXPECT_EQ(eversion_t(), missing.have_old(oid)); + eversion_t have(1,1); + missing.revise_have(oid, have); + EXPECT_EQ(have, missing.have_old(oid)); +} + +TEST(pg_missing_t, add_next_event) +{ + hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); + hobject_t oid_other(object_t("other"), "key", 9123, 9456, 0, ""); + eversion_t version(10,5); + eversion_t prior_version(3,4); + pg_log_entry_t sample_e(pg_log_entry_t::DELETE, oid, version, prior_version, + 0, osd_reqid_t(entity_name_t::CLIENT(777), 8, 999), + utime_t(8,9)); + + // new object (MODIFY) + { + pg_missing_t missing; + pg_log_entry_t e = sample_e; + + e.op = pg_log_entry_t::MODIFY; + e.prior_version = eversion_t(); + EXPECT_TRUE(e.is_update()); + EXPECT_FALSE(missing.is_missing(oid)); + missing.add_next_event(e); + EXPECT_TRUE(missing.is_missing(oid)); + EXPECT_EQ(eversion_t(), missing.missing[oid].have); + EXPECT_EQ(oid, missing.rmissing[e.version.version]); + EXPECT_EQ(1U, missing.num_missing()); + EXPECT_EQ(1U, missing.rmissing.size()); + + // adding the same object replaces the previous one + missing.add_next_event(e); + EXPECT_TRUE(missing.is_missing(oid)); + EXPECT_EQ(1U, missing.num_missing()); + EXPECT_EQ(1U, missing.rmissing.size()); + } + + // new object (CLONE) + { + pg_missing_t missing; + pg_log_entry_t e = sample_e; + + e.op = pg_log_entry_t::CLONE; + e.prior_version = eversion_t(); + EXPECT_TRUE(e.is_clone()); + EXPECT_FALSE(missing.is_missing(oid)); + missing.add_next_event(e); + EXPECT_TRUE(missing.is_missing(oid)); + EXPECT_EQ(eversion_t(), missing.missing[oid].have); + EXPECT_EQ(oid, missing.rmissing[e.version.version]); + EXPECT_EQ(1U, missing.num_missing()); + EXPECT_EQ(1U, missing.rmissing.size()); + + // adding the same object replaces the previous one + missing.add_next_event(e); + EXPECT_TRUE(missing.is_missing(oid)); + EXPECT_EQ(1U, missing.num_missing()); + EXPECT_EQ(1U, missing.rmissing.size()); + } + + // existing object (MODIFY) + { + pg_missing_t missing; + pg_log_entry_t e = sample_e; + + e.op = pg_log_entry_t::MODIFY; + e.prior_version = eversion_t(); + EXPECT_TRUE(e.is_update()); + EXPECT_FALSE(missing.is_missing(oid)); + missing.add_next_event(e); + EXPECT_TRUE(missing.is_missing(oid)); + EXPECT_EQ(eversion_t(), missing.missing[oid].have); + EXPECT_EQ(oid, missing.rmissing[e.version.version]); + EXPECT_EQ(1U, missing.num_missing()); + EXPECT_EQ(1U, missing.rmissing.size()); + + // adding the same object with a different version + e.prior_version = prior_version; + missing.add_next_event(e); + EXPECT_EQ(eversion_t(), missing.missing[oid].have); + EXPECT_TRUE(missing.is_missing(oid)); + EXPECT_EQ(1U, missing.num_missing()); + EXPECT_EQ(1U, missing.rmissing.size()); + } + + // object with prior version (MODIFY) + { + pg_missing_t missing; + pg_log_entry_t e = sample_e; + + e.op = pg_log_entry_t::MODIFY; + EXPECT_TRUE(e.is_update()); + EXPECT_FALSE(missing.is_missing(oid)); + missing.add_next_event(e); + EXPECT_TRUE(missing.is_missing(oid)); + EXPECT_EQ(prior_version, missing.missing[oid].have); + EXPECT_EQ(version, missing.missing[oid].need); + EXPECT_EQ(oid, missing.rmissing[e.version.version]); + EXPECT_EQ(1U, missing.num_missing()); + EXPECT_EQ(1U, missing.rmissing.size()); + } + + // obsolete (BACKLOG) + { + pg_missing_t missing; + pg_log_entry_t e = sample_e; + + e.op = pg_log_entry_t::BACKLOG; + EXPECT_TRUE(e.is_backlog()); + EXPECT_FALSE(missing.is_missing(oid)); + EXPECT_THROW(missing.add_next_event(e), FailedAssertion); + } + + // adding a DELETE matching an existing event + { + pg_missing_t missing; + pg_log_entry_t e = sample_e; + + e.op = pg_log_entry_t::MODIFY; + EXPECT_TRUE(e.is_update()); + EXPECT_FALSE(missing.is_missing(oid)); + missing.add_next_event(e); + EXPECT_TRUE(missing.is_missing(oid)); + + e.op = pg_log_entry_t::DELETE; + EXPECT_TRUE(e.is_delete()); + missing.add_next_event(e); + EXPECT_FALSE(missing.have_missing()); + } +} + +TEST(pg_missing_t, revise_need) +{ + hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); + pg_missing_t missing; + // create a new entry + EXPECT_FALSE(missing.is_missing(oid)); + eversion_t need(10,10); + missing.revise_need(oid, need); + EXPECT_TRUE(missing.is_missing(oid)); + EXPECT_EQ(eversion_t(), missing.missing[oid].have); + EXPECT_EQ(need, missing.missing[oid].need); + // update an existing entry and preserve have + eversion_t have(1,1); + missing.revise_have(oid, have); + eversion_t new_need(10,12); + EXPECT_EQ(have, missing.missing[oid].have); + missing.revise_need(oid, new_need); + EXPECT_EQ(have, missing.missing[oid].have); + EXPECT_EQ(new_need, missing.missing[oid].need); +} + +TEST(pg_missing_t, revise_have) +{ + hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); + pg_missing_t missing; + // a non existing entry means noop + EXPECT_FALSE(missing.is_missing(oid)); + eversion_t have(1,1); + missing.revise_have(oid, have); + EXPECT_FALSE(missing.is_missing(oid)); + // update an existing entry + eversion_t need(10,12); + missing.add(oid, need, have); + EXPECT_TRUE(missing.is_missing(oid)); + eversion_t new_have(2,2); + EXPECT_EQ(have, missing.missing[oid].have); + missing.revise_have(oid, new_have); + EXPECT_EQ(new_have, missing.missing[oid].have); + EXPECT_EQ(need, missing.missing[oid].need); +} + +TEST(pg_missing_t, add) +{ + hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); + pg_missing_t missing; + EXPECT_FALSE(missing.is_missing(oid)); + eversion_t have(1,1); + eversion_t need(10,10); + missing.add(oid, need, have); + EXPECT_TRUE(missing.is_missing(oid)); + EXPECT_EQ(have, missing.missing[oid].have); + EXPECT_EQ(need, missing.missing[oid].need); +} + +TEST(pg_missing_t, rm) +{ + // void pg_missing_t::rm(const hobject_t& oid, eversion_t v) + { + hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); + pg_missing_t missing; + EXPECT_FALSE(missing.is_missing(oid)); + epoch_t epoch = 10; + eversion_t need(epoch,10); + missing.add(oid, need, eversion_t()); + EXPECT_TRUE(missing.is_missing(oid)); + // rm of an older version is a noop + missing.rm(oid, eversion_t(epoch / 2,20)); + EXPECT_TRUE(missing.is_missing(oid)); + // rm of a later version removes the object + missing.rm(oid, eversion_t(epoch * 2,20)); + EXPECT_FALSE(missing.is_missing(oid)); + } + // void pg_missing_t::rm(const std::map::iterator &m) + { + hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); + pg_missing_t missing; + EXPECT_FALSE(missing.is_missing(oid)); + missing.add(oid, eversion_t(), eversion_t()); + EXPECT_TRUE(missing.is_missing(oid)); + const std::map::iterator m = missing.missing.find(oid); + missing.rm(m); + EXPECT_FALSE(missing.is_missing(oid)); + } +} + +TEST(pg_missing_t, got) +{ + // void pg_missing_t::got(const hobject_t& oid, eversion_t v) + { + hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); + pg_missing_t missing; + // assert if the oid does not exist + EXPECT_THROW(missing.got(oid, eversion_t()), FailedAssertion); + EXPECT_FALSE(missing.is_missing(oid)); + epoch_t epoch = 10; + eversion_t need(epoch,10); + missing.add(oid, need, eversion_t()); + EXPECT_TRUE(missing.is_missing(oid)); + // assert if that the version to be removed is lower than the version of the object + EXPECT_THROW(missing.got(oid, eversion_t(epoch / 2,20)), FailedAssertion); + // remove of a later version removes the object + missing.got(oid, eversion_t(epoch * 2,20)); + EXPECT_FALSE(missing.is_missing(oid)); + } + // void pg_missing_t::got(const std::map::iterator &m) + { + hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); + pg_missing_t missing; + EXPECT_FALSE(missing.is_missing(oid)); + missing.add(oid, eversion_t(), eversion_t()); + EXPECT_TRUE(missing.is_missing(oid)); + const std::map::iterator m = missing.missing.find(oid); + missing.got(m); + EXPECT_FALSE(missing.is_missing(oid)); + } +} + +TEST(pg_missing_t, split_into) +{ + uint32_t hash1 = 1; + hobject_t oid1(object_t("objname"), "key1", 123, hash1, 0, ""); + uint32_t hash2 = 2; + hobject_t oid2(object_t("objname"), "key2", 123, hash2, 0, ""); + pg_missing_t missing; + missing.add(oid1, eversion_t(), eversion_t()); + missing.add(oid2, eversion_t(), eversion_t()); + pg_t child_pgid; + child_pgid.m_seed = 1; + pg_missing_t child; + unsigned split_bits = 1; + missing.split_into(child_pgid, split_bits, &child); + EXPECT_TRUE(child.is_missing(oid1)); + EXPECT_FALSE(child.is_missing(oid2)); + EXPECT_FALSE(missing.is_missing(oid1)); + EXPECT_TRUE(missing.is_missing(oid2)); +} + +class ObjectContextTest : public ::testing::Test { +protected: + + static const useconds_t DELAY_MAX = 20 * 1000 * 1000; + + class Thread_read_lock : public Thread { + public: + ObjectContext &obc; + + Thread_read_lock(ObjectContext& _obc) : + obc(_obc) + { + } + + virtual void *entry() { + obc.ondisk_read_lock(); + return NULL; + } + }; + + class Thread_write_lock : public Thread { + public: + ObjectContext &obc; + + Thread_write_lock(ObjectContext& _obc) : + obc(_obc) + { + } + + virtual void *entry() { + obc.ondisk_write_lock(); + return NULL; + } + }; + +}; + +TEST_F(ObjectContextTest, read_write_lock) +{ + { + ObjectContext obc; + + // + // write_lock + // write_lock + // write_unlock + // write_unlock + // + EXPECT_EQ(0, obc.writers_waiting); + EXPECT_EQ(0, obc.unstable_writes); + + obc.ondisk_write_lock(); + + EXPECT_EQ(0, obc.writers_waiting); + EXPECT_EQ(1, obc.unstable_writes); + + obc.ondisk_write_lock(); + + EXPECT_EQ(0, obc.writers_waiting); + EXPECT_EQ(2, obc.unstable_writes); + + obc.ondisk_write_unlock(); + + EXPECT_EQ(0, obc.writers_waiting); + EXPECT_EQ(1, obc.unstable_writes); + + obc.ondisk_write_unlock(); + + EXPECT_EQ(0, obc.writers_waiting); + EXPECT_EQ(0, obc.unstable_writes); + } + + useconds_t delay = 0; + + { + ObjectContext obc; + + // + // write_lock + // read_lock => wait + // write_unlock => signal + // read_unlock + // + EXPECT_EQ(0, obc.readers_waiting); + EXPECT_EQ(0, obc.readers); + EXPECT_EQ(0, obc.writers_waiting); + EXPECT_EQ(0, obc.unstable_writes); + + obc.ondisk_write_lock(); + + EXPECT_EQ(0, obc.readers_waiting); + EXPECT_EQ(0, obc.readers); + EXPECT_EQ(0, obc.writers_waiting); + EXPECT_EQ(1, obc.unstable_writes); + + Thread_read_lock t(obc); + t.create(); + + do { + cout << "Trying (1) with delay " << delay << "us\n"; + usleep(delay); + } while (obc.readers_waiting == 0 && + ( delay = delay * 2 + 1) < DELAY_MAX); + + EXPECT_EQ(1, obc.readers_waiting); + EXPECT_EQ(0, obc.readers); + EXPECT_EQ(0, obc.writers_waiting); + EXPECT_EQ(1, obc.unstable_writes); + + obc.ondisk_write_unlock(); + + do { + cout << "Trying (2) with delay " << delay << "us\n"; + usleep(delay); + } while ((obc.readers == 0 || obc.readers_waiting == 1) && + ( delay = delay * 2 + 1) < DELAY_MAX); + EXPECT_EQ(0, obc.readers_waiting); + EXPECT_EQ(1, obc.readers); + EXPECT_EQ(0, obc.writers_waiting); + EXPECT_EQ(0, obc.unstable_writes); + + obc.ondisk_read_unlock(); + + EXPECT_EQ(0, obc.readers_waiting); + EXPECT_EQ(0, obc.readers); + EXPECT_EQ(0, obc.writers_waiting); + EXPECT_EQ(0, obc.unstable_writes); + + t.join(); + } + + { + ObjectContext obc; + + // + // read_lock + // write_lock => wait + // read_unlock => signal + // write_unlock + // + EXPECT_EQ(0, obc.readers_waiting); + EXPECT_EQ(0, obc.readers); + EXPECT_EQ(0, obc.writers_waiting); + EXPECT_EQ(0, obc.unstable_writes); + + obc.ondisk_read_lock(); + + EXPECT_EQ(0, obc.readers_waiting); + EXPECT_EQ(1, obc.readers); + EXPECT_EQ(0, obc.writers_waiting); + EXPECT_EQ(0, obc.unstable_writes); + + Thread_write_lock t(obc); + t.create(); + + do { + cout << "Trying (3) with delay " << delay << "us\n"; + usleep(delay); + } while ((obc.writers_waiting == 0) && + ( delay = delay * 2 + 1) < DELAY_MAX); + + EXPECT_EQ(0, obc.readers_waiting); + EXPECT_EQ(1, obc.readers); + EXPECT_EQ(1, obc.writers_waiting); + EXPECT_EQ(0, obc.unstable_writes); + + obc.ondisk_read_unlock(); + + do { + cout << "Trying (4) with delay " << delay << "us\n"; + usleep(delay); + } while ((obc.unstable_writes == 0 || obc.writers_waiting == 1) && + ( delay = delay * 2 + 1) < DELAY_MAX); + + EXPECT_EQ(0, obc.readers_waiting); + EXPECT_EQ(0, obc.readers); + EXPECT_EQ(0, obc.writers_waiting); + EXPECT_EQ(1, obc.unstable_writes); + + obc.ondisk_write_unlock(); + + EXPECT_EQ(0, obc.readers_waiting); + EXPECT_EQ(0, obc.readers); + EXPECT_EQ(0, obc.writers_waiting); + EXPECT_EQ(0, obc.unstable_writes); + + t.join(); + } + +} + +TEST(pg_pool_t_test, get_pg_num_divisor) { + pg_pool_t p; + p.set_pg_num(16); + p.set_pgp_num(16); + + for (int i = 0; i < 16; ++i) + ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(i, 1))); + + p.set_pg_num(12); + p.set_pgp_num(12); + //cout << "num " << p.get_pg_num() + // << " mask " << p.get_pg_num_mask() << std::endl; + ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(0, 1))); + ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(1, 1))); + ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(2, 1))); + ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(3, 1))); + ASSERT_EQ(8u, p.get_pg_num_divisor(pg_t(4, 1))); + ASSERT_EQ(8u, p.get_pg_num_divisor(pg_t(5, 1))); + ASSERT_EQ(8u, p.get_pg_num_divisor(pg_t(6, 1))); + ASSERT_EQ(8u, p.get_pg_num_divisor(pg_t(7, 1))); + ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(8, 1))); + ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(9, 1))); + ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(10, 1))); + ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(11, 1))); +} + + +/* + * Local Variables: + * compile-command: "cd .. ; + * make unittest_osd_types ; + * ./unittest_osd_types # --gtest_filter=pg_missing_t.constructor + * " + * End: + */ diff --git a/src/test/test_osd_types.cc b/src/test/test_osd_types.cc deleted file mode 100644 index ed878695122..00000000000 --- a/src/test/test_osd_types.cc +++ /dev/null @@ -1,1198 +0,0 @@ -// -*- 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) 2011 New Dream Network - * Copyright (C) 2013 Cloudwatt - * - * Author: Loic Dachary - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License version 2, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#include "include/types.h" -#include "osd/osd_types.h" -#include "osd/OSDMap.h" -#include "gtest/gtest.h" -#include "common/Thread.h" - -#include - -TEST(hobject, prefixes0) -{ - uint32_t mask = 0xE947FA20; - uint32_t bits = 12; - int64_t pool = 0; - - set prefixes_correct; - prefixes_correct.insert(string("0000000000000000.02A")); - - set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); - ASSERT_EQ(prefixes_out, prefixes_correct); -} - -TEST(hobject, prefixes1) -{ - uint32_t mask = 0x0000000F; - uint32_t bits = 6; - int64_t pool = 20; - - set prefixes_correct; - prefixes_correct.insert(string("0000000000000014.F0")); - prefixes_correct.insert(string("0000000000000014.F4")); - prefixes_correct.insert(string("0000000000000014.F8")); - prefixes_correct.insert(string("0000000000000014.FC")); - - set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); - ASSERT_EQ(prefixes_out, prefixes_correct); -} - -TEST(hobject, prefixes2) -{ - uint32_t mask = 0xDEADBEAF; - uint32_t bits = 25; - int64_t pool = 0; - - set prefixes_correct; - prefixes_correct.insert(string("0000000000000000.FAEBDA0")); - prefixes_correct.insert(string("0000000000000000.FAEBDA2")); - prefixes_correct.insert(string("0000000000000000.FAEBDA4")); - prefixes_correct.insert(string("0000000000000000.FAEBDA6")); - prefixes_correct.insert(string("0000000000000000.FAEBDA8")); - prefixes_correct.insert(string("0000000000000000.FAEBDAA")); - prefixes_correct.insert(string("0000000000000000.FAEBDAC")); - prefixes_correct.insert(string("0000000000000000.FAEBDAE")); - - set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); - ASSERT_EQ(prefixes_out, prefixes_correct); -} - -TEST(hobject, prefixes3) -{ - uint32_t mask = 0xE947FA20; - uint32_t bits = 32; - int64_t pool = 0x23; - - set prefixes_correct; - prefixes_correct.insert(string("0000000000000023.02AF749E")); - - set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); - ASSERT_EQ(prefixes_out, prefixes_correct); -} - -TEST(hobject, prefixes4) -{ - uint32_t mask = 0xE947FA20; - uint32_t bits = 0; - int64_t pool = 0x23; - - set prefixes_correct; - prefixes_correct.insert(string("0000000000000023.")); - - set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); - ASSERT_EQ(prefixes_out, prefixes_correct); -} - -TEST(hobject, prefixes5) -{ - uint32_t mask = 0xDEADBEAF; - uint32_t bits = 1; - int64_t pool = 0x34AC5D00; - - set prefixes_correct; - prefixes_correct.insert(string("0000000034AC5D00.1")); - prefixes_correct.insert(string("0000000034AC5D00.3")); - prefixes_correct.insert(string("0000000034AC5D00.5")); - prefixes_correct.insert(string("0000000034AC5D00.7")); - prefixes_correct.insert(string("0000000034AC5D00.9")); - prefixes_correct.insert(string("0000000034AC5D00.B")); - prefixes_correct.insert(string("0000000034AC5D00.D")); - prefixes_correct.insert(string("0000000034AC5D00.F")); - - set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); - ASSERT_EQ(prefixes_out, prefixes_correct); -} - -TEST(pg_interval_t, check_new_interval) -{ - // - // Create a situation where osdmaps are the same so that - // each test case can diverge from it using minimal code. - // - int osd_id = 1; - epoch_t epoch = 40; - ceph::shared_ptr osdmap(new OSDMap()); - osdmap->set_max_osd(10); - osdmap->set_state(osd_id, CEPH_OSD_EXISTS); - osdmap->set_epoch(epoch); - ceph::shared_ptr lastmap(new OSDMap()); - lastmap->set_max_osd(10); - lastmap->set_state(osd_id, CEPH_OSD_EXISTS); - lastmap->set_epoch(epoch); - epoch_t same_interval_since = epoch; - epoch_t last_epoch_clean = same_interval_since; - int64_t pool_id = 200; - int pg_num = 4; - __u8 min_size = 2; - { - OSDMap::Incremental inc(epoch + 1); - inc.new_pools[pool_id].min_size = min_size; - inc.new_pools[pool_id].set_pg_num(pg_num); - inc.new_up_thru[osd_id] = epoch + 1; - osdmap->apply_incremental(inc); - lastmap->apply_incremental(inc); - } - vector new_acting; - new_acting.push_back(osd_id); - new_acting.push_back(osd_id + 1); - vector old_acting = new_acting; - vector new_up; - new_up.push_back(osd_id); - vector old_up = new_up; - pg_t pgid; - pgid.set_pool(pool_id); - - // - // Do nothing if there are no modifications in - // acting, up or pool size and that the pool is not - // being split - // - { - map past_intervals; - - ASSERT_TRUE(past_intervals.empty()); - ASSERT_FALSE(pg_interval_t::check_new_interval(old_acting, - new_acting, - old_up, - new_up, - same_interval_since, - last_epoch_clean, - osdmap, - lastmap, - pool_id, - pgid, - &past_intervals)); - ASSERT_TRUE(past_intervals.empty()); - } - - // - // pool did not exist in the old osdmap - // - { - ceph::shared_ptr lastmap(new OSDMap()); - lastmap->set_max_osd(10); - lastmap->set_state(osd_id, CEPH_OSD_EXISTS); - lastmap->set_epoch(epoch); - - map past_intervals; - - ASSERT_TRUE(past_intervals.empty()); - ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, - new_acting, - old_up, - new_up, - same_interval_since, - last_epoch_clean, - osdmap, - lastmap, - pool_id, - pgid, - &past_intervals)); - ASSERT_EQ((unsigned int)1, past_intervals.size()); - ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first); - ASSERT_EQ(osdmap->get_epoch() - 1, past_intervals[same_interval_since].last); - ASSERT_EQ(osd_id, past_intervals[same_interval_since].acting[0]); - ASSERT_EQ(osd_id, past_intervals[same_interval_since].up[0]); - } - - // - // The acting set has changed - // - { - vector new_acting; - int new_primary = osd_id + 1; - new_acting.push_back(new_primary); - - map past_intervals; - - ASSERT_TRUE(past_intervals.empty()); - ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, - new_acting, - old_up, - new_up, - same_interval_since, - last_epoch_clean, - osdmap, - lastmap, - pool_id, - pgid, - &past_intervals)); - ASSERT_EQ((unsigned int)1, past_intervals.size()); - ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first); - ASSERT_EQ(osdmap->get_epoch() - 1, past_intervals[same_interval_since].last); - ASSERT_EQ(osd_id, past_intervals[same_interval_since].acting[0]); - ASSERT_EQ(osd_id, past_intervals[same_interval_since].up[0]); - } - - // - // The up set has changed - // - { - vector new_up; - int new_primary = osd_id + 1; - new_up.push_back(new_primary); - - map past_intervals; - - ASSERT_TRUE(past_intervals.empty()); - ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, - new_acting, - old_up, - new_up, - same_interval_since, - last_epoch_clean, - osdmap, - lastmap, - pool_id, - pgid, - &past_intervals)); - ASSERT_EQ((unsigned int)1, past_intervals.size()); - ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first); - ASSERT_EQ(osdmap->get_epoch() - 1, past_intervals[same_interval_since].last); - ASSERT_EQ(osd_id, past_intervals[same_interval_since].acting[0]); - ASSERT_EQ(osd_id, past_intervals[same_interval_since].up[0]); - } - - // - // PG is splitting - // - { - ceph::shared_ptr osdmap(new OSDMap()); - osdmap->set_max_osd(10); - osdmap->set_state(osd_id, CEPH_OSD_EXISTS); - osdmap->set_epoch(epoch); - int new_pg_num = pg_num ^ 2; - OSDMap::Incremental inc(epoch + 1); - inc.new_pools[pool_id].min_size = min_size; - inc.new_pools[pool_id].set_pg_num(new_pg_num); - osdmap->apply_incremental(inc); - - map past_intervals; - - ASSERT_TRUE(past_intervals.empty()); - ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, - new_acting, - old_up, - new_up, - same_interval_since, - last_epoch_clean, - osdmap, - lastmap, - pool_id, - pgid, - &past_intervals)); - ASSERT_EQ((unsigned int)1, past_intervals.size()); - ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first); - ASSERT_EQ(osdmap->get_epoch() - 1, past_intervals[same_interval_since].last); - ASSERT_EQ(osd_id, past_intervals[same_interval_since].acting[0]); - ASSERT_EQ(osd_id, past_intervals[same_interval_since].up[0]); - } - - // - // PG size has changed - // - { - ceph::shared_ptr osdmap(new OSDMap()); - osdmap->set_max_osd(10); - osdmap->set_state(osd_id, CEPH_OSD_EXISTS); - osdmap->set_epoch(epoch); - OSDMap::Incremental inc(epoch + 1); - __u8 new_min_size = min_size + 1; - inc.new_pools[pool_id].min_size = new_min_size; - inc.new_pools[pool_id].set_pg_num(pg_num); - osdmap->apply_incremental(inc); - - map past_intervals; - - ASSERT_TRUE(past_intervals.empty()); - ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, - new_acting, - old_up, - new_up, - same_interval_since, - last_epoch_clean, - osdmap, - lastmap, - pool_id, - pgid, - &past_intervals)); - ASSERT_EQ((unsigned int)1, past_intervals.size()); - ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first); - ASSERT_EQ(osdmap->get_epoch() - 1, past_intervals[same_interval_since].last); - ASSERT_EQ(osd_id, past_intervals[same_interval_since].acting[0]); - ASSERT_EQ(osd_id, past_intervals[same_interval_since].up[0]); - } - - // - // The old acting set was empty : the previous interval could not - // have been rw - // - { - vector old_acting; - - map past_intervals; - - ostringstream out; - - ASSERT_TRUE(past_intervals.empty()); - ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, - new_acting, - old_up, - new_up, - same_interval_since, - last_epoch_clean, - osdmap, - lastmap, - pool_id, - pgid, - &past_intervals, - &out)); - ASSERT_EQ((unsigned int)1, past_intervals.size()); - ASSERT_FALSE(past_intervals[same_interval_since].maybe_went_rw); - ASSERT_NE(string::npos, out.str().find("acting set is too small")); - } - - // - // The old acting set did not have enough osd : it could - // not have been rw - // - { - vector old_acting; - old_acting.push_back(osd_id); - - // - // see http://tracker.ceph.com/issues/5780 - // the size of the old acting set should be compared - // with the min_size of the old osdmap - // - // The new osdmap is created so that it triggers the - // bug. - // - ceph::shared_ptr osdmap(new OSDMap()); - osdmap->set_max_osd(10); - osdmap->set_state(osd_id, CEPH_OSD_EXISTS); - osdmap->set_epoch(epoch); - OSDMap::Incremental inc(epoch + 1); - __u8 new_min_size = old_acting.size(); - inc.new_pools[pool_id].min_size = new_min_size; - inc.new_pools[pool_id].set_pg_num(pg_num); - osdmap->apply_incremental(inc); - - ostringstream out; - - map past_intervals; - - ASSERT_TRUE(past_intervals.empty()); - ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, - new_acting, - old_up, - new_up, - same_interval_since, - last_epoch_clean, - osdmap, - lastmap, - pool_id, - pgid, - &past_intervals, - &out)); - ASSERT_EQ((unsigned int)1, past_intervals.size()); - ASSERT_FALSE(past_intervals[same_interval_since].maybe_went_rw); - ASSERT_NE(string::npos, out.str().find("acting set is too small")); - } - - // - // The acting set changes. The old acting set primary was up during the - // previous interval and may have been rw. - // - { - vector new_acting; - new_acting.push_back(osd_id + 4); - new_acting.push_back(osd_id + 5); - - ostringstream out; - - map past_intervals; - - ASSERT_TRUE(past_intervals.empty()); - ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, - new_acting, - old_up, - new_up, - same_interval_since, - last_epoch_clean, - osdmap, - lastmap, - pool_id, - pgid, - &past_intervals, - &out)); - ASSERT_EQ((unsigned int)1, past_intervals.size()); - ASSERT_TRUE(past_intervals[same_interval_since].maybe_went_rw); - ASSERT_NE(string::npos, out.str().find("includes interval")); - } - // - // The acting set changes. The old acting set primary was not up - // during the old interval but last_epoch_clean is in the - // old interval and it may have been rw. - // - { - vector new_acting; - new_acting.push_back(osd_id + 4); - new_acting.push_back(osd_id + 5); - - ceph::shared_ptr lastmap(new OSDMap()); - lastmap->set_max_osd(10); - lastmap->set_state(osd_id, CEPH_OSD_EXISTS); - lastmap->set_epoch(epoch); - OSDMap::Incremental inc(epoch + 1); - inc.new_pools[pool_id].min_size = min_size; - inc.new_pools[pool_id].set_pg_num(pg_num); - inc.new_up_thru[osd_id] = epoch - 10; - lastmap->apply_incremental(inc); - - ostringstream out; - - map past_intervals; - - ASSERT_TRUE(past_intervals.empty()); - ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, - new_acting, - old_up, - new_up, - same_interval_since, - last_epoch_clean, - osdmap, - lastmap, - pool_id, - pgid, - &past_intervals, - &out)); - ASSERT_EQ((unsigned int)1, past_intervals.size()); - ASSERT_TRUE(past_intervals[same_interval_since].maybe_went_rw); - ASSERT_NE(string::npos, out.str().find("presumed to have been rw")); - } - - // - // The acting set changes. The old acting set primary was not up - // during the old interval and last_epoch_clean is before the - // old interval : the previous interval could not possibly have - // been rw. - // - { - vector new_acting; - new_acting.push_back(osd_id + 4); - new_acting.push_back(osd_id + 5); - - epoch_t last_epoch_clean = epoch - 10; - - ceph::shared_ptr lastmap(new OSDMap()); - lastmap->set_max_osd(10); - lastmap->set_state(osd_id, CEPH_OSD_EXISTS); - lastmap->set_epoch(epoch); - OSDMap::Incremental inc(epoch + 1); - inc.new_pools[pool_id].min_size = min_size; - inc.new_pools[pool_id].set_pg_num(pg_num); - inc.new_up_thru[osd_id] = last_epoch_clean; - lastmap->apply_incremental(inc); - - ostringstream out; - - map past_intervals; - - ASSERT_TRUE(past_intervals.empty()); - ASSERT_TRUE(pg_interval_t::check_new_interval(old_acting, - new_acting, - old_up, - new_up, - same_interval_since, - last_epoch_clean, - osdmap, - lastmap, - pool_id, - pgid, - &past_intervals, - &out)); - ASSERT_EQ((unsigned int)1, past_intervals.size()); - ASSERT_FALSE(past_intervals[same_interval_since].maybe_went_rw); - ASSERT_NE(string::npos, out.str().find("does not include interval")); - } -} - -TEST(pg_t, split) -{ - pg_t pgid(0, 0, -1); - set s; - bool b; - - s.clear(); - b = pgid.is_split(1, 1, &s); - ASSERT_TRUE(!b); - - s.clear(); - b = pgid.is_split(2, 4, NULL); - ASSERT_TRUE(b); - b = pgid.is_split(2, 4, &s); - ASSERT_TRUE(b); - ASSERT_EQ(1u, s.size()); - ASSERT_TRUE(s.count(pg_t(2, 0, -1))); - - s.clear(); - b = pgid.is_split(2, 8, &s); - ASSERT_TRUE(b); - ASSERT_EQ(3u, s.size()); - ASSERT_TRUE(s.count(pg_t(2, 0, -1))); - ASSERT_TRUE(s.count(pg_t(4, 0, -1))); - ASSERT_TRUE(s.count(pg_t(6, 0, -1))); - - s.clear(); - b = pgid.is_split(3, 8, &s); - ASSERT_TRUE(b); - ASSERT_EQ(1u, s.size()); - ASSERT_TRUE(s.count(pg_t(4, 0, -1))); - - s.clear(); - b = pgid.is_split(6, 8, NULL); - ASSERT_TRUE(!b); - b = pgid.is_split(6, 8, &s); - ASSERT_TRUE(!b); - ASSERT_EQ(0u, s.size()); - - pgid = pg_t(1, 0, -1); - - s.clear(); - b = pgid.is_split(2, 4, &s); - ASSERT_TRUE(b); - ASSERT_EQ(1u, s.size()); - ASSERT_TRUE(s.count(pg_t(3, 0, -1))); - - s.clear(); - b = pgid.is_split(2, 6, &s); - ASSERT_TRUE(b); - ASSERT_EQ(2u, s.size()); - ASSERT_TRUE(s.count(pg_t(3, 0, -1))); - ASSERT_TRUE(s.count(pg_t(5, 0, -1))); - - s.clear(); - b = pgid.is_split(2, 8, &s); - ASSERT_TRUE(b); - ASSERT_EQ(3u, s.size()); - ASSERT_TRUE(s.count(pg_t(3, 0, -1))); - ASSERT_TRUE(s.count(pg_t(5, 0, -1))); - ASSERT_TRUE(s.count(pg_t(7, 0, -1))); - - s.clear(); - b = pgid.is_split(4, 8, &s); - ASSERT_TRUE(b); - ASSERT_EQ(1u, s.size()); - ASSERT_TRUE(s.count(pg_t(5, 0, -1))); - - s.clear(); - b = pgid.is_split(3, 8, &s); - ASSERT_TRUE(b); - ASSERT_EQ(3u, s.size()); - ASSERT_TRUE(s.count(pg_t(3, 0, -1))); - ASSERT_TRUE(s.count(pg_t(5, 0, -1))); - ASSERT_TRUE(s.count(pg_t(7, 0, -1))); - - s.clear(); - b = pgid.is_split(6, 8, &s); - ASSERT_TRUE(!b); - ASSERT_EQ(0u, s.size()); - - pgid = pg_t(3, 0, -1); - - s.clear(); - b = pgid.is_split(7, 8, &s); - ASSERT_TRUE(b); - ASSERT_EQ(1u, s.size()); - ASSERT_TRUE(s.count(pg_t(7, 0, -1))); - - s.clear(); - b = pgid.is_split(7, 12, &s); - ASSERT_TRUE(b); - ASSERT_EQ(2u, s.size()); - ASSERT_TRUE(s.count(pg_t(7, 0, -1))); - ASSERT_TRUE(s.count(pg_t(11, 0, -1))); - - s.clear(); - b = pgid.is_split(7, 11, &s); - ASSERT_TRUE(b); - ASSERT_EQ(1u, s.size()); - ASSERT_TRUE(s.count(pg_t(7, 0, -1))); - -} - -TEST(pg_missing_t, constructor) -{ - pg_missing_t missing; - EXPECT_EQ((unsigned int)0, missing.num_missing()); - EXPECT_FALSE(missing.have_missing()); -} - -TEST(pg_missing_t, have_missing) -{ - hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); - pg_missing_t missing; - EXPECT_FALSE(missing.have_missing()); - missing.add(oid, eversion_t(), eversion_t()); - EXPECT_TRUE(missing.have_missing()); -} - -TEST(pg_missing_t, swap) -{ - hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); - pg_missing_t missing; - EXPECT_FALSE(missing.have_missing()); - missing.add(oid, eversion_t(), eversion_t()); - EXPECT_TRUE(missing.have_missing()); - - pg_missing_t other; - EXPECT_FALSE(other.have_missing()); - - other.swap(missing); - EXPECT_FALSE(missing.have_missing()); - EXPECT_TRUE(other.have_missing()); -} - -TEST(pg_missing_t, is_missing) -{ - // pg_missing_t::is_missing(const hobject_t& oid) const - { - hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); - pg_missing_t missing; - EXPECT_FALSE(missing.is_missing(oid)); - missing.add(oid, eversion_t(), eversion_t()); - EXPECT_TRUE(missing.is_missing(oid)); - } - - // bool pg_missing_t::is_missing(const hobject_t& oid, eversion_t v) const - { - hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); - pg_missing_t missing; - eversion_t need(10,5); - EXPECT_FALSE(missing.is_missing(oid, eversion_t())); - missing.add(oid, need, eversion_t()); - EXPECT_TRUE(missing.is_missing(oid)); - EXPECT_FALSE(missing.is_missing(oid, eversion_t())); - EXPECT_TRUE(missing.is_missing(oid, need)); - } -} - -TEST(pg_missing_t, have_old) -{ - hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); - pg_missing_t missing; - EXPECT_EQ(eversion_t(), missing.have_old(oid)); - missing.add(oid, eversion_t(), eversion_t()); - EXPECT_EQ(eversion_t(), missing.have_old(oid)); - eversion_t have(1,1); - missing.revise_have(oid, have); - EXPECT_EQ(have, missing.have_old(oid)); -} - -TEST(pg_missing_t, add_next_event) -{ - hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); - hobject_t oid_other(object_t("other"), "key", 9123, 9456, 0, ""); - eversion_t version(10,5); - eversion_t prior_version(3,4); - pg_log_entry_t sample_e(pg_log_entry_t::DELETE, oid, version, prior_version, - 0, osd_reqid_t(entity_name_t::CLIENT(777), 8, 999), - utime_t(8,9)); - - // new object (MODIFY) - { - pg_missing_t missing; - pg_log_entry_t e = sample_e; - - e.op = pg_log_entry_t::MODIFY; - e.prior_version = eversion_t(); - EXPECT_TRUE(e.is_update()); - EXPECT_FALSE(missing.is_missing(oid)); - missing.add_next_event(e); - EXPECT_TRUE(missing.is_missing(oid)); - EXPECT_EQ(eversion_t(), missing.missing[oid].have); - EXPECT_EQ(oid, missing.rmissing[e.version.version]); - EXPECT_EQ(1U, missing.num_missing()); - EXPECT_EQ(1U, missing.rmissing.size()); - - // adding the same object replaces the previous one - missing.add_next_event(e); - EXPECT_TRUE(missing.is_missing(oid)); - EXPECT_EQ(1U, missing.num_missing()); - EXPECT_EQ(1U, missing.rmissing.size()); - } - - // new object (CLONE) - { - pg_missing_t missing; - pg_log_entry_t e = sample_e; - - e.op = pg_log_entry_t::CLONE; - e.prior_version = eversion_t(); - EXPECT_TRUE(e.is_clone()); - EXPECT_FALSE(missing.is_missing(oid)); - missing.add_next_event(e); - EXPECT_TRUE(missing.is_missing(oid)); - EXPECT_EQ(eversion_t(), missing.missing[oid].have); - EXPECT_EQ(oid, missing.rmissing[e.version.version]); - EXPECT_EQ(1U, missing.num_missing()); - EXPECT_EQ(1U, missing.rmissing.size()); - - // adding the same object replaces the previous one - missing.add_next_event(e); - EXPECT_TRUE(missing.is_missing(oid)); - EXPECT_EQ(1U, missing.num_missing()); - EXPECT_EQ(1U, missing.rmissing.size()); - } - - // existing object (MODIFY) - { - pg_missing_t missing; - pg_log_entry_t e = sample_e; - - e.op = pg_log_entry_t::MODIFY; - e.prior_version = eversion_t(); - EXPECT_TRUE(e.is_update()); - EXPECT_FALSE(missing.is_missing(oid)); - missing.add_next_event(e); - EXPECT_TRUE(missing.is_missing(oid)); - EXPECT_EQ(eversion_t(), missing.missing[oid].have); - EXPECT_EQ(oid, missing.rmissing[e.version.version]); - EXPECT_EQ(1U, missing.num_missing()); - EXPECT_EQ(1U, missing.rmissing.size()); - - // adding the same object with a different version - e.prior_version = prior_version; - missing.add_next_event(e); - EXPECT_EQ(eversion_t(), missing.missing[oid].have); - EXPECT_TRUE(missing.is_missing(oid)); - EXPECT_EQ(1U, missing.num_missing()); - EXPECT_EQ(1U, missing.rmissing.size()); - } - - // object with prior version (MODIFY) - { - pg_missing_t missing; - pg_log_entry_t e = sample_e; - - e.op = pg_log_entry_t::MODIFY; - EXPECT_TRUE(e.is_update()); - EXPECT_FALSE(missing.is_missing(oid)); - missing.add_next_event(e); - EXPECT_TRUE(missing.is_missing(oid)); - EXPECT_EQ(prior_version, missing.missing[oid].have); - EXPECT_EQ(version, missing.missing[oid].need); - EXPECT_EQ(oid, missing.rmissing[e.version.version]); - EXPECT_EQ(1U, missing.num_missing()); - EXPECT_EQ(1U, missing.rmissing.size()); - } - - // obsolete (BACKLOG) - { - pg_missing_t missing; - pg_log_entry_t e = sample_e; - - e.op = pg_log_entry_t::BACKLOG; - EXPECT_TRUE(e.is_backlog()); - EXPECT_FALSE(missing.is_missing(oid)); - EXPECT_THROW(missing.add_next_event(e), FailedAssertion); - } - - // adding a DELETE matching an existing event - { - pg_missing_t missing; - pg_log_entry_t e = sample_e; - - e.op = pg_log_entry_t::MODIFY; - EXPECT_TRUE(e.is_update()); - EXPECT_FALSE(missing.is_missing(oid)); - missing.add_next_event(e); - EXPECT_TRUE(missing.is_missing(oid)); - - e.op = pg_log_entry_t::DELETE; - EXPECT_TRUE(e.is_delete()); - missing.add_next_event(e); - EXPECT_FALSE(missing.have_missing()); - } -} - -TEST(pg_missing_t, revise_need) -{ - hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); - pg_missing_t missing; - // create a new entry - EXPECT_FALSE(missing.is_missing(oid)); - eversion_t need(10,10); - missing.revise_need(oid, need); - EXPECT_TRUE(missing.is_missing(oid)); - EXPECT_EQ(eversion_t(), missing.missing[oid].have); - EXPECT_EQ(need, missing.missing[oid].need); - // update an existing entry and preserve have - eversion_t have(1,1); - missing.revise_have(oid, have); - eversion_t new_need(10,12); - EXPECT_EQ(have, missing.missing[oid].have); - missing.revise_need(oid, new_need); - EXPECT_EQ(have, missing.missing[oid].have); - EXPECT_EQ(new_need, missing.missing[oid].need); -} - -TEST(pg_missing_t, revise_have) -{ - hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); - pg_missing_t missing; - // a non existing entry means noop - EXPECT_FALSE(missing.is_missing(oid)); - eversion_t have(1,1); - missing.revise_have(oid, have); - EXPECT_FALSE(missing.is_missing(oid)); - // update an existing entry - eversion_t need(10,12); - missing.add(oid, need, have); - EXPECT_TRUE(missing.is_missing(oid)); - eversion_t new_have(2,2); - EXPECT_EQ(have, missing.missing[oid].have); - missing.revise_have(oid, new_have); - EXPECT_EQ(new_have, missing.missing[oid].have); - EXPECT_EQ(need, missing.missing[oid].need); -} - -TEST(pg_missing_t, add) -{ - hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); - pg_missing_t missing; - EXPECT_FALSE(missing.is_missing(oid)); - eversion_t have(1,1); - eversion_t need(10,10); - missing.add(oid, need, have); - EXPECT_TRUE(missing.is_missing(oid)); - EXPECT_EQ(have, missing.missing[oid].have); - EXPECT_EQ(need, missing.missing[oid].need); -} - -TEST(pg_missing_t, rm) -{ - // void pg_missing_t::rm(const hobject_t& oid, eversion_t v) - { - hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); - pg_missing_t missing; - EXPECT_FALSE(missing.is_missing(oid)); - epoch_t epoch = 10; - eversion_t need(epoch,10); - missing.add(oid, need, eversion_t()); - EXPECT_TRUE(missing.is_missing(oid)); - // rm of an older version is a noop - missing.rm(oid, eversion_t(epoch / 2,20)); - EXPECT_TRUE(missing.is_missing(oid)); - // rm of a later version removes the object - missing.rm(oid, eversion_t(epoch * 2,20)); - EXPECT_FALSE(missing.is_missing(oid)); - } - // void pg_missing_t::rm(const std::map::iterator &m) - { - hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); - pg_missing_t missing; - EXPECT_FALSE(missing.is_missing(oid)); - missing.add(oid, eversion_t(), eversion_t()); - EXPECT_TRUE(missing.is_missing(oid)); - const std::map::iterator m = missing.missing.find(oid); - missing.rm(m); - EXPECT_FALSE(missing.is_missing(oid)); - } -} - -TEST(pg_missing_t, got) -{ - // void pg_missing_t::got(const hobject_t& oid, eversion_t v) - { - hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); - pg_missing_t missing; - // assert if the oid does not exist - EXPECT_THROW(missing.got(oid, eversion_t()), FailedAssertion); - EXPECT_FALSE(missing.is_missing(oid)); - epoch_t epoch = 10; - eversion_t need(epoch,10); - missing.add(oid, need, eversion_t()); - EXPECT_TRUE(missing.is_missing(oid)); - // assert if that the version to be removed is lower than the version of the object - EXPECT_THROW(missing.got(oid, eversion_t(epoch / 2,20)), FailedAssertion); - // remove of a later version removes the object - missing.got(oid, eversion_t(epoch * 2,20)); - EXPECT_FALSE(missing.is_missing(oid)); - } - // void pg_missing_t::got(const std::map::iterator &m) - { - hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); - pg_missing_t missing; - EXPECT_FALSE(missing.is_missing(oid)); - missing.add(oid, eversion_t(), eversion_t()); - EXPECT_TRUE(missing.is_missing(oid)); - const std::map::iterator m = missing.missing.find(oid); - missing.got(m); - EXPECT_FALSE(missing.is_missing(oid)); - } -} - -TEST(pg_missing_t, split_into) -{ - uint32_t hash1 = 1; - hobject_t oid1(object_t("objname"), "key1", 123, hash1, 0, ""); - uint32_t hash2 = 2; - hobject_t oid2(object_t("objname"), "key2", 123, hash2, 0, ""); - pg_missing_t missing; - missing.add(oid1, eversion_t(), eversion_t()); - missing.add(oid2, eversion_t(), eversion_t()); - pg_t child_pgid; - child_pgid.m_seed = 1; - pg_missing_t child; - unsigned split_bits = 1; - missing.split_into(child_pgid, split_bits, &child); - EXPECT_TRUE(child.is_missing(oid1)); - EXPECT_FALSE(child.is_missing(oid2)); - EXPECT_FALSE(missing.is_missing(oid1)); - EXPECT_TRUE(missing.is_missing(oid2)); -} - -class ObjectContextTest : public ::testing::Test { -protected: - - static const useconds_t DELAY_MAX = 20 * 1000 * 1000; - - class Thread_read_lock : public Thread { - public: - ObjectContext &obc; - - Thread_read_lock(ObjectContext& _obc) : - obc(_obc) - { - } - - virtual void *entry() { - obc.ondisk_read_lock(); - return NULL; - } - }; - - class Thread_write_lock : public Thread { - public: - ObjectContext &obc; - - Thread_write_lock(ObjectContext& _obc) : - obc(_obc) - { - } - - virtual void *entry() { - obc.ondisk_write_lock(); - return NULL; - } - }; - -}; - -TEST_F(ObjectContextTest, read_write_lock) -{ - { - ObjectContext obc; - - // - // write_lock - // write_lock - // write_unlock - // write_unlock - // - EXPECT_EQ(0, obc.writers_waiting); - EXPECT_EQ(0, obc.unstable_writes); - - obc.ondisk_write_lock(); - - EXPECT_EQ(0, obc.writers_waiting); - EXPECT_EQ(1, obc.unstable_writes); - - obc.ondisk_write_lock(); - - EXPECT_EQ(0, obc.writers_waiting); - EXPECT_EQ(2, obc.unstable_writes); - - obc.ondisk_write_unlock(); - - EXPECT_EQ(0, obc.writers_waiting); - EXPECT_EQ(1, obc.unstable_writes); - - obc.ondisk_write_unlock(); - - EXPECT_EQ(0, obc.writers_waiting); - EXPECT_EQ(0, obc.unstable_writes); - } - - useconds_t delay = 0; - - { - ObjectContext obc; - - // - // write_lock - // read_lock => wait - // write_unlock => signal - // read_unlock - // - EXPECT_EQ(0, obc.readers_waiting); - EXPECT_EQ(0, obc.readers); - EXPECT_EQ(0, obc.writers_waiting); - EXPECT_EQ(0, obc.unstable_writes); - - obc.ondisk_write_lock(); - - EXPECT_EQ(0, obc.readers_waiting); - EXPECT_EQ(0, obc.readers); - EXPECT_EQ(0, obc.writers_waiting); - EXPECT_EQ(1, obc.unstable_writes); - - Thread_read_lock t(obc); - t.create(); - - do { - cout << "Trying (1) with delay " << delay << "us\n"; - usleep(delay); - } while (obc.readers_waiting == 0 && - ( delay = delay * 2 + 1) < DELAY_MAX); - - EXPECT_EQ(1, obc.readers_waiting); - EXPECT_EQ(0, obc.readers); - EXPECT_EQ(0, obc.writers_waiting); - EXPECT_EQ(1, obc.unstable_writes); - - obc.ondisk_write_unlock(); - - do { - cout << "Trying (2) with delay " << delay << "us\n"; - usleep(delay); - } while ((obc.readers == 0 || obc.readers_waiting == 1) && - ( delay = delay * 2 + 1) < DELAY_MAX); - EXPECT_EQ(0, obc.readers_waiting); - EXPECT_EQ(1, obc.readers); - EXPECT_EQ(0, obc.writers_waiting); - EXPECT_EQ(0, obc.unstable_writes); - - obc.ondisk_read_unlock(); - - EXPECT_EQ(0, obc.readers_waiting); - EXPECT_EQ(0, obc.readers); - EXPECT_EQ(0, obc.writers_waiting); - EXPECT_EQ(0, obc.unstable_writes); - - t.join(); - } - - { - ObjectContext obc; - - // - // read_lock - // write_lock => wait - // read_unlock => signal - // write_unlock - // - EXPECT_EQ(0, obc.readers_waiting); - EXPECT_EQ(0, obc.readers); - EXPECT_EQ(0, obc.writers_waiting); - EXPECT_EQ(0, obc.unstable_writes); - - obc.ondisk_read_lock(); - - EXPECT_EQ(0, obc.readers_waiting); - EXPECT_EQ(1, obc.readers); - EXPECT_EQ(0, obc.writers_waiting); - EXPECT_EQ(0, obc.unstable_writes); - - Thread_write_lock t(obc); - t.create(); - - do { - cout << "Trying (3) with delay " << delay << "us\n"; - usleep(delay); - } while ((obc.writers_waiting == 0) && - ( delay = delay * 2 + 1) < DELAY_MAX); - - EXPECT_EQ(0, obc.readers_waiting); - EXPECT_EQ(1, obc.readers); - EXPECT_EQ(1, obc.writers_waiting); - EXPECT_EQ(0, obc.unstable_writes); - - obc.ondisk_read_unlock(); - - do { - cout << "Trying (4) with delay " << delay << "us\n"; - usleep(delay); - } while ((obc.unstable_writes == 0 || obc.writers_waiting == 1) && - ( delay = delay * 2 + 1) < DELAY_MAX); - - EXPECT_EQ(0, obc.readers_waiting); - EXPECT_EQ(0, obc.readers); - EXPECT_EQ(0, obc.writers_waiting); - EXPECT_EQ(1, obc.unstable_writes); - - obc.ondisk_write_unlock(); - - EXPECT_EQ(0, obc.readers_waiting); - EXPECT_EQ(0, obc.readers); - EXPECT_EQ(0, obc.writers_waiting); - EXPECT_EQ(0, obc.unstable_writes); - - t.join(); - } - -} - -TEST(pg_pool_t_test, get_pg_num_divisor) { - pg_pool_t p; - p.set_pg_num(16); - p.set_pgp_num(16); - - for (int i = 0; i < 16; ++i) - ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(i, 1))); - - p.set_pg_num(12); - p.set_pgp_num(12); - //cout << "num " << p.get_pg_num() - // << " mask " << p.get_pg_num_mask() << std::endl; - ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(0, 1))); - ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(1, 1))); - ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(2, 1))); - ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(3, 1))); - ASSERT_EQ(8u, p.get_pg_num_divisor(pg_t(4, 1))); - ASSERT_EQ(8u, p.get_pg_num_divisor(pg_t(5, 1))); - ASSERT_EQ(8u, p.get_pg_num_divisor(pg_t(6, 1))); - ASSERT_EQ(8u, p.get_pg_num_divisor(pg_t(7, 1))); - ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(8, 1))); - ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(9, 1))); - ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(10, 1))); - ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(11, 1))); -} - - -/* - * Local Variables: - * compile-command: "cd .. ; - * make unittest_osd_types ; - * ./unittest_osd_types # --gtest_filter=pg_missing_t.constructor - * " - * End: - */ -