Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / osd / types.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2011 New Dream Network
7  * Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com>
8  *
9  * Author: Loic Dachary <loic@dachary.org>
10  *
11  * This is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public
13  * License version 2, as published by the Free Software
14  * Foundation.  See file COPYING.
15  *
16  */
17
18 #include "include/types.h"
19 #include "osd/osd_types.h"
20 #include "osd/OSDMap.h"
21 #include "gtest/gtest.h"
22 #include "include/coredumpctl.h"
23 #include "common/Thread.h"
24 #include "include/stringify.h"
25 #include "osd/ReplicatedBackend.h"
26
27 #include <sstream>
28
29 TEST(hobject, prefixes0)
30 {
31   uint32_t mask = 0xE947FA20;
32   uint32_t bits = 12;
33   int64_t pool = 0;
34
35   set<string> prefixes_correct;
36   prefixes_correct.insert(string("0000000000000000.02A"));
37
38   set<string> prefixes_out(hobject_t::get_prefixes(bits, mask, pool));
39   ASSERT_EQ(prefixes_out, prefixes_correct);
40 }
41
42 TEST(hobject, prefixes1)
43 {
44   uint32_t mask = 0x0000000F;
45   uint32_t bits = 6;
46   int64_t pool = 20;
47
48   set<string> prefixes_correct;
49   prefixes_correct.insert(string("0000000000000014.F0"));
50   prefixes_correct.insert(string("0000000000000014.F4"));
51   prefixes_correct.insert(string("0000000000000014.F8"));
52   prefixes_correct.insert(string("0000000000000014.FC"));
53
54   set<string> prefixes_out(hobject_t::get_prefixes(bits, mask, pool));
55   ASSERT_EQ(prefixes_out, prefixes_correct);
56 }
57
58 TEST(hobject, prefixes2)
59 {
60   uint32_t mask = 0xDEADBEAF;
61   uint32_t bits = 25;
62   int64_t pool = 0;
63
64   set<string> prefixes_correct;
65   prefixes_correct.insert(string("0000000000000000.FAEBDA0"));
66   prefixes_correct.insert(string("0000000000000000.FAEBDA2"));
67   prefixes_correct.insert(string("0000000000000000.FAEBDA4"));
68   prefixes_correct.insert(string("0000000000000000.FAEBDA6"));
69   prefixes_correct.insert(string("0000000000000000.FAEBDA8"));
70   prefixes_correct.insert(string("0000000000000000.FAEBDAA"));
71   prefixes_correct.insert(string("0000000000000000.FAEBDAC"));
72   prefixes_correct.insert(string("0000000000000000.FAEBDAE"));
73
74   set<string> prefixes_out(hobject_t::get_prefixes(bits, mask, pool));
75   ASSERT_EQ(prefixes_out, prefixes_correct);
76 }
77
78 TEST(hobject, prefixes3)
79 {
80   uint32_t mask = 0xE947FA20;
81   uint32_t bits = 32;
82   int64_t pool = 0x23;
83
84   set<string> prefixes_correct;
85   prefixes_correct.insert(string("0000000000000023.02AF749E"));
86
87   set<string> prefixes_out(hobject_t::get_prefixes(bits, mask, pool));
88   ASSERT_EQ(prefixes_out, prefixes_correct);
89 }
90
91 TEST(hobject, prefixes4)
92 {
93   uint32_t mask = 0xE947FA20;
94   uint32_t bits = 0;
95   int64_t pool = 0x23;
96
97   set<string> prefixes_correct;
98   prefixes_correct.insert(string("0000000000000023."));
99
100   set<string> prefixes_out(hobject_t::get_prefixes(bits, mask, pool));
101   ASSERT_EQ(prefixes_out, prefixes_correct);
102 }
103
104 TEST(hobject, prefixes5)
105 {
106   uint32_t mask = 0xDEADBEAF;
107   uint32_t bits = 1;
108   int64_t pool = 0x34AC5D00;
109
110   set<string> prefixes_correct;
111   prefixes_correct.insert(string("0000000034AC5D00.1"));
112   prefixes_correct.insert(string("0000000034AC5D00.3"));
113   prefixes_correct.insert(string("0000000034AC5D00.5"));
114   prefixes_correct.insert(string("0000000034AC5D00.7"));
115   prefixes_correct.insert(string("0000000034AC5D00.9"));
116   prefixes_correct.insert(string("0000000034AC5D00.B"));
117   prefixes_correct.insert(string("0000000034AC5D00.D"));
118   prefixes_correct.insert(string("0000000034AC5D00.F"));
119
120   set<string> prefixes_out(hobject_t::get_prefixes(bits, mask, pool));
121   ASSERT_EQ(prefixes_out, prefixes_correct);
122 }
123
124 TEST(pg_interval_t, check_new_interval)
125 {
126 // iterate through all 4 combinations
127 for (unsigned i = 0; i < 4; ++i) {
128   bool compact = i & 1;
129   bool ec_pool = i & 2;
130   //
131   // Create a situation where osdmaps are the same so that
132   // each test case can diverge from it using minimal code.
133   //
134   int osd_id = 1;
135   epoch_t epoch = 40;
136   ceph::shared_ptr<OSDMap> osdmap(new OSDMap());
137   osdmap->set_max_osd(10);
138   osdmap->set_state(osd_id, CEPH_OSD_EXISTS);
139   osdmap->set_epoch(epoch);
140   ceph::shared_ptr<OSDMap> lastmap(new OSDMap());
141   lastmap->set_max_osd(10);
142   lastmap->set_state(osd_id, CEPH_OSD_EXISTS);
143   lastmap->set_epoch(epoch);
144   epoch_t same_interval_since = epoch;
145   epoch_t last_epoch_clean = same_interval_since;
146   int64_t pool_id = 200;
147   int pg_num = 4;
148   __u8 min_size = 2;
149   boost::scoped_ptr<IsPGRecoverablePredicate> recoverable(new ReplicatedBackend::RPCRecPred());
150   {
151     OSDMap::Incremental inc(epoch + 1);
152     inc.new_pools[pool_id].min_size = min_size;
153     inc.new_pools[pool_id].set_pg_num(pg_num);
154     inc.new_up_thru[osd_id] = epoch + 1;
155     osdmap->apply_incremental(inc);
156     lastmap->apply_incremental(inc);
157   }
158   vector<int> new_acting;
159   new_acting.push_back(osd_id);
160   new_acting.push_back(osd_id + 1);
161   vector<int> old_acting = new_acting;
162   int old_primary = osd_id;
163   int new_primary = osd_id;
164   vector<int> new_up;
165   new_up.push_back(osd_id);
166   int old_up_primary = osd_id;
167   int new_up_primary = osd_id;
168   vector<int> old_up = new_up;
169   pg_t pgid;
170   pgid.set_pool(pool_id);
171
172   //
173   // Do nothing if there are no modifications in
174   // acting, up or pool size and that the pool is not
175   // being split
176   //
177   {
178     PastIntervals past_intervals; past_intervals.update_type(ec_pool, compact);
179
180     ASSERT_TRUE(past_intervals.empty());
181     ASSERT_FALSE(PastIntervals::check_new_interval(old_primary,
182                                                    new_primary,
183                                                    old_acting,
184                                                    new_acting,
185                                                    old_up_primary,
186                                                    new_up_primary,
187                                                    old_up,
188                                                    new_up,
189                                                    same_interval_since,
190                                                    last_epoch_clean,
191                                                    osdmap,
192                                                    lastmap,
193                                                    pgid,
194                                                    recoverable.get(),
195                                                    &past_intervals));
196     ASSERT_TRUE(past_intervals.empty());
197   }
198
199   //
200   // The acting set has changed
201   //
202   {
203     vector<int> new_acting;
204     int _new_primary = osd_id + 1;
205     new_acting.push_back(_new_primary);
206
207     PastIntervals past_intervals; past_intervals.update_type(ec_pool, compact);
208
209     ASSERT_TRUE(past_intervals.empty());
210     ASSERT_TRUE(PastIntervals::check_new_interval(old_primary,
211                                                   new_primary,
212                                                   old_acting,
213                                                   new_acting,
214                                                   old_up_primary,
215                                                   new_up_primary,
216                                                   old_up,
217                                                   new_up,
218                                                   same_interval_since,
219                                                   last_epoch_clean,
220                                                   osdmap,
221                                                   lastmap,
222                                                   pgid,
223                                                   recoverable.get(),
224                                                   &past_intervals));
225     old_primary = new_primary;
226   }
227
228   //
229   // The up set has changed
230   //
231   {
232     vector<int> new_up;
233     int _new_primary = osd_id + 1;
234     new_up.push_back(_new_primary);
235
236     PastIntervals past_intervals; past_intervals.update_type(ec_pool, compact);
237
238     ASSERT_TRUE(past_intervals.empty());
239     ASSERT_TRUE(PastIntervals::check_new_interval(old_primary,
240                                                   new_primary,
241                                                   old_acting,
242                                                   new_acting,
243                                                   old_up_primary,
244                                                   new_up_primary,
245                                                   old_up,
246                                                   new_up,
247                                                   same_interval_since,
248                                                   last_epoch_clean,
249                                                   osdmap,
250                                                   lastmap,
251                                                   pgid,
252                                                   recoverable.get(),
253                                                   &past_intervals));
254   }
255
256   //
257   // The up primary has changed
258   //
259   {
260     vector<int> new_up;
261     int _new_up_primary = osd_id + 1;
262
263     PastIntervals past_intervals; past_intervals.update_type(ec_pool, compact);
264
265     ASSERT_TRUE(past_intervals.empty());
266     ASSERT_TRUE(PastIntervals::check_new_interval(old_primary,
267                                                   new_primary,
268                                                   old_acting,
269                                                   new_acting,
270                                                   old_up_primary,
271                                                   _new_up_primary,
272                                                   old_up,
273                                                   new_up,
274                                                   same_interval_since,
275                                                   last_epoch_clean,
276                                                   osdmap,
277                                                   lastmap,
278                                                   pgid,
279                                                   recoverable.get(),
280                                                   &past_intervals));
281   }
282
283   //
284   // PG is splitting
285   //
286   {
287     ceph::shared_ptr<OSDMap> osdmap(new OSDMap());
288     osdmap->set_max_osd(10);
289     osdmap->set_state(osd_id, CEPH_OSD_EXISTS);
290     osdmap->set_epoch(epoch);
291     int new_pg_num = pg_num ^ 2;
292     OSDMap::Incremental inc(epoch + 1);
293     inc.new_pools[pool_id].min_size = min_size;
294     inc.new_pools[pool_id].set_pg_num(new_pg_num);
295     osdmap->apply_incremental(inc);
296
297     PastIntervals past_intervals; past_intervals.update_type(ec_pool, compact);
298
299     ASSERT_TRUE(past_intervals.empty());
300     ASSERT_TRUE(PastIntervals::check_new_interval(old_primary,
301                                                   new_primary,
302                                                   old_acting,
303                                                   new_acting,
304                                                   old_up_primary,
305                                                   new_up_primary,
306                                                   old_up,
307                                                   new_up,
308                                                   same_interval_since,
309                                                   last_epoch_clean,
310                                                   osdmap,
311                                                   lastmap,
312                                                   pgid,
313                                                   recoverable.get(),
314                                                   &past_intervals));
315   }
316
317   //
318   // PG size has changed
319   //
320   {
321     ceph::shared_ptr<OSDMap> osdmap(new OSDMap());
322     osdmap->set_max_osd(10);
323     osdmap->set_state(osd_id, CEPH_OSD_EXISTS);
324     osdmap->set_epoch(epoch);
325     OSDMap::Incremental inc(epoch + 1);
326     __u8 new_min_size = min_size + 1;
327     inc.new_pools[pool_id].min_size = new_min_size;
328     inc.new_pools[pool_id].set_pg_num(pg_num);
329     osdmap->apply_incremental(inc);
330
331     PastIntervals past_intervals; past_intervals.update_type(ec_pool, compact);
332
333     ASSERT_TRUE(past_intervals.empty());
334     ASSERT_TRUE(PastIntervals::check_new_interval(old_primary,
335                                                   new_primary,
336                                                   old_acting,
337                                                   new_acting,
338                                                   old_up_primary,
339                                                   new_up_primary,
340                                                   old_up,
341                                                   new_up,
342                                                   same_interval_since,
343                                                   last_epoch_clean,
344                                                   osdmap,
345                                                   lastmap,
346                                                   pgid,
347                                                   recoverable.get(),
348                                                   &past_intervals));
349   }
350
351   //
352   // The old acting set was empty : the previous interval could not
353   // have been rw
354   //
355   {
356     vector<int> old_acting;
357
358     PastIntervals past_intervals; past_intervals.update_type(ec_pool, compact);
359
360     ostringstream out;
361
362     ASSERT_TRUE(past_intervals.empty());
363     ASSERT_TRUE(PastIntervals::check_new_interval(old_primary,
364                                                   new_primary,
365                                                   old_acting,
366                                                   new_acting,
367                                                   old_up_primary,
368                                                   new_up_primary,
369                                                   old_up,
370                                                   new_up,
371                                                   same_interval_since,
372                                                   last_epoch_clean,
373                                                   osdmap,
374                                                   lastmap,
375                                                   pgid,
376                                                   recoverable.get(),
377                                                   &past_intervals,
378                                                   &out));
379     ASSERT_NE(string::npos, out.str().find("acting set is too small"));
380   }
381
382   //
383   // The old acting set did not have enough osd : it could
384   // not have been rw
385   //
386   {
387     vector<int> old_acting;
388     old_acting.push_back(osd_id);
389
390     //
391     // see http://tracker.ceph.com/issues/5780
392     // the size of the old acting set should be compared
393     // with the min_size of the old osdmap
394     //
395     // The new osdmap is created so that it triggers the
396     // bug.
397     //
398     ceph::shared_ptr<OSDMap> osdmap(new OSDMap());
399     osdmap->set_max_osd(10);
400     osdmap->set_state(osd_id, CEPH_OSD_EXISTS);
401     osdmap->set_epoch(epoch);
402     OSDMap::Incremental inc(epoch + 1);
403     __u8 new_min_size = old_acting.size();
404     inc.new_pools[pool_id].min_size = new_min_size;
405     inc.new_pools[pool_id].set_pg_num(pg_num);
406     osdmap->apply_incremental(inc);
407
408     ostringstream out;
409
410     PastIntervals past_intervals; past_intervals.update_type(ec_pool, compact);
411
412     ASSERT_TRUE(past_intervals.empty());
413     ASSERT_TRUE(PastIntervals::check_new_interval(old_primary,
414                                                   new_primary,
415                                                   old_acting,
416                                                   new_acting,
417                                                   old_up_primary,
418                                                   new_up_primary,
419                                                   old_up,
420                                                   new_up,
421                                                   same_interval_since,
422                                                   last_epoch_clean,
423                                                   osdmap,
424                                                   lastmap,
425                                                   pgid,
426                                                   recoverable.get(),
427                                                   &past_intervals,
428                                                   &out));
429     ASSERT_NE(string::npos, out.str().find("acting set is too small"));
430   }
431
432   //
433   // The acting set changes. The old acting set primary was up during the
434   // previous interval and may have been rw.
435   //
436   {
437     vector<int> new_acting;
438     new_acting.push_back(osd_id + 4);
439     new_acting.push_back(osd_id + 5);
440
441     ostringstream out;
442
443     PastIntervals past_intervals; past_intervals.update_type(ec_pool, compact);
444
445     ASSERT_TRUE(past_intervals.empty());
446     ASSERT_TRUE(PastIntervals::check_new_interval(old_primary,
447                                                   new_primary,
448                                                   old_acting,
449                                                   new_acting,
450                                                   old_up_primary,
451                                                   new_up_primary,
452                                                   old_up,
453                                                   new_up,
454                                                   same_interval_since,
455                                                   last_epoch_clean,
456                                                   osdmap,
457                                                   lastmap,
458                                                   pgid,
459                                                   recoverable.get(),
460                                                   &past_intervals,
461                                                   &out));
462     ASSERT_NE(string::npos, out.str().find("includes interval"));
463   }
464   //
465   // The acting set changes. The old acting set primary was not up
466   // during the old interval but last_epoch_clean is in the
467   // old interval and it may have been rw.
468   //
469   {
470     vector<int> new_acting;
471     new_acting.push_back(osd_id + 4);
472     new_acting.push_back(osd_id + 5);
473
474     ceph::shared_ptr<OSDMap> lastmap(new OSDMap());
475     lastmap->set_max_osd(10);
476     lastmap->set_state(osd_id, CEPH_OSD_EXISTS);
477     lastmap->set_epoch(epoch);
478     OSDMap::Incremental inc(epoch + 1);
479     inc.new_pools[pool_id].min_size = min_size;
480     inc.new_pools[pool_id].set_pg_num(pg_num);
481     inc.new_up_thru[osd_id] = epoch - 10;
482     lastmap->apply_incremental(inc);
483
484     ostringstream out;
485
486     PastIntervals past_intervals; past_intervals.update_type(ec_pool, compact);
487
488     ASSERT_TRUE(past_intervals.empty());
489     ASSERT_TRUE(PastIntervals::check_new_interval(old_primary,
490                                                   new_primary,
491                                                   old_acting,
492                                                   new_acting,
493                                                   old_up_primary,
494                                                   new_up_primary,
495                                                   old_up,
496                                                   new_up,
497                                                   same_interval_since,
498                                                   last_epoch_clean,
499                                                   osdmap,
500                                                   lastmap,
501                                                   pgid,
502                                                   recoverable.get(),
503                                                   &past_intervals,
504                                                   &out));
505     ASSERT_NE(string::npos, out.str().find("presumed to have been rw"));
506   }
507
508   //
509   // The acting set changes. The old acting set primary was not up
510   // during the old interval and last_epoch_clean is before the
511   // old interval : the previous interval could not possibly have
512   // been rw.
513   //
514   {
515     vector<int> new_acting;
516     new_acting.push_back(osd_id + 4);
517     new_acting.push_back(osd_id + 5);
518
519     epoch_t last_epoch_clean = epoch - 10;
520
521     ceph::shared_ptr<OSDMap> lastmap(new OSDMap());
522     lastmap->set_max_osd(10);
523     lastmap->set_state(osd_id, CEPH_OSD_EXISTS);
524     lastmap->set_epoch(epoch);
525     OSDMap::Incremental inc(epoch + 1);
526     inc.new_pools[pool_id].min_size = min_size;
527     inc.new_pools[pool_id].set_pg_num(pg_num);
528     inc.new_up_thru[osd_id] = last_epoch_clean;
529     lastmap->apply_incremental(inc);
530
531     ostringstream out;
532
533     PastIntervals past_intervals; past_intervals.update_type(ec_pool, compact);
534
535     ASSERT_TRUE(past_intervals.empty());
536     ASSERT_TRUE(PastIntervals::check_new_interval(old_primary,
537                                                   new_primary,
538                                                   old_acting,
539                                                   new_acting,
540                                                   old_up_primary,
541                                                   new_up_primary,
542                                                   old_up,
543                                                   new_up,
544                                                   same_interval_since,
545                                                   last_epoch_clean,
546                                                   osdmap,
547                                                   lastmap,
548                                                   pgid,
549                                                   recoverable.get(),
550                                                   &past_intervals,
551                                                   &out));
552     ASSERT_NE(string::npos, out.str().find("does not include interval"));
553   }
554 } // end for, didn't want to reindent
555 }
556
557 TEST(pg_t, get_ancestor)
558 {
559   ASSERT_EQ(pg_t(0, 0, -1), pg_t(16, 0, -1).get_ancestor(16));
560   ASSERT_EQ(pg_t(1, 0, -1), pg_t(17, 0, -1).get_ancestor(16));
561   ASSERT_EQ(pg_t(0, 0, -1), pg_t(16, 0, -1).get_ancestor(8));
562   ASSERT_EQ(pg_t(16, 0, -1), pg_t(16, 0, -1).get_ancestor(80));
563   ASSERT_EQ(pg_t(16, 0, -1), pg_t(16, 0, -1).get_ancestor(83));
564   ASSERT_EQ(pg_t(1, 0, -1), pg_t(1321, 0, -1).get_ancestor(123).get_ancestor(8));
565   ASSERT_EQ(pg_t(3, 0, -1), pg_t(1323, 0, -1).get_ancestor(123).get_ancestor(8));
566   ASSERT_EQ(pg_t(3, 0, -1), pg_t(1323, 0, -1).get_ancestor(8));
567 }
568
569 TEST(pg_t, split)
570 {
571   pg_t pgid(0, 0, -1);
572   set<pg_t> s;
573   bool b;
574
575   s.clear();
576   b = pgid.is_split(1, 1, &s);
577   ASSERT_TRUE(!b);
578
579   s.clear();
580   b = pgid.is_split(2, 4, NULL);
581   ASSERT_TRUE(b);
582   b = pgid.is_split(2, 4, &s);
583   ASSERT_TRUE(b);
584   ASSERT_EQ(1u, s.size());
585   ASSERT_TRUE(s.count(pg_t(2, 0, -1)));
586
587   s.clear();
588   b = pgid.is_split(2, 8, &s);
589   ASSERT_TRUE(b);
590   ASSERT_EQ(3u, s.size());
591   ASSERT_TRUE(s.count(pg_t(2, 0, -1)));
592   ASSERT_TRUE(s.count(pg_t(4, 0, -1)));
593   ASSERT_TRUE(s.count(pg_t(6, 0, -1)));
594
595   s.clear();
596   b = pgid.is_split(3, 8, &s);
597   ASSERT_TRUE(b);
598   ASSERT_EQ(1u, s.size());
599   ASSERT_TRUE(s.count(pg_t(4, 0, -1)));
600
601   s.clear();
602   b = pgid.is_split(6, 8, NULL);
603   ASSERT_TRUE(!b);
604   b = pgid.is_split(6, 8, &s);
605   ASSERT_TRUE(!b);
606   ASSERT_EQ(0u, s.size());
607
608   pgid = pg_t(1, 0, -1);
609
610   s.clear();
611   b = pgid.is_split(2, 4, &s);
612   ASSERT_TRUE(b);
613   ASSERT_EQ(1u, s.size());
614   ASSERT_TRUE(s.count(pg_t(3, 0, -1)));
615
616   s.clear();
617   b = pgid.is_split(2, 6, &s);
618   ASSERT_TRUE(b);
619   ASSERT_EQ(2u, s.size());
620   ASSERT_TRUE(s.count(pg_t(3, 0, -1)));
621   ASSERT_TRUE(s.count(pg_t(5, 0, -1)));
622
623   s.clear();
624   b = pgid.is_split(2, 8, &s);
625   ASSERT_TRUE(b);
626   ASSERT_EQ(3u, s.size());
627   ASSERT_TRUE(s.count(pg_t(3, 0, -1)));
628   ASSERT_TRUE(s.count(pg_t(5, 0, -1)));
629   ASSERT_TRUE(s.count(pg_t(7, 0, -1)));
630
631   s.clear();
632   b = pgid.is_split(4, 8, &s);
633   ASSERT_TRUE(b);
634   ASSERT_EQ(1u, s.size());
635   ASSERT_TRUE(s.count(pg_t(5, 0, -1)));
636
637   s.clear();
638   b = pgid.is_split(3, 8, &s);
639   ASSERT_TRUE(b);
640   ASSERT_EQ(3u, s.size());
641   ASSERT_TRUE(s.count(pg_t(3, 0, -1)));
642   ASSERT_TRUE(s.count(pg_t(5, 0, -1)));
643   ASSERT_TRUE(s.count(pg_t(7, 0, -1)));
644
645   s.clear();
646   b = pgid.is_split(6, 8, &s);
647   ASSERT_TRUE(!b);
648   ASSERT_EQ(0u, s.size());
649
650   pgid = pg_t(3, 0, -1);
651
652   s.clear();
653   b = pgid.is_split(7, 8, &s);
654   ASSERT_TRUE(b);
655   ASSERT_EQ(1u, s.size());
656   ASSERT_TRUE(s.count(pg_t(7, 0, -1)));
657
658   s.clear();
659   b = pgid.is_split(7, 12, &s);
660   ASSERT_TRUE(b);
661   ASSERT_EQ(2u, s.size());
662   ASSERT_TRUE(s.count(pg_t(7, 0, -1)));
663   ASSERT_TRUE(s.count(pg_t(11, 0, -1)));
664
665   s.clear();
666   b = pgid.is_split(7, 11, &s);
667   ASSERT_TRUE(b);
668   ASSERT_EQ(1u, s.size());
669   ASSERT_TRUE(s.count(pg_t(7, 0, -1)));
670
671 }
672
673 TEST(pg_missing_t, constructor)
674 {
675   pg_missing_t missing;
676   EXPECT_EQ((unsigned int)0, missing.num_missing());
677   EXPECT_FALSE(missing.have_missing());
678 }
679
680 TEST(pg_missing_t, have_missing)
681 {
682   hobject_t oid(object_t("objname"), "key", 123, 456, 0, "");
683   pg_missing_t missing;
684   EXPECT_FALSE(missing.have_missing());
685   missing.add(oid, eversion_t(), eversion_t(), false);
686   EXPECT_TRUE(missing.have_missing());
687 }
688
689 TEST(pg_missing_t, claim)
690 {
691   hobject_t oid(object_t("objname"), "key", 123, 456, 0, "");
692   pg_missing_t missing;
693   EXPECT_FALSE(missing.have_missing());
694   missing.add(oid, eversion_t(), eversion_t(), false);
695   EXPECT_TRUE(missing.have_missing());
696
697   pg_missing_t other;
698   EXPECT_FALSE(other.have_missing());
699
700   other.claim(missing);
701   EXPECT_TRUE(other.have_missing());
702 }
703
704 TEST(pg_missing_t, is_missing)
705 {
706   // pg_missing_t::is_missing(const hobject_t& oid) const
707   {
708     hobject_t oid(object_t("objname"), "key", 123, 456, 0, "");
709     pg_missing_t missing;
710     EXPECT_FALSE(missing.is_missing(oid));
711     missing.add(oid, eversion_t(), eversion_t(), false);
712     EXPECT_TRUE(missing.is_missing(oid));
713   }
714
715   // bool pg_missing_t::is_missing(const hobject_t& oid, eversion_t v) const
716   {
717     hobject_t oid(object_t("objname"), "key", 123, 456, 0, "");
718     pg_missing_t missing;
719     eversion_t need(10,5);
720     EXPECT_FALSE(missing.is_missing(oid, eversion_t()));
721     missing.add(oid, need, eversion_t(), false);
722     EXPECT_TRUE(missing.is_missing(oid));
723     EXPECT_FALSE(missing.is_missing(oid, eversion_t()));
724     EXPECT_TRUE(missing.is_missing(oid, need));
725   }
726 }
727
728 TEST(pg_missing_t, have_old)
729 {
730   hobject_t oid(object_t("objname"), "key", 123, 456, 0, "");
731   pg_missing_t missing;
732   EXPECT_EQ(eversion_t(), missing.have_old(oid));
733   missing.add(oid, eversion_t(), eversion_t(), false);
734   EXPECT_EQ(eversion_t(), missing.have_old(oid));
735   eversion_t have(1,1);
736   missing.revise_have(oid, have);
737   EXPECT_EQ(have, missing.have_old(oid));
738 }
739
740 TEST(pg_missing_t, add_next_event)
741 {
742   hobject_t oid(object_t("objname"), "key", 123, 456, 0, "");
743   hobject_t oid_other(object_t("other"), "key", 9123, 9456, 0, "");
744   eversion_t version(10,5);
745   eversion_t prior_version(3,4);
746   pg_log_entry_t sample_e(pg_log_entry_t::DELETE, oid, version, prior_version,
747                           0, osd_reqid_t(entity_name_t::CLIENT(777), 8, 999),
748                           utime_t(8,9), 0);
749
750   // new object (MODIFY)
751   {
752     pg_missing_t missing;
753     pg_log_entry_t e = sample_e;
754
755     e.op = pg_log_entry_t::MODIFY;
756     e.prior_version = eversion_t();
757     EXPECT_TRUE(e.is_update());
758     EXPECT_TRUE(e.object_is_indexed());
759     EXPECT_TRUE(e.reqid_is_indexed());
760     EXPECT_FALSE(missing.is_missing(oid));
761     missing.add_next_event(e);
762     EXPECT_TRUE(missing.is_missing(oid));
763     EXPECT_EQ(eversion_t(), missing.get_items().at(oid).have);
764     EXPECT_EQ(oid, missing.get_rmissing().at(e.version.version));
765     EXPECT_EQ(1U, missing.num_missing());
766     EXPECT_EQ(1U, missing.get_rmissing().size());
767
768     // adding the same object replaces the previous one
769     missing.add_next_event(e);
770     EXPECT_TRUE(missing.is_missing(oid));
771     EXPECT_EQ(1U, missing.num_missing());
772     EXPECT_EQ(1U, missing.get_rmissing().size());
773   }
774
775   // new object (CLONE)
776   {
777     pg_missing_t missing;
778     pg_log_entry_t e = sample_e;
779
780     e.op = pg_log_entry_t::CLONE;
781     e.prior_version = eversion_t();
782     EXPECT_TRUE(e.is_clone());
783     EXPECT_TRUE(e.object_is_indexed());
784     EXPECT_FALSE(e.reqid_is_indexed());
785     EXPECT_FALSE(missing.is_missing(oid));
786     missing.add_next_event(e);
787     EXPECT_TRUE(missing.is_missing(oid));
788     EXPECT_EQ(eversion_t(), missing.get_items().at(oid).have);
789     EXPECT_EQ(oid, missing.get_rmissing().at(e.version.version));
790     EXPECT_EQ(1U, missing.num_missing());
791     EXPECT_EQ(1U, missing.get_rmissing().size());
792
793     // adding the same object replaces the previous one
794     missing.add_next_event(e);
795     EXPECT_TRUE(missing.is_missing(oid));
796     EXPECT_EQ(1U, missing.num_missing());
797     EXPECT_EQ(1U, missing.get_rmissing().size());
798   }
799
800   // existing object (MODIFY)
801   {
802     pg_missing_t missing;
803     pg_log_entry_t e = sample_e;
804
805     e.op = pg_log_entry_t::MODIFY;
806     e.prior_version = eversion_t();
807     EXPECT_TRUE(e.is_update());
808     EXPECT_TRUE(e.object_is_indexed());
809     EXPECT_TRUE(e.reqid_is_indexed());
810     EXPECT_FALSE(missing.is_missing(oid));
811     missing.add_next_event(e);
812     EXPECT_TRUE(missing.is_missing(oid));
813     EXPECT_EQ(eversion_t(), missing.get_items().at(oid).have);
814     EXPECT_EQ(oid, missing.get_rmissing().at(e.version.version));
815     EXPECT_EQ(1U, missing.num_missing());
816     EXPECT_EQ(1U, missing.get_rmissing().size());
817
818     // adding the same object with a different version
819     e.prior_version = prior_version;
820     missing.add_next_event(e);
821     EXPECT_EQ(eversion_t(), missing.get_items().at(oid).have);
822     EXPECT_TRUE(missing.is_missing(oid));
823     EXPECT_EQ(1U, missing.num_missing());
824     EXPECT_EQ(1U, missing.get_rmissing().size());
825   }
826
827   // object with prior version (MODIFY)
828   {
829     pg_missing_t missing;
830     pg_log_entry_t e = sample_e;
831
832     e.op = pg_log_entry_t::MODIFY;
833     EXPECT_TRUE(e.is_update());
834     EXPECT_TRUE(e.object_is_indexed());
835     EXPECT_TRUE(e.reqid_is_indexed());
836     EXPECT_FALSE(missing.is_missing(oid));
837     missing.add_next_event(e);
838     EXPECT_TRUE(missing.is_missing(oid));
839     EXPECT_EQ(prior_version, missing.get_items().at(oid).have);
840     EXPECT_EQ(version, missing.get_items().at(oid).need);
841     EXPECT_EQ(oid, missing.get_rmissing().at(e.version.version));
842     EXPECT_EQ(1U, missing.num_missing());
843     EXPECT_EQ(1U, missing.get_rmissing().size());
844   }
845
846   // obsolete (BACKLOG)
847   {
848     pg_missing_t missing;
849     pg_log_entry_t e = sample_e;
850
851     e.op = pg_log_entry_t::BACKLOG;
852     EXPECT_TRUE(e.is_backlog());
853     EXPECT_TRUE(e.object_is_indexed());
854     EXPECT_FALSE(e.reqid_is_indexed());
855     EXPECT_FALSE(missing.is_missing(oid));
856     PrCtl unset_dumpable;
857     EXPECT_DEATH(missing.add_next_event(e), "");
858   }
859
860   // adding a DELETE matching an existing event
861   {
862     pg_missing_t missing;
863     pg_log_entry_t e = sample_e;
864
865     e.op = pg_log_entry_t::MODIFY;
866     EXPECT_TRUE(e.is_update());
867     EXPECT_TRUE(e.object_is_indexed());
868     EXPECT_TRUE(e.reqid_is_indexed());
869     EXPECT_FALSE(missing.is_missing(oid));
870     missing.add_next_event(e);
871     EXPECT_TRUE(missing.is_missing(oid));
872
873     e.op = pg_log_entry_t::DELETE;
874     EXPECT_TRUE(e.is_delete());
875     missing.add_next_event(e);
876     EXPECT_TRUE(missing.is_missing(oid));
877     EXPECT_TRUE(missing.get_items().at(oid).is_delete());
878     EXPECT_EQ(prior_version, missing.get_items().at(oid).have);
879     EXPECT_EQ(version, missing.get_items().at(oid).need);
880     EXPECT_EQ(oid, missing.get_rmissing().at(e.version.version));
881     EXPECT_EQ(1U, missing.num_missing());
882     EXPECT_EQ(1U, missing.get_rmissing().size());
883   }
884
885   // adding a LOST_DELETE after an existing event
886   {
887     pg_missing_t missing;
888     pg_log_entry_t e = sample_e;
889
890     e.op = pg_log_entry_t::MODIFY;
891     EXPECT_TRUE(e.is_update());
892     EXPECT_TRUE(e.object_is_indexed());
893     EXPECT_TRUE(e.reqid_is_indexed());
894     EXPECT_FALSE(missing.is_missing(oid));
895     missing.add_next_event(e);
896     EXPECT_TRUE(missing.is_missing(oid));
897     EXPECT_FALSE(missing.get_items().at(oid).is_delete());
898
899     e.op = pg_log_entry_t::LOST_DELETE;
900     e.version.version++;
901     EXPECT_TRUE(e.is_delete());
902     missing.add_next_event(e);
903     EXPECT_TRUE(missing.is_missing(oid));
904     EXPECT_TRUE(missing.get_items().at(oid).is_delete());
905     EXPECT_EQ(prior_version, missing.get_items().at(oid).have);
906     EXPECT_EQ(e.version, missing.get_items().at(oid).need);
907     EXPECT_EQ(oid, missing.get_rmissing().at(e.version.version));
908     EXPECT_EQ(1U, missing.num_missing());
909     EXPECT_EQ(1U, missing.get_rmissing().size());
910   }
911 }
912
913 TEST(pg_missing_t, revise_need)
914 {
915   hobject_t oid(object_t("objname"), "key", 123, 456, 0, "");
916   pg_missing_t missing;
917   // create a new entry
918   EXPECT_FALSE(missing.is_missing(oid));
919   eversion_t need(10,10);
920   missing.revise_need(oid, need, false);
921   EXPECT_TRUE(missing.is_missing(oid));
922   EXPECT_EQ(eversion_t(), missing.get_items().at(oid).have);
923   EXPECT_EQ(need, missing.get_items().at(oid).need);
924   // update an existing entry and preserve have
925   eversion_t have(1,1);
926   missing.revise_have(oid, have);
927   eversion_t new_need(10,12);
928   EXPECT_EQ(have, missing.get_items().at(oid).have);
929   missing.revise_need(oid, new_need, false);
930   EXPECT_EQ(have, missing.get_items().at(oid).have);
931   EXPECT_EQ(new_need, missing.get_items().at(oid).need);
932 }
933
934 TEST(pg_missing_t, revise_have)
935 {
936   hobject_t oid(object_t("objname"), "key", 123, 456, 0, "");
937   pg_missing_t missing;
938   // a non existing entry means noop
939   EXPECT_FALSE(missing.is_missing(oid));
940   eversion_t have(1,1);
941   missing.revise_have(oid, have);
942   EXPECT_FALSE(missing.is_missing(oid));
943   // update an existing entry
944   eversion_t need(10,12);
945   missing.add(oid, need, have, false);
946   EXPECT_TRUE(missing.is_missing(oid));
947   eversion_t new_have(2,2);
948   EXPECT_EQ(have, missing.get_items().at(oid).have);
949   missing.revise_have(oid, new_have);
950   EXPECT_EQ(new_have, missing.get_items().at(oid).have);
951   EXPECT_EQ(need, missing.get_items().at(oid).need);
952 }
953
954 TEST(pg_missing_t, add)
955 {
956   hobject_t oid(object_t("objname"), "key", 123, 456, 0, "");
957   pg_missing_t missing;
958   EXPECT_FALSE(missing.is_missing(oid));
959   eversion_t have(1,1);
960   eversion_t need(10,10);
961   missing.add(oid, need, have, false);
962   EXPECT_TRUE(missing.is_missing(oid));
963   EXPECT_EQ(have, missing.get_items().at(oid).have);
964   EXPECT_EQ(need, missing.get_items().at(oid).need);
965 }
966
967 TEST(pg_missing_t, rm)
968 {
969   // void pg_missing_t::rm(const hobject_t& oid, eversion_t v)
970   {
971     hobject_t oid(object_t("objname"), "key", 123, 456, 0, "");
972     pg_missing_t missing;
973     EXPECT_FALSE(missing.is_missing(oid));
974     epoch_t epoch = 10;
975     eversion_t need(epoch,10);
976     missing.add(oid, need, eversion_t(), false);
977     EXPECT_TRUE(missing.is_missing(oid));
978     // rm of an older version is a noop
979     missing.rm(oid, eversion_t(epoch / 2,20));
980     EXPECT_TRUE(missing.is_missing(oid));
981     // rm of a later version removes the object
982     missing.rm(oid, eversion_t(epoch * 2,20));
983     EXPECT_FALSE(missing.is_missing(oid));
984   }
985   // void pg_missing_t::rm(const std::map<hobject_t, pg_missing_item>::iterator &m)
986   {
987     hobject_t oid(object_t("objname"), "key", 123, 456, 0, "");
988     pg_missing_t missing;
989     EXPECT_FALSE(missing.is_missing(oid));
990     missing.add(oid, eversion_t(), eversion_t(), false);
991     EXPECT_TRUE(missing.is_missing(oid));
992     auto m = missing.get_items().find(oid);
993     missing.rm(m);
994     EXPECT_FALSE(missing.is_missing(oid));
995   }
996 }
997
998 TEST(pg_missing_t, got)
999 {
1000   // void pg_missing_t::got(const hobject_t& oid, eversion_t v)
1001   {
1002     hobject_t oid(object_t("objname"), "key", 123, 456, 0, "");
1003     pg_missing_t missing;
1004     // assert if the oid does not exist
1005     {
1006       PrCtl unset_dumpable;
1007       EXPECT_DEATH(missing.got(oid, eversion_t()), "");
1008     }
1009     EXPECT_FALSE(missing.is_missing(oid));
1010     epoch_t epoch = 10;
1011     eversion_t need(epoch,10);
1012     missing.add(oid, need, eversion_t(), false);
1013     EXPECT_TRUE(missing.is_missing(oid));
1014     // assert if that the version to be removed is lower than the version of the object
1015     {
1016       PrCtl unset_dumpable;
1017       EXPECT_DEATH(missing.got(oid, eversion_t(epoch / 2,20)), "");
1018     }
1019     // remove of a later version removes the object
1020     missing.got(oid, eversion_t(epoch * 2,20));
1021     EXPECT_FALSE(missing.is_missing(oid));
1022   }
1023   // void pg_missing_t::got(const std::map<hobject_t, pg_missing_item>::iterator &m)
1024   {
1025     hobject_t oid(object_t("objname"), "key", 123, 456, 0, "");
1026     pg_missing_t missing;
1027     EXPECT_FALSE(missing.is_missing(oid));
1028     missing.add(oid, eversion_t(), eversion_t(), false);
1029     EXPECT_TRUE(missing.is_missing(oid));
1030     auto m = missing.get_items().find(oid);
1031     missing.got(m);
1032     EXPECT_FALSE(missing.is_missing(oid));
1033   }
1034 }
1035
1036 TEST(pg_missing_t, split_into)
1037 {
1038   uint32_t hash1 = 1;
1039   hobject_t oid1(object_t("objname"), "key1", 123, hash1, 0, "");
1040   uint32_t hash2 = 2;
1041   hobject_t oid2(object_t("objname"), "key2", 123, hash2, 0, "");
1042   pg_missing_t missing;
1043   missing.add(oid1, eversion_t(), eversion_t(), false);
1044   missing.add(oid2, eversion_t(), eversion_t(), false);
1045   pg_t child_pgid;
1046   child_pgid.m_seed = 1;
1047   pg_missing_t child;
1048   unsigned split_bits = 1;
1049   missing.split_into(child_pgid, split_bits, &child);
1050   EXPECT_TRUE(child.is_missing(oid1));
1051   EXPECT_FALSE(child.is_missing(oid2));
1052   EXPECT_FALSE(missing.is_missing(oid1));
1053   EXPECT_TRUE(missing.is_missing(oid2));
1054 }
1055
1056 class ObjectContextTest : public ::testing::Test {
1057 protected:
1058
1059   static const useconds_t DELAY_MAX = 20 * 1000 * 1000;
1060
1061   class Thread_read_lock : public Thread {
1062   public:
1063     ObjectContext &obc;
1064
1065     explicit Thread_read_lock(ObjectContext& _obc) :
1066       obc(_obc)
1067     {
1068     }
1069
1070     void *entry() override {
1071       obc.ondisk_read_lock();
1072       return NULL;
1073     }
1074   };
1075
1076   class Thread_write_lock : public Thread {
1077   public:
1078     ObjectContext &obc;
1079
1080     explicit Thread_write_lock(ObjectContext& _obc) :
1081       obc(_obc)
1082     {
1083     }
1084
1085     void *entry() override {
1086       obc.ondisk_write_lock();
1087       return NULL;
1088     }
1089   };
1090
1091 };
1092
1093 TEST_F(ObjectContextTest, read_write_lock)
1094 {
1095   {
1096     ObjectContext obc;
1097
1098     //
1099     // write_lock
1100     // write_lock
1101     // write_unlock
1102     // write_unlock
1103     //
1104     EXPECT_EQ(0, obc.writers_waiting);
1105     EXPECT_EQ(0, obc.unstable_writes);
1106
1107     obc.ondisk_write_lock();
1108
1109     EXPECT_EQ(0, obc.writers_waiting);
1110     EXPECT_EQ(1, obc.unstable_writes);
1111
1112     obc.ondisk_write_lock();
1113
1114     EXPECT_EQ(0, obc.writers_waiting);
1115     EXPECT_EQ(2, obc.unstable_writes);
1116
1117     obc.ondisk_write_unlock();
1118
1119     EXPECT_EQ(0, obc.writers_waiting);
1120     EXPECT_EQ(1, obc.unstable_writes);
1121
1122     obc.ondisk_write_unlock();
1123
1124     EXPECT_EQ(0, obc.writers_waiting);
1125     EXPECT_EQ(0, obc.unstable_writes);
1126   }
1127
1128   useconds_t delay = 0;
1129
1130   {
1131     ObjectContext obc;
1132
1133     //
1134     // write_lock
1135     // read_lock => wait
1136     // write_unlock => signal
1137     // read_unlock
1138     //
1139     EXPECT_EQ(0, obc.readers_waiting);
1140     EXPECT_EQ(0, obc.readers);
1141     EXPECT_EQ(0, obc.writers_waiting);
1142     EXPECT_EQ(0, obc.unstable_writes);
1143
1144     obc.ondisk_write_lock();
1145
1146     EXPECT_EQ(0, obc.readers_waiting);
1147     EXPECT_EQ(0, obc.readers);
1148     EXPECT_EQ(0, obc.writers_waiting);
1149     EXPECT_EQ(1, obc.unstable_writes);
1150
1151     Thread_read_lock t(obc);
1152     t.create("obc_read");
1153
1154     do {
1155       cout << "Trying (1) with delay " << delay << "us\n";
1156       usleep(delay);
1157     } while (obc.readers_waiting == 0 &&
1158              ( delay = delay * 2 + 1) < DELAY_MAX);
1159
1160     EXPECT_EQ(1, obc.readers_waiting);
1161     EXPECT_EQ(0, obc.readers);
1162     EXPECT_EQ(0, obc.writers_waiting);
1163     EXPECT_EQ(1, obc.unstable_writes);
1164
1165     obc.ondisk_write_unlock();
1166
1167     do {
1168       cout << "Trying (2) with delay " << delay << "us\n";
1169       usleep(delay);
1170     } while ((obc.readers == 0 || obc.readers_waiting == 1) &&
1171              ( delay = delay * 2 + 1) < DELAY_MAX);
1172     EXPECT_EQ(0, obc.readers_waiting);
1173     EXPECT_EQ(1, obc.readers);
1174     EXPECT_EQ(0, obc.writers_waiting);
1175     EXPECT_EQ(0, obc.unstable_writes);
1176
1177     obc.ondisk_read_unlock();
1178
1179     EXPECT_EQ(0, obc.readers_waiting);
1180     EXPECT_EQ(0, obc.readers);
1181     EXPECT_EQ(0, obc.writers_waiting);
1182     EXPECT_EQ(0, obc.unstable_writes);
1183
1184     t.join();
1185   }
1186
1187   {
1188     ObjectContext obc;
1189
1190     //
1191     // read_lock
1192     // write_lock => wait
1193     // read_unlock => signal
1194     // write_unlock
1195     //
1196     EXPECT_EQ(0, obc.readers_waiting);
1197     EXPECT_EQ(0, obc.readers);
1198     EXPECT_EQ(0, obc.writers_waiting);
1199     EXPECT_EQ(0, obc.unstable_writes);
1200
1201     obc.ondisk_read_lock();
1202
1203     EXPECT_EQ(0, obc.readers_waiting);
1204     EXPECT_EQ(1, obc.readers);
1205     EXPECT_EQ(0, obc.writers_waiting);
1206     EXPECT_EQ(0, obc.unstable_writes);
1207
1208     Thread_write_lock t(obc);
1209     t.create("obc_write");
1210
1211     do {
1212       cout << "Trying (3) with delay " << delay << "us\n";
1213       usleep(delay);
1214     } while ((obc.writers_waiting == 0) &&
1215              ( delay = delay * 2 + 1) < DELAY_MAX);
1216
1217     EXPECT_EQ(0, obc.readers_waiting);
1218     EXPECT_EQ(1, obc.readers);
1219     EXPECT_EQ(1, obc.writers_waiting);
1220     EXPECT_EQ(0, obc.unstable_writes);
1221
1222     obc.ondisk_read_unlock();
1223
1224     do {
1225       cout << "Trying (4) with delay " << delay << "us\n";
1226       usleep(delay);
1227     } while ((obc.unstable_writes == 0 || obc.writers_waiting == 1) &&
1228              ( delay = delay * 2 + 1) < DELAY_MAX);
1229
1230     EXPECT_EQ(0, obc.readers_waiting);
1231     EXPECT_EQ(0, obc.readers);
1232     EXPECT_EQ(0, obc.writers_waiting);
1233     EXPECT_EQ(1, obc.unstable_writes);
1234
1235     obc.ondisk_write_unlock();
1236
1237     EXPECT_EQ(0, obc.readers_waiting);
1238     EXPECT_EQ(0, obc.readers);
1239     EXPECT_EQ(0, obc.writers_waiting);
1240     EXPECT_EQ(0, obc.unstable_writes);
1241
1242     t.join();
1243   }
1244
1245 }
1246
1247 TEST(pg_pool_t_test, get_pg_num_divisor) {
1248   pg_pool_t p;
1249   p.set_pg_num(16);
1250   p.set_pgp_num(16);
1251
1252   for (int i = 0; i < 16; ++i)
1253     ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(i, 1)));
1254
1255   p.set_pg_num(12);
1256   p.set_pgp_num(12);
1257
1258   ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(0, 1)));
1259   ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(1, 1)));
1260   ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(2, 1)));
1261   ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(3, 1)));
1262   ASSERT_EQ(8u, p.get_pg_num_divisor(pg_t(4, 1)));
1263   ASSERT_EQ(8u, p.get_pg_num_divisor(pg_t(5, 1)));
1264   ASSERT_EQ(8u, p.get_pg_num_divisor(pg_t(6, 1)));
1265   ASSERT_EQ(8u, p.get_pg_num_divisor(pg_t(7, 1)));
1266   ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(8, 1)));
1267   ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(9, 1)));
1268   ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(10, 1)));
1269   ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(11, 1)));
1270 }
1271
1272 TEST(pg_pool_t_test, get_random_pg_position) {
1273   srand(getpid());
1274   for (int i = 0; i < 100; ++i) {
1275     pg_pool_t p;
1276     p.set_pg_num(1 + (rand() % 1000));
1277     p.set_pgp_num(p.get_pg_num());
1278     pg_t pgid(rand() % p.get_pg_num(), 1);
1279     uint32_t h = p.get_random_pg_position(pgid, rand());
1280     uint32_t ps = p.raw_hash_to_pg(h);
1281     cout << p.get_pg_num() << " " << pgid << ": "
1282          << h << " -> " << pg_t(ps, 1) << std::endl;
1283     ASSERT_EQ(pgid.ps(), ps);
1284   }
1285 }
1286
1287 TEST(shard_id_t, iostream) {
1288     set<shard_id_t> shards;
1289     shards.insert(shard_id_t(0));
1290     shards.insert(shard_id_t(1));
1291     shards.insert(shard_id_t(2));
1292     ostringstream out;
1293     out << shards;
1294     ASSERT_EQ(out.str(), "0,1,2");
1295
1296     shard_id_t noshard = shard_id_t::NO_SHARD;
1297     shard_id_t zero(0);
1298     ASSERT_GT(zero, noshard);
1299 }
1300
1301 TEST(spg_t, parse) {
1302   spg_t a(pg_t(1,2), shard_id_t::NO_SHARD);
1303   spg_t aa, bb;
1304   spg_t b(pg_t(3,2), shard_id_t(2));
1305   std::string s = stringify(a);
1306   ASSERT_TRUE(aa.parse(s.c_str()));
1307   ASSERT_EQ(a, aa);
1308
1309   s = stringify(b);
1310   ASSERT_TRUE(bb.parse(s.c_str()));
1311   ASSERT_EQ(b, bb);
1312 }
1313
1314 TEST(coll_t, parse) {
1315   const char *ok[] = {
1316     "meta",
1317     "1.2_head",
1318     "1.2_TEMP",
1319     "1.2s3_head",
1320     "1.3s2_TEMP",
1321     "1.2s0_head",
1322     0
1323   };
1324   const char *bad[] = {
1325     "foo",
1326     "1.2_food",
1327     "1.2_head ",
1328     //" 1.2_head",   // hrm, this parses, which is not ideal.. pg_t's fault?
1329     "1.2_temp",
1330     "1.2_HEAD",
1331     "1.xS3_HEAD",
1332     "1.2s_HEAD",
1333     "1.2sfoo_HEAD",
1334     0
1335   };
1336   coll_t a;
1337   for (int i = 0; ok[i]; ++i) {
1338     cout << "check ok " << ok[i] << std::endl;
1339     ASSERT_TRUE(a.parse(ok[i]));
1340     ASSERT_EQ(string(ok[i]), a.to_str());
1341   }
1342   for (int i = 0; bad[i]; ++i) {
1343     cout << "check bad " << bad[i] << std::endl;
1344     ASSERT_FALSE(a.parse(bad[i]));
1345   }
1346 }
1347
1348 TEST(coll_t, temp) {
1349   spg_t pgid;
1350   coll_t foo(pgid);
1351   ASSERT_EQ(foo.to_str(), string("0.0_head"));
1352
1353   coll_t temp = foo.get_temp();
1354   ASSERT_EQ(temp.to_str(), string("0.0_TEMP"));
1355
1356   spg_t pgid2;
1357   ASSERT_TRUE(temp.is_temp());
1358   ASSERT_TRUE(temp.is_temp(&pgid2));
1359   ASSERT_EQ(pgid, pgid2);
1360 }
1361
1362 TEST(coll_t, assigment) {
1363   spg_t pgid;
1364   coll_t right(pgid);
1365   ASSERT_EQ(right.to_str(), string("0.0_head"));
1366
1367   coll_t left, middle;
1368
1369   ASSERT_EQ(left.to_str(), string("meta"));
1370   ASSERT_EQ(middle.to_str(), string("meta"));
1371
1372   left = middle = right;
1373
1374   ASSERT_EQ(left.to_str(), string("0.0_head"));
1375   ASSERT_EQ(middle.to_str(), string("0.0_head"));
1376   
1377   ASSERT_NE(middle.c_str(), right.c_str());
1378   ASSERT_NE(left.c_str(), middle.c_str());
1379 }
1380
1381 TEST(hobject_t, parse) {
1382   const char *v[] = {
1383     "MIN",
1384     "MAX",
1385     "-1:60c2fa6d:::inc_osdmap.1:0",
1386     "-1:60c2fa6d:::inc_osdmap.1:333",
1387     "0:00000000::::head",
1388     "1:00000000:nspace:key:obj:head",
1389     "-40:00000000:nspace::obj:head",
1390     "20:00000000::key:obj:head",
1391     "20:00000000:::o%fdj:head",
1392     "20:00000000:::o%02fdj:head",
1393     "20:00000000:::_zero_%00_:head",
1394     NULL
1395   };
1396
1397   for (unsigned i=0; v[i]; ++i) {
1398     hobject_t o;
1399     bool b = o.parse(v[i]);
1400     if (!b) {
1401       cout << "failed to parse " << v[i] << std::endl;
1402       ASSERT_TRUE(false);
1403     }
1404     string s = stringify(o);
1405     if (s != v[i]) {
1406       cout << v[i] << " -> " << o << " -> " << s << std::endl;
1407       ASSERT_EQ(s, string(v[i]));
1408     }
1409   }
1410 }
1411
1412 TEST(ghobject_t, cmp) {
1413   ghobject_t min;
1414   ghobject_t sep;
1415   sep.set_shard(shard_id_t(1));
1416   sep.hobj.pool = -1;
1417   cout << min << " < " << sep << std::endl;
1418   ASSERT_TRUE(min < sep);
1419
1420   sep.set_shard(shard_id_t::NO_SHARD);
1421   cout << "sep shard " << sep.shard_id << std::endl;
1422   ghobject_t o(hobject_t(object_t(), string(), CEPH_NOSNAP, 0x42,
1423                          1, string()));
1424   cout << "o " << o << std::endl;
1425   ASSERT_TRUE(o > sep);
1426 }
1427
1428 TEST(ghobject_t, parse) {
1429   const char *v[] = {
1430     "GHMIN",
1431     "GHMAX",
1432     "13#0:00000000::::head#",
1433     "13#0:00000000::::head#deadbeef",
1434     "#-1:60c2fa6d:::inc_osdmap.1:333#deadbeef",
1435     "#-1:60c2fa6d:::inc%02osdmap.1:333#deadbeef",
1436     "#-1:60c2fa6d:::inc_osdmap.1:333#",
1437     "1#MIN#deadbeefff",
1438     "1#MAX#",
1439     "#MAX#123",
1440     "#-40:00000000:nspace::obj:head#",
1441     NULL
1442   };
1443
1444   for (unsigned i=0; v[i]; ++i) {
1445     ghobject_t o;
1446     bool b = o.parse(v[i]);
1447     if (!b) {
1448       cout << "failed to parse " << v[i] << std::endl;
1449       ASSERT_TRUE(false);
1450     }
1451     string s = stringify(o);
1452     if (s != v[i]) {
1453       cout << v[i] << " -> " << o << " -> " << s << std::endl;
1454       ASSERT_EQ(s, string(v[i]));
1455     }
1456   }
1457 }
1458
1459 TEST(pool_opts_t, invalid_opt) {
1460   EXPECT_FALSE(pool_opts_t::is_opt_name("INVALID_OPT"));
1461   PrCtl unset_dumpable;
1462   EXPECT_DEATH(pool_opts_t::get_opt_desc("INVALID_OPT"), "");
1463 }
1464
1465 TEST(pool_opts_t, scrub_min_interval) {
1466   EXPECT_TRUE(pool_opts_t::is_opt_name("scrub_min_interval"));
1467   EXPECT_EQ(pool_opts_t::get_opt_desc("scrub_min_interval"),
1468             pool_opts_t::opt_desc_t(pool_opts_t::SCRUB_MIN_INTERVAL,
1469                                     pool_opts_t::DOUBLE));
1470
1471   pool_opts_t opts;
1472   EXPECT_FALSE(opts.is_set(pool_opts_t::SCRUB_MIN_INTERVAL));
1473   {
1474     PrCtl unset_dumpable;
1475     EXPECT_DEATH(opts.get(pool_opts_t::SCRUB_MIN_INTERVAL), "");
1476   }
1477   double val;
1478   EXPECT_FALSE(opts.get(pool_opts_t::SCRUB_MIN_INTERVAL, &val));
1479   opts.set(pool_opts_t::SCRUB_MIN_INTERVAL, static_cast<double>(2015));
1480   EXPECT_TRUE(opts.get(pool_opts_t::SCRUB_MIN_INTERVAL, &val));
1481   EXPECT_EQ(val, 2015);
1482   opts.unset(pool_opts_t::SCRUB_MIN_INTERVAL);
1483   EXPECT_FALSE(opts.is_set(pool_opts_t::SCRUB_MIN_INTERVAL));
1484 }
1485
1486 TEST(pool_opts_t, scrub_max_interval) {
1487   EXPECT_TRUE(pool_opts_t::is_opt_name("scrub_max_interval"));
1488   EXPECT_EQ(pool_opts_t::get_opt_desc("scrub_max_interval"),
1489             pool_opts_t::opt_desc_t(pool_opts_t::SCRUB_MAX_INTERVAL,
1490                                     pool_opts_t::DOUBLE));
1491
1492   pool_opts_t opts;
1493   EXPECT_FALSE(opts.is_set(pool_opts_t::SCRUB_MAX_INTERVAL));
1494   {
1495     PrCtl unset_dumpable;
1496     EXPECT_DEATH(opts.get(pool_opts_t::SCRUB_MAX_INTERVAL), "");
1497   }
1498   double val;
1499   EXPECT_FALSE(opts.get(pool_opts_t::SCRUB_MAX_INTERVAL, &val));
1500   opts.set(pool_opts_t::SCRUB_MAX_INTERVAL, static_cast<double>(2015));
1501   EXPECT_TRUE(opts.get(pool_opts_t::SCRUB_MAX_INTERVAL, &val));
1502   EXPECT_EQ(val, 2015);
1503   opts.unset(pool_opts_t::SCRUB_MAX_INTERVAL);
1504   EXPECT_FALSE(opts.is_set(pool_opts_t::SCRUB_MAX_INTERVAL));
1505 }
1506
1507 TEST(pool_opts_t, deep_scrub_interval) {
1508   EXPECT_TRUE(pool_opts_t::is_opt_name("deep_scrub_interval"));
1509   EXPECT_EQ(pool_opts_t::get_opt_desc("deep_scrub_interval"),
1510             pool_opts_t::opt_desc_t(pool_opts_t::DEEP_SCRUB_INTERVAL,
1511                                     pool_opts_t::DOUBLE));
1512
1513   pool_opts_t opts;
1514   EXPECT_FALSE(opts.is_set(pool_opts_t::DEEP_SCRUB_INTERVAL));
1515   {
1516     PrCtl unset_dumpable;
1517     EXPECT_DEATH(opts.get(pool_opts_t::DEEP_SCRUB_INTERVAL), "");
1518   }
1519   double val;
1520   EXPECT_FALSE(opts.get(pool_opts_t::DEEP_SCRUB_INTERVAL, &val));
1521   opts.set(pool_opts_t::DEEP_SCRUB_INTERVAL, static_cast<double>(2015));
1522   EXPECT_TRUE(opts.get(pool_opts_t::DEEP_SCRUB_INTERVAL, &val));
1523   EXPECT_EQ(val, 2015);
1524   opts.unset(pool_opts_t::DEEP_SCRUB_INTERVAL);
1525   EXPECT_FALSE(opts.is_set(pool_opts_t::DEEP_SCRUB_INTERVAL));
1526 }
1527
1528 struct RequiredPredicate : IsPGRecoverablePredicate {
1529   unsigned required_size;
1530   RequiredPredicate(unsigned required_size) : required_size(required_size) {}
1531   bool operator()(const set<pg_shard_t> &have) const override {
1532     return have.size() >= required_size;
1533   }
1534 };
1535
1536 using namespace std;
1537 struct MapPredicate {
1538   map<int, pair<PastIntervals::osd_state_t, epoch_t>> states;
1539   MapPredicate(
1540     vector<pair<int, pair<PastIntervals::osd_state_t, epoch_t>>> _states)
1541    : states(_states.begin(), _states.end()) {}
1542   PastIntervals::osd_state_t operator()(epoch_t start, int osd, epoch_t *lost_at) {
1543     auto val = states.at(osd);
1544     if (lost_at)
1545       *lost_at = val.second;
1546     return val.first;
1547   }
1548 };
1549
1550 using sit = shard_id_t;
1551 using PI = PastIntervals;
1552 using pst = pg_shard_t;
1553 using ival = PastIntervals::pg_interval_t;
1554 using ivallst = std::list<ival>;
1555 const int N = 0x7fffffff /* CRUSH_ITEM_NONE, can't import crush.h here */;
1556
1557 struct PITest : ::testing::Test {
1558   PITest() {}
1559   void run(
1560     bool ec_pool,
1561     ivallst intervals,
1562     epoch_t last_epoch_started,
1563     unsigned min_to_peer,
1564     vector<pair<int, pair<PastIntervals::osd_state_t, epoch_t>>> osd_states,
1565     vector<int> up,
1566     vector<int> acting,
1567     set<pg_shard_t> probe,
1568     set<int> down,
1569     map<int, epoch_t> blocked_by,
1570     bool pg_down) {
1571     RequiredPredicate rec_pred(min_to_peer);
1572     MapPredicate map_pred(osd_states);
1573
1574     PI::PriorSet correct(
1575       ec_pool,
1576       probe,
1577       down,
1578       blocked_by,
1579       pg_down,
1580       new RequiredPredicate(rec_pred));
1581
1582     PastIntervals simple, compact;
1583     simple.update_type(ec_pool, false);
1584     compact.update_type(ec_pool, true);
1585     for (auto &&i: intervals) {
1586       simple.add_interval(ec_pool, i);
1587       compact.add_interval(ec_pool, i);
1588     }
1589     PI::PriorSet simple_ps = simple.get_prior_set(
1590       ec_pool,
1591       last_epoch_started,
1592       new RequiredPredicate(rec_pred),
1593       map_pred,
1594       up,
1595       acting,
1596       nullptr);
1597     PI::PriorSet compact_ps = compact.get_prior_set(
1598       ec_pool,
1599       last_epoch_started,
1600       new RequiredPredicate(rec_pred),
1601       map_pred,
1602       up,
1603       acting,
1604       nullptr);
1605     ASSERT_EQ(correct, simple_ps);
1606     ASSERT_EQ(correct, compact_ps);
1607   }
1608 };
1609
1610 TEST_F(PITest, past_intervals_rep) {
1611   run(
1612     /* ec_pool    */ false,
1613     /* intervals  */
1614     { ival{{0, 1, 2}, {0, 1, 2}, 10, 20,  true, 0, 0}
1615     , ival{{   1, 2}, {   1, 2}, 21, 30,  true, 1, 1}
1616     , ival{{      2}, {      2}, 31, 35, false, 2, 2}
1617     , ival{{0,    2}, {0,    2}, 36, 50,  true, 0, 0}
1618     },
1619     /* les        */ 5,
1620     /* min_peer   */ 1,
1621     /* osd states at end */
1622     { make_pair(0, make_pair(PI::UP   , 0))
1623     , make_pair(1, make_pair(PI::UP   , 0))
1624     , make_pair(2, make_pair(PI::DOWN , 0))
1625     },
1626     /* acting     */ {0, 1   },
1627     /* up         */ {0, 1   },
1628     /* probe      */ {pst(0), pst(1)},
1629     /* down       */ {2},
1630     /* blocked_by */ {},
1631     /* pg_down    */ false);
1632 }
1633
1634 TEST_F(PITest, past_intervals_ec) {
1635   run(
1636     /* ec_pool    */ true,
1637     /* intervals  */
1638     { ival{{0, 1, 2}, {0, 1, 2}, 10, 20,  true, 0, 0}
1639     , ival{{N, 1, 2}, {N, 1, 2}, 21, 30,  true, 1, 1}
1640     },
1641     /* les        */ 5,
1642     /* min_peer   */ 2,
1643     /* osd states at end */
1644     { make_pair(0, make_pair(PI::DOWN , 0))
1645     , make_pair(1, make_pair(PI::UP   , 0))
1646     , make_pair(2, make_pair(PI::UP   , 0))
1647     },
1648     /* acting     */ {N, 1, 2},
1649     /* up         */ {N, 1, 2},
1650     /* probe      */ {pst(1, sit(1)), pst(2, sit(2))},
1651     /* down       */ {0},
1652     /* blocked_by */ {},
1653     /* pg_down    */ false);
1654 }
1655
1656 TEST_F(PITest, past_intervals_rep_down) {
1657   run(
1658     /* ec_pool    */ false,
1659     /* intervals  */
1660     { ival{{0, 1, 2}, {0, 1, 2}, 10, 20,  true, 0, 0}
1661     , ival{{   1, 2}, {   1, 2}, 21, 30,  true, 1, 1}
1662     , ival{{      2}, {      2}, 31, 35,  true, 2, 2}
1663     , ival{{0,    2}, {0,    2}, 36, 50,  true, 0, 0}
1664     },
1665     /* les        */ 5,
1666     /* min_peer   */ 1,
1667     /* osd states at end */
1668     { make_pair(0, make_pair(PI::UP   , 0))
1669     , make_pair(1, make_pair(PI::UP   , 0))
1670     , make_pair(2, make_pair(PI::DOWN , 0))
1671     },
1672     /* acting     */ {0, 1   },
1673     /* up         */ {0, 1   },
1674     /* probe      */ {pst(0), pst(1)},
1675     /* down       */ {2},
1676     /* blocked_by */ {{2, 0}},
1677     /* pg_down    */ true);
1678 }
1679
1680 TEST_F(PITest, past_intervals_ec_down) {
1681   run(
1682     /* ec_pool    */ true,
1683     /* intervals  */
1684     { ival{{0, 1, 2}, {0, 1, 2}, 10, 20,  true, 0, 0}
1685     , ival{{N, 1, 2}, {N, 1, 2}, 21, 30,  true, 1, 1}
1686     , ival{{N, N, 2}, {N, N, 2}, 31, 35, false, 2, 2}
1687     },
1688     /* les        */ 5,
1689     /* min_peer   */ 2,
1690     /* osd states at end */
1691     { make_pair(0, make_pair(PI::UP   , 0))
1692     , make_pair(1, make_pair(PI::DOWN , 0))
1693     , make_pair(2, make_pair(PI::UP   , 0))
1694     },
1695     /* acting     */ {0, N, 2},
1696     /* up         */ {0, N, 2},
1697     /* probe      */ {pst(0, sit(0)), pst(2, sit(2))},
1698     /* down       */ {1},
1699     /* blocked_by */ {{1, 0}},
1700     /* pg_down    */ true);
1701 }
1702
1703 TEST_F(PITest, past_intervals_rep_no_subsets) {
1704   run(
1705     /* ec_pool    */ false,
1706     /* intervals  */
1707     { ival{{0,    2}, {0,    2}, 10, 20,  true, 0, 0}
1708     , ival{{   1, 2}, {   1, 2}, 21, 30,  true, 1, 1}
1709     , ival{{0, 1   }, {0, 1   }, 31, 35,  true, 0, 0}
1710     },
1711     /* les        */ 5,
1712     /* min_peer   */ 1,
1713     /* osd states at end */
1714     { make_pair(0, make_pair(PI::UP   , 0))
1715     , make_pair(1, make_pair(PI::UP   , 0))
1716     , make_pair(2, make_pair(PI::DOWN , 0))
1717     },
1718     /* acting     */ {0, 1   },
1719     /* up         */ {0, 1   },
1720     /* probe      */ {pst(0), pst(1)},
1721     /* down       */ {2},
1722     /* blocked_by */ {},
1723     /* pg_down    */ false);
1724 }
1725
1726 TEST_F(PITest, past_intervals_ec_no_subsets) {
1727   run(
1728     /* ec_pool    */ true,
1729     /* intervals  */
1730     { ival{{0, N, 2}, {0, N, 2}, 10, 20,  true, 0, 0}
1731     , ival{{N, 1, 2}, {N, 1, 2}, 21, 30,  true, 1, 1}
1732     , ival{{0, 1, N}, {0, 1, N}, 31, 35,  true, 0, 0}
1733     },
1734     /* les        */ 5,
1735     /* min_peer   */ 2,
1736     /* osd states at end */
1737     { make_pair(0, make_pair(PI::UP   , 0))
1738     , make_pair(1, make_pair(PI::DOWN , 0))
1739     , make_pair(2, make_pair(PI::UP   , 0))
1740     },
1741     /* acting     */ {0, N, 2},
1742     /* up         */ {0, N, 2},
1743     /* probe      */ {pst(0, sit(0)), pst(2, sit(2))},
1744     /* down       */ {1},
1745     /* blocked_by */ {{1, 0}},
1746     /* pg_down    */ true);
1747 }
1748
1749 TEST_F(PITest, past_intervals_ec_no_subsets2) {
1750   run(
1751     /* ec_pool    */ true,
1752     /* intervals  */
1753     { ival{{N, 1, 2}, {N, 1, 2}, 10, 20,  true, 0, 0}
1754     , ival{{0, N, 2}, {0, N, 2}, 21, 30,  true, 1, 1}
1755     , ival{{0, 3, N}, {0, 3, N}, 31, 35,  true, 0, 0}
1756     },
1757     /* les        */ 31,
1758     /* min_peer   */ 2,
1759     /* osd states at end */
1760     { make_pair(0, make_pair(PI::UP   , 0))
1761     , make_pair(1, make_pair(PI::DOWN , 0))
1762     , make_pair(2, make_pair(PI::UP   , 0))
1763     , make_pair(3, make_pair(PI::UP   , 0))
1764     },
1765     /* acting     */ {0, N, 2},
1766     /* up         */ {0, N, 2},
1767     /* probe      */ {pst(0, sit(0)), pst(2, sit(2)), pst(3, sit(1))},
1768     /* down       */ {1},
1769     /* blocked_by */ {},
1770     /* pg_down    */ false);
1771 }
1772
1773 TEST_F(PITest, past_intervals_rep_lost) {
1774   run(
1775     /* ec_pool    */ false,
1776     /* intervals  */
1777     { ival{{0, 1, 2}, {0, 1, 2}, 10, 20,  true, 0, 0}
1778     , ival{{   1, 2}, {   1, 2}, 21, 30,  true, 1, 1}
1779     , ival{{      2}, {      2}, 31, 35,  true, 2, 2}
1780     , ival{{0,    2}, {0,    2}, 36, 50,  true, 0, 0}
1781     },
1782     /* les        */ 5,
1783     /* min_peer   */ 1,
1784     /* osd states at end */
1785     { make_pair(0, make_pair(PI::UP   , 0))
1786     , make_pair(1, make_pair(PI::UP   , 0))
1787     , make_pair(2, make_pair(PI::LOST , 55))
1788     },
1789     /* acting     */ {0, 1   },
1790     /* up         */ {0, 1   },
1791     /* probe      */ {pst(0), pst(1)},
1792     /* down       */ {2},
1793     /* blocked_by */ {},
1794     /* pg_down    */ false);
1795 }
1796
1797 TEST_F(PITest, past_intervals_ec_lost) {
1798   run(
1799     /* ec_pool    */ true,
1800     /* intervals  */
1801     { ival{{0, N, 2}, {0, N, 2}, 10, 20,  true, 0, 0}
1802     , ival{{N, 1, 2}, {N, 1, 2}, 21, 30,  true, 1, 1}
1803     , ival{{0, 1, N}, {0, 1, N}, 31, 35,  true, 0, 0}
1804     },
1805     /* les        */ 5,
1806     /* min_peer   */ 2,
1807     /* osd states at end */
1808     { make_pair(0, make_pair(PI::UP   , 0))
1809     , make_pair(1, make_pair(PI::LOST , 36))
1810     , make_pair(2, make_pair(PI::UP   , 0))
1811     },
1812     /* acting     */ {0, N, 2},
1813     /* up         */ {0, N, 2},
1814     /* probe      */ {pst(0, sit(0)), pst(2, sit(2))},
1815     /* down       */ {1},
1816     /* blocked_by */ {},
1817     /* pg_down    */ false);
1818 }
1819
1820
1821 /*
1822  * Local Variables:
1823  * compile-command: "cd ../.. ;
1824  *   make unittest_osd_types ;
1825  *   ./unittest_osd_types # --gtest_filter=pg_missing_t.constructor
1826  * "
1827  * End:
1828  */