If the pool's min_size is set improperly, during peering, pg_interval_t::check_new_interval
might wrongly determine the PG's state and cause the PG to stuck at down+peering forever
Fixes: #12162
Signed-off-by: Guang Yang yguang@yahoo-inc.com
}
assert(last_map);
+ boost::scoped_ptr<IsPGRecoverablePredicate> recoverable(
+ pg->get_is_recoverable_predicate());
std::stringstream debug;
bool new_interval = pg_interval_t::check_new_interval(
p.primary,
pg->info.history.last_epoch_clean,
cur_map, last_map,
pgid,
+ recoverable.get(),
&pg->past_intervals,
&debug);
if (new_interval) {
pgid = pgid.get_ancestor(last_map->get_pg_num(pgid.pool()));
cur_map->pg_to_up_acting_osds(pgid, &up, &up_primary, &acting, &primary);
+ boost::scoped_ptr<IsPGRecoverablePredicate> recoverable(
+ get_is_recoverable_predicate());
std::stringstream debug;
bool new_interval = pg_interval_t::check_new_interval(
old_primary,
cur_map,
last_map,
pgid,
+ recoverable.get(),
&past_intervals,
&debug);
if (new_interval) {
} else {
std::stringstream debug;
assert(info.history.same_interval_since != 0);
+ boost::scoped_ptr<IsPGRecoverablePredicate> recoverable(
+ get_is_recoverable_predicate());
bool new_interval = pg_interval_t::check_new_interval(
old_acting_primary.osd,
new_acting_primary,
osdmap,
lastmap,
info.pgid.pgid,
+ recoverable.get(),
&past_intervals,
&debug);
dout(10) << __func__ << ": check_new_interval output: "
void update_snap_mapper_bits(uint32_t bits) {
snap_mapper.update_bits(bits);
}
+ /// get_is_recoverable_predicate: caller owns returned pointer and must delete when done
+ IsPGRecoverablePredicate *get_is_recoverable_predicate() {
+ return get_pgbackend()->get_is_recoverable_predicate();
+ }
protected:
// Ops waiting for map, should be queued at back
Mutex map_lock;
f->dump_unsigned("expected_num_objects", expected_num_objects);
}
+void pg_pool_t::convert_to_pg_shards(const vector<int> &from, set<pg_shard_t>* to) const {
+ for (size_t i = 0; i < from.size(); ++i) {
+ if (from[i] != CRUSH_ITEM_NONE) {
+ to->insert(
+ pg_shard_t(
+ from[i],
+ ec_pool() ? shard_id_t(i) : shard_id_t::NO_SHARD));
+ }
+ }
+}
int pg_pool_t::calc_bits_of(int t)
{
OSDMapRef osdmap,
OSDMapRef lastmap,
pg_t pgid,
+ IsPGRecoverablePredicate *could_have_gone_active,
map<epoch_t, pg_interval_t> *past_intervals,
std::ostream *out)
{
if (*p != CRUSH_ITEM_NONE)
++num_acting;
+ const pg_pool_t& old_pg_pool = lastmap->get_pools().find(pgid.pool())->second;
+ set<pg_shard_t> old_acting_shards;
+ old_pg_pool.convert_to_pg_shards(old_acting, &old_acting_shards);
+
if (num_acting &&
i.primary != -1 &&
- num_acting >= lastmap->get_pools().find(pgid.pool())->second.min_size) {
+ num_acting >= old_pg_pool.min_size &&
+ (*could_have_gone_active)(old_acting_shards)) {
if (out)
*out << "generate_past_intervals " << i
<< ": not rw,"
return 0;
}
+ /// converts the acting/up vector to a set of pg shards
+ void convert_to_pg_shards(const vector<int> &from, set<pg_shard_t>* to) const;
+
typedef enum {
CACHEMODE_NONE = 0, ///< no caching
CACHEMODE_WRITEBACK = 1, ///< write to cache, flush later
ceph::shared_ptr<const OSDMap> osdmap, ///< [in] current map
ceph::shared_ptr<const OSDMap> lastmap, ///< [in] last map
pg_t pgid, ///< [in] pgid for pg
+ IsPGRecoverablePredicate *could_have_gone_active, /// [in] predicate whether the pg can be active
map<epoch_t, pg_interval_t> *past_intervals,///< [out] intervals
ostream *out = 0 ///< [out] debug ostream
);
#include "gtest/gtest.h"
#include "common/Thread.h"
#include "include/stringify.h"
+#include "osd/ReplicatedBackend.h"
#include <sstream>
int64_t pool_id = 200;
int pg_num = 4;
__u8 min_size = 2;
+ boost::scoped_ptr<IsPGRecoverablePredicate> recoverable(new ReplicatedBackend::RPCRecPred());
{
OSDMap::Incremental inc(epoch + 1);
inc.new_pools[pool_id].min_size = min_size;
osdmap,
lastmap,
pgid,
+ recoverable.get(),
&past_intervals));
ASSERT_TRUE(past_intervals.empty());
}
osdmap,
lastmap,
pgid,
+ recoverable.get(),
&past_intervals));
ASSERT_EQ((unsigned int)1, past_intervals.size());
ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first);
osdmap,
lastmap,
pgid,
+ recoverable.get(),
&past_intervals));
old_primary = new_primary;
ASSERT_EQ((unsigned int)1, past_intervals.size());
osdmap,
lastmap,
pgid,
+ recoverable.get(),
&past_intervals));
ASSERT_EQ((unsigned int)1, past_intervals.size());
ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first);
osdmap,
lastmap,
pgid,
+ recoverable.get(),
&past_intervals));
ASSERT_EQ((unsigned int)1, past_intervals.size());
ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first);
osdmap,
lastmap,
pgid,
+ recoverable.get(),
&past_intervals));
ASSERT_EQ((unsigned int)1, past_intervals.size());
ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first);
osdmap,
lastmap,
pgid,
+ recoverable.get(),
&past_intervals));
ASSERT_EQ((unsigned int)1, past_intervals.size());
ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first);
osdmap,
lastmap,
pgid,
+ recoverable.get(),
&past_intervals,
&out));
ASSERT_EQ((unsigned int)1, past_intervals.size());
osdmap,
lastmap,
pgid,
+ recoverable.get(),
&past_intervals,
&out));
ASSERT_EQ((unsigned int)1, past_intervals.size());
osdmap,
lastmap,
pgid,
+ recoverable.get(),
&past_intervals,
&out));
ASSERT_EQ((unsigned int)1, past_intervals.size());
osdmap,
lastmap,
pgid,
+ recoverable.get(),
&past_intervals,
&out));
ASSERT_EQ((unsigned int)1, past_intervals.size());
osdmap,
lastmap,
pgid,
+ recoverable.get(),
&past_intervals,
&out));
ASSERT_EQ((unsigned int)1, past_intervals.size());