~ubuntu-branches/ubuntu/raring/ceph/raring

« back to all changes in this revision

Viewing changes to src/mon/PGMonitor.cc

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2012-06-08 15:54:37 UTC
  • mfrom: (1.1.8) (0.1.13 sid)
  • Revision ID: package-import@ubuntu.com-20120608155437-gy3j9k6wzv7w4gn9
Tags: 0.44.1-1ubuntu1
* Merge from Debian unstable.  Remaining changes:
  - d/control: Switch from libcryptopp to libnss as libcryptopp
    is not seeded.
  - d/control,d/rules: Move from python-support to dh_python2.
  - d/patches/manpage_updates*.patch: cherry picked upstream manpage
    updates warning about lack of encryption, per MIR review.
  - d/rules,d/control: Drop radosgw since libfcgi is not in main and
    the code may not be suitable for LTS.
  - d/rules,d/control: Drop tcmalloc since google perftools is not
    in main yet.
  - d/rules,d/control: Drop ceph-fuse entirely per MIR review
    recommendation.
* d/patches/fix-radosgw-tests.patch: Cherry picked patch from upstream
  VCS to fixup tests to conditionally use radosgw if enabled.

Show diffs side-by-side

added added

removed removed

Lines of Context:
44
44
#define DOUT_SUBSYS mon
45
45
#undef dout_prefix
46
46
#define dout_prefix _prefix(_dout, mon, pg_map)
47
 
static ostream& _prefix(std::ostream *_dout, Monitor *mon, PGMap& pg_map) {
 
47
static ostream& _prefix(std::ostream *_dout, const Monitor *mon, const PGMap& pg_map) {
48
48
  return *_dout << "mon." << mon->name << "@" << mon->rank
49
49
                << "(" << mon->get_state_name()
50
50
                << ").pg v" << pg_map.version << " ";
63
63
  }
64
64
  virtual void handle_conf_change(const md_config_t *conf,
65
65
                                  const std::set<std::string>& changed) {
66
 
    mon->update_full_ratios(((float)conf->mon_osd_full_ratio) / 100,
67
 
                            ((float)conf->mon_osd_nearfull_ratio) / 100);
 
66
    mon->update_full_ratios(conf->mon_osd_full_ratio,
 
67
                            conf->mon_osd_nearfull_ratio);
68
68
  }
69
69
};
70
70
 
72
72
  : PaxosService(mn, p),
73
73
    ratio_lock("PGMonitor::ratio_lock"),
74
74
    need_full_ratio_update(false),
75
 
    need_nearfull_ratio_update(false)
 
75
    need_nearfull_ratio_update(false),
 
76
    need_check_down_pgs(false)
76
77
{
77
78
  ratio_monitor = new RatioMonitor(this);
78
79
  g_conf->add_observer(ratio_monitor);
99
100
{
100
101
  if (mon->is_leader()) {
101
102
    check_osd_map(mon->osdmon()->osdmap.epoch);
 
103
    need_check_down_pgs = true;
102
104
  }
103
105
 
104
106
  update_logger();
140
142
void PGMonitor::update_full_ratios(float full_ratio, float nearfull_ratio)
141
143
{
142
144
  Mutex::Locker l(ratio_lock);
 
145
 
 
146
  if (full_ratio > 1.0)
 
147
    full_ratio /= 100.0;
 
148
  if (nearfull_ratio > 1.0)
 
149
    nearfull_ratio /= 100.0;
 
150
 
143
151
  dout(10) << "update_full_ratios full " << full_ratio << " nearfull " << nearfull_ratio << dendl;
144
152
  if (full_ratio != 0) {
145
153
    new_full_ratio = full_ratio;
178
186
      }
179
187
    }
180
188
    ratio_lock.Unlock();
 
189
    
 
190
    if (need_check_down_pgs && check_down_pgs())
 
191
      propose = true;
 
192
    
181
193
    if (propose) {
182
194
      propose_pending();
183
195
    }
189
201
void PGMonitor::create_initial()
190
202
{
191
203
  dout(10) << "create_initial -- creating initial map" << dendl;
 
204
  pg_map.full_ratio = g_conf->mon_osd_full_ratio;
 
205
  if (pg_map.full_ratio > 1.0)
 
206
    pg_map.full_ratio /= 100.0;
 
207
  pg_map.nearfull_ratio = g_conf->mon_osd_nearfull_ratio;
 
208
  if (pg_map.nearfull_ratio > 1.0)
 
209
    pg_map.nearfull_ratio /= 100.0;
192
210
}
193
211
 
194
 
bool PGMonitor::update_from_paxos()
 
212
void PGMonitor::update_from_paxos()
195
213
{
196
214
  version_t paxosv = paxos->get_version();
197
215
  if (paxosv == pg_map.version)
198
 
    return true;
 
216
    return;
199
217
  assert(paxosv >= pg_map.version);
200
218
 
201
219
  if (pg_map.version != paxos->get_stashed_version()) {
211
229
    catch (const std::exception &e) {
212
230
      dout(0) << "update_from_paxos: error parsing update: "
213
231
              << e.what() << dendl;
214
 
      return false;
 
232
      assert(0 == "update_from_paxos: error parsing update");
 
233
      return;
215
234
    }
216
235
  } 
217
236
 
231
250
    catch (const std::exception &e) {
232
251
      dout(0) << "update_from_paxos: error parsing "
233
252
              << "incremental update: " << e.what() << dendl;
234
 
      return false;
 
253
      assert(0 == "update_from_paxos: error parsing incremental update");
 
254
      return;
235
255
    }
236
256
 
237
257
    pg_map.apply_incremental(inc);
266
286
  send_pg_creates();
267
287
 
268
288
  update_logger();
269
 
 
270
 
  return true;
271
289
}
272
290
 
273
291
void PGMonitor::handle_osd_timeouts()
629
647
        pending_inc.osd_stat_rm.erase(p->first);
630
648
        pending_inc.osd_stat_updates[p->first]; 
631
649
      }
 
650
 
 
651
    // this is conservative: we want to know if any osds (maybe) got marked down.
 
652
    for (map<int32_t,uint8_t>::iterator p = inc.new_state.begin();
 
653
         p != inc.new_state.end();
 
654
         ++p)
 
655
      if (p->second & CEPH_OSD_UP)   // true if marked up OR down, but we're too lazy to check which
 
656
        need_check_down_pgs = true;
632
657
  }
633
658
 
634
659
  bool propose = false;
640
665
  // scan pg space?
641
666
  if (register_new_pgs())
642
667
    propose = true;
 
668
 
 
669
  if (need_check_down_pgs && check_down_pgs())
 
670
    propose = true;
643
671
  
644
672
  if (propose)
645
673
    propose_pending();
812
840
             << " in epoch " << pg_map.pg_stat[pgid].created << dendl;
813
841
    if (msg.count(osd) == 0)
814
842
      msg[osd] = new MOSDPGCreate(mon->osdmon()->osdmap.get_epoch());
815
 
    msg[osd]->mkpg[pgid].created = pg_map.pg_stat[pgid].created;
816
 
    msg[osd]->mkpg[pgid].parent = pg_map.pg_stat[pgid].parent;
817
 
    msg[osd]->mkpg[pgid].split_bits = pg_map.pg_stat[pgid].parent_split_bits;
 
843
    msg[osd]->mkpg[pgid] = pg_create_t(pg_map.pg_stat[pgid].created,
 
844
                                       pg_map.pg_stat[pgid].parent,
 
845
                                       pg_map.pg_stat[pgid].parent_split_bits);
818
846
  }
819
847
 
820
848
  for (map<int, MOSDPGCreate*>::iterator p = msg.begin();
826
854
  }
827
855
}
828
856
 
 
857
bool PGMonitor::check_down_pgs()
 
858
{
 
859
  dout(10) << "check_down_pgs" << dendl;
 
860
 
 
861
  OSDMap *osdmap = &mon->osdmon()->osdmap;
 
862
  bool ret = false;
 
863
 
 
864
  for (hash_map<pg_t,pg_stat_t>::iterator p = pg_map.pg_stat.begin();
 
865
       p != pg_map.pg_stat.end();
 
866
       ++p) {
 
867
    if ((p->second.state & PG_STATE_STALE) == 0 &&
 
868
        p->second.acting.size() &&
 
869
        osdmap->is_down(p->second.acting[0])) {
 
870
      dout(10) << " marking pg " << p->first << " stale with acting " << p->second.acting << dendl;
 
871
 
 
872
      map<pg_t,pg_stat_t>::iterator q = pending_inc.pg_stat_updates.find(p->first);
 
873
      pg_stat_t *stat;
 
874
      if (q == pending_inc.pg_stat_updates.end()) {
 
875
        stat = &pending_inc.pg_stat_updates[p->first];
 
876
        *stat = p->second;
 
877
      } else {
 
878
        stat = &q->second;
 
879
      }
 
880
      stat->state |= PG_STATE_STALE;
 
881
      stat->last_unstale = ceph_clock_now(g_ceph_context);
 
882
      ret = true;
 
883
    }
 
884
  }
 
885
  need_check_down_pgs = false;
 
886
  return ret;
 
887
}
 
888
 
 
889
 
829
890
bool PGMonitor::preprocess_command(MMonCommand *m)
830
891
{
831
892
  int r = -1;
920
981
      jsf.flush(ds);
921
982
      rdata.append(ds);
922
983
    }
 
984
    else if (m->cmd[1] == "dump_stuck") {
 
985
      r = dump_stuck_pg_stats(ss, rdata, args);
 
986
    }
923
987
    else if (m->cmd[1] == "dump_pools_json") {
924
988
      ss << "ok";
925
989
      r = 0;
1047
1111
    ss << "pg " << pgid << " already creating";
1048
1112
    goto out;
1049
1113
  }
1050
 
  pending_inc.pg_stat_updates[pgid].state = PG_STATE_CREATING;
1051
 
  pending_inc.pg_stat_updates[pgid].created = epoch;
 
1114
  {
 
1115
    pg_stat_t& s = pending_inc.pg_stat_updates[pgid];
 
1116
    s.state = PG_STATE_CREATING;
 
1117
    s.created = epoch;
 
1118
    s.last_change = ceph_clock_now(g_ceph_context);
 
1119
  }
1052
1120
  ss << "pg " << m->cmd[2] << " now creating, ok";
1053
1121
  getline(ss, rs);
1054
1122
  paxos->wait_for_commit(new Monitor::C_Command(mon, m, 0, rs, paxos->get_version()));
1061
1129
  return false;
1062
1130
}
1063
1131
 
1064
 
enum health_status_t PGMonitor::get_health(std::ostream &ss) const
 
1132
void PGMonitor::get_health(list<pair<health_status_t,string> >& summary,
 
1133
                           list<pair<health_status_t,string> > *detail) const
1065
1134
{
1066
 
  enum health_status_t ret(HEALTH_OK);
1067
1135
  map<string,int> note;
1068
 
 
1069
1136
  hash_map<int,int>::const_iterator p = pg_map.num_pg_by_state.begin();
1070
1137
  hash_map<int,int>::const_iterator p_end = pg_map.num_pg_by_state.end();
1071
1138
  for (; p != p_end; ++p) {
 
1139
    if (p->first & PG_STATE_STALE)
 
1140
      note["stale"] += p->second;
1072
1141
    if (p->first & PG_STATE_DOWN)
1073
1142
      note["down"] += p->second;
1074
1143
    if (p->first & PG_STATE_DEGRADED)
1081
1150
      note["repair"] += p->second;
1082
1151
    if (p->first & PG_STATE_SPLITTING)
1083
1152
      note["splitting"] += p->second;
1084
 
  }
 
1153
    if (p->first & PG_STATE_RECOVERING)
 
1154
      note["recovering"] += p->second;
 
1155
    if (p->first & PG_STATE_INCOMPLETE)
 
1156
      note["incomplete"] += p->second;
 
1157
    if (p->first & PG_STATE_BACKFILL)
 
1158
      note["backfill"] += p->second;
 
1159
  }
 
1160
 
 
1161
  hash_map<pg_t, pg_stat_t> stuck_pgs;
 
1162
  utime_t now(ceph_clock_now(g_ceph_context));
 
1163
  utime_t cutoff = now - utime_t(g_conf->mon_pg_stuck_threshold, 0);
 
1164
 
 
1165
  pg_map.get_stuck_stats(PGMap::STUCK_INACTIVE, cutoff, stuck_pgs);
 
1166
  if (!stuck_pgs.empty()) {
 
1167
    note["stuck inactive"] = stuck_pgs.size();
 
1168
  }
 
1169
  stuck_pgs.clear();
 
1170
 
 
1171
  pg_map.get_stuck_stats(PGMap::STUCK_UNCLEAN, cutoff, stuck_pgs);
 
1172
  if (!stuck_pgs.empty()) {
 
1173
    note["stuck unclean"] = stuck_pgs.size();
 
1174
  }
 
1175
  stuck_pgs.clear();
 
1176
 
 
1177
  pg_map.get_stuck_stats(PGMap::STUCK_STALE, cutoff, stuck_pgs);
 
1178
  if (!stuck_pgs.empty()) {
 
1179
    note["stuck stale"] = stuck_pgs.size();
 
1180
  }
 
1181
 
 
1182
  if (detail) {
 
1183
    for (hash_map<pg_t,pg_stat_t>::iterator p = stuck_pgs.begin();
 
1184
         p != stuck_pgs.end();
 
1185
         ++p) {
 
1186
      ostringstream ss;
 
1187
      ss << "pg " << p->first << " is stuck " << pg_state_string(p->second.state)
 
1188
         << ", last acting " << p->second.acting;
 
1189
      detail->push_back(make_pair(HEALTH_WARN, ss.str()));
 
1190
    }
 
1191
  }
 
1192
 
1085
1193
  if (!note.empty()) {
1086
 
    ret = HEALTH_WARN;
1087
1194
    for (map<string,int>::iterator p = note.begin(); p != note.end(); p++) {
1088
 
      if (p != note.begin())
1089
 
        ss << ", ";
 
1195
      ostringstream ss;
1090
1196
      ss << p->second << " pgs " << p->first;
 
1197
      summary.push_back(make_pair(HEALTH_WARN, ss.str()));
 
1198
    }
 
1199
    if (detail) {
 
1200
      for (hash_map<pg_t,pg_stat_t>::const_iterator p = pg_map.pg_stat.begin();
 
1201
           p != pg_map.pg_stat.end();
 
1202
           ++p) {
 
1203
        if (p->second.state & (PG_STATE_STALE |
 
1204
                               PG_STATE_DOWN |
 
1205
                               PG_STATE_DEGRADED |
 
1206
                               PG_STATE_INCONSISTENT |
 
1207
                               PG_STATE_PEERING |
 
1208
                               PG_STATE_REPAIR |
 
1209
                               PG_STATE_SPLITTING |
 
1210
                               PG_STATE_RECOVERING |
 
1211
                               PG_STATE_INCOMPLETE |
 
1212
                               PG_STATE_BACKFILL) &&
 
1213
            stuck_pgs.count(p->first) == 0) {
 
1214
          ostringstream ss;
 
1215
          ss << "pg " << p->first << " is " << pg_state_string(p->second.state);
 
1216
          if (p->second.stats.sum.num_objects_unfound)
 
1217
            ss << ", " << p->second.stats.sum.num_objects_unfound << " unfound";
 
1218
          detail->push_back(make_pair(HEALTH_WARN, ss.str()));
 
1219
        }
 
1220
      }
1091
1221
    }
1092
1222
  }
1093
1223
 
1094
1224
  stringstream rss;
1095
1225
  pg_map.recovery_summary(rss);
1096
1226
  if (!rss.str().empty()) {
1097
 
    if (ret != HEALTH_OK)
1098
 
      ss << ", ";
1099
 
    ret = HEALTH_WARN;
1100
 
    ss << rss.str();
1101
 
  }
1102
 
 
1103
 
  return ret;
 
1227
    summary.push_back(make_pair(HEALTH_WARN, "recovery " + rss.str()));
 
1228
    if (detail)
 
1229
      detail->push_back(make_pair(HEALTH_WARN, "recovery " + rss.str()));
 
1230
  }
 
1231
  
 
1232
  check_full_osd_health(summary, detail, pg_map.full_osds, "full", HEALTH_ERR);
 
1233
  check_full_osd_health(summary, detail, pg_map.nearfull_osds, "near full", HEALTH_WARN);
 
1234
}
 
1235
 
 
1236
void PGMonitor::check_full_osd_health(list<pair<health_status_t,string> >& summary,
 
1237
                                      list<pair<health_status_t,string> > *detail,
 
1238
                                      const set<int>& s, const char *desc,
 
1239
                                      health_status_t sev) const
 
1240
{
 
1241
  if (s.size() > 0) {
 
1242
    ostringstream ss;
 
1243
    ss << s.size() << " " << desc << " osd(s)";
 
1244
    summary.push_back(make_pair(sev, ss.str()));
 
1245
    if (detail) {
 
1246
      for (set<int>::const_iterator p = s.begin(); p != s.end(); ++p) {
 
1247
        ostringstream ss;
 
1248
        const osd_stat_t& os = pg_map.osd_stat.find(*p)->second;
 
1249
        int ratio = (int)(((float)os.kb_used) / (float) os.kb * 100.0);
 
1250
        ss << "osd." << *p << " is " << desc << " at " << ratio << "%";
 
1251
        detail->push_back(make_pair(sev, ss.str()));
 
1252
      }
 
1253
    }
 
1254
  }
 
1255
}
 
1256
 
 
1257
int PGMonitor::dump_stuck_pg_stats(ostream& ss,
 
1258
                                   bufferlist& rdata,
 
1259
                                   vector<const char*>& args) const
 
1260
{
 
1261
  string format = "plain";
 
1262
  string val;
 
1263
  int threshold = g_conf->mon_pg_stuck_threshold;
 
1264
  int seconds;
 
1265
  ostringstream err;
 
1266
 
 
1267
  if (args.size() < 2) {
 
1268
    ss << "Must specify inactive or unclean or stale.";
 
1269
    return -EINVAL;
 
1270
  }
 
1271
 
 
1272
  PGMap::StuckPG stuck_type = PGMap::STUCK_NONE;
 
1273
  string type = args[1];
 
1274
  if (type == "inactive")
 
1275
    stuck_type = PGMap::STUCK_INACTIVE;
 
1276
  if (type == "unclean")
 
1277
    stuck_type = PGMap::STUCK_UNCLEAN;
 
1278
  if (type == "stale")
 
1279
    stuck_type = PGMap::STUCK_STALE;
 
1280
  if (stuck_type == PGMap::STUCK_NONE) {
 
1281
    ss << "Invalid stuck type '" << type
 
1282
       << "'. Valid types are: inactive, unclean, or stale";
 
1283
    return -EINVAL;
 
1284
  }
 
1285
 
 
1286
  for (std::vector<const char*>::iterator i = args.begin() + 2;
 
1287
       i != args.end(); ) {
 
1288
    if (ceph_argparse_double_dash(args, i)) {
 
1289
      break;
 
1290
    } else if (ceph_argparse_witharg(args, i, &val,
 
1291
                                     "-f", "--format", (char*)NULL)) {
 
1292
      if (val != "json" && val != "plain") {
 
1293
        ss << "format must be json or plain";
 
1294
        return -EINVAL;
 
1295
      }
 
1296
      format = val;
 
1297
    } else if (ceph_argparse_withint(args, i, &seconds, &err,
 
1298
                                     "-t", "--threshold", (char*)NULL)) {
 
1299
      if (!err.str().empty()) {
 
1300
        ss << err.str();
 
1301
        return -EINVAL;
 
1302
      }
 
1303
      threshold = seconds;
 
1304
    } else if (ceph_argparse_flag(args, i, "-h", "--help", (char*)NULL)) {
 
1305
      stringstream ds;
 
1306
      ds << "Usage: ceph pg dump_stuck inactive|unclean|stale [options]" << std::endl
 
1307
         << std::endl
 
1308
         << "Get stats for pgs that have not been active, clean, or refreshed in some number of seconds." << std::endl
 
1309
         << std::endl
 
1310
         << "Options: " << std::endl
 
1311
         << "  -h, --help                   display usage info" << std::endl
 
1312
         << "  -f, --format [plain|json]    output format (default: plain)" << std::endl
 
1313
         << "  -t, --threshold [seconds]    how many seconds 'stuck' is (default: 300)" << std::endl;
 
1314
      rdata.append(ds);
 
1315
      return 0;
 
1316
    } else {
 
1317
      ss << "invalid argument '" << *i << "'";
 
1318
      return -EINVAL;
 
1319
    }
 
1320
  }
 
1321
 
 
1322
  utime_t now(ceph_clock_now(g_ceph_context));
 
1323
  utime_t cutoff = now - utime_t(threshold, 0);
 
1324
 
 
1325
  stringstream ds;
 
1326
  if (format == "json") {
 
1327
    JSONFormatter jsf(true);
 
1328
    pg_map.dump_stuck(&jsf, stuck_type, cutoff);
 
1329
    jsf.flush(ds);
 
1330
  } else {
 
1331
    pg_map.dump_stuck_plain(ds, stuck_type, cutoff);
 
1332
  }
 
1333
  rdata.append(ds);
 
1334
  ss << "ok";
 
1335
  return 0;
1104
1336
}