summaryrefslogtreecommitdiffstats
path: root/src/test/osd/scrubber_generators.h
blob: d0cbb22c4c8061fdfbf91556bbf52de3cd6531c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
#pragma once

/// \file generating scrub-related maps & objects for unit tests

#include <functional>
#include <map>
#include <sstream>
#include <string>
#include <variant>
#include <vector>

#include "include/buffer.h"
#include "include/buffer_raw.h"
#include "include/object_fmt.h"
#include "osd/osd_types_fmt.h"
#include "osd/scrubber/pg_scrubber.h"

namespace ScrubGenerator {

/// \todo enhance the MockLog to capture the log messages
class MockLog : public LoggerSinkSet {
 public:
  void debug(std::stringstream& s) final
  {
    std::cout << "\n<<debug>> " << s.str() << std::endl;
  }
  void info(std::stringstream& s) final
  {
    std::cout << "\n<<info>> " << s.str() << std::endl;
  }
  void sec(std::stringstream& s) final
  {
    std::cout << "\n<<sec>> " << s.str() << std::endl;
  }
  void warn(std::stringstream& s) final
  {
    std::cout << "\n<<warn>> " << s.str() << std::endl;
  }
  void error(std::stringstream& s) final
  {
    err_count++;
    std::cout << "\n<<error>> " << s.str() << std::endl;
  }
  OstreamTemp info() final { return OstreamTemp(CLOG_INFO, this); }
  OstreamTemp warn() final { return OstreamTemp(CLOG_WARN, this); }
  OstreamTemp error() final { return OstreamTemp(CLOG_ERROR, this); }
  OstreamTemp sec() final { return OstreamTemp(CLOG_ERROR, this); }
  OstreamTemp debug() final { return OstreamTemp(CLOG_DEBUG, this); }

  void do_log(clog_type prio, std::stringstream& ss) final
  {
    switch (prio) {
      case CLOG_DEBUG:
	debug(ss);
	break;
      case CLOG_INFO:
	info(ss);
	break;
      case CLOG_SEC:
	sec(ss);
	break;
      case CLOG_WARN:
	warn(ss);
	break;
      case CLOG_ERROR:
      default:
	error(ss);
	break;
    }
  }

  void do_log(clog_type prio, const std::string& ss) final
  {
    switch (prio) {
      case CLOG_DEBUG:
	debug() << ss;
	break;
      case CLOG_INFO:
	info() << ss;
	break;
      case CLOG_SEC:
	sec() << ss;
	break;
      case CLOG_WARN:
	warn() << ss;
	break;
      case CLOG_ERROR:
      default:
	error() << ss;
	break;
    }
  }

  virtual ~MockLog() {}

  int err_count{0};
  int expected_err_count{0};
  void set_expected_err_count(int c) { expected_err_count = c; }
};

// ///////////////////////////////////////////////////////////////////////// //
// ///////////////////////////////////////////////////////////////////////// //

struct pool_conf_t {
  int pg_num{3};
  int pgp_num{3};
  int size{3};
  int min_size{3};
  std::string name{"rep_pool"};
};

using attr_t = std::map<std::string, std::string>;

using all_clones_snaps_t = std::map<hobject_t, std::vector<snapid_t>>;

struct RealObj;

// a function to manipulate (i.e. corrupt) an object in a specific OSD
using CorruptFunc =
  std::function<RealObj(const RealObj& s, [[maybe_unused]] int osd_num)>;
using CorruptFuncList = std::map<int, CorruptFunc>;  // per OSD

struct SnapsetMockData {

  using CookedCloneSnaps =
    std::tuple<std::map<snapid_t, uint64_t>,
	       std::map<snapid_t, std::vector<snapid_t>>,
	       std::map<snapid_t, interval_set<uint64_t>>>;

  // an auxiliary function to cook the data for the SnapsetMockData
  using clone_snaps_cooker = CookedCloneSnaps (*)();

  snapid_t seq;
  std::vector<snapid_t> snaps;	 // descending
  std::vector<snapid_t> clones;	 // ascending

  std::map<snapid_t, interval_set<uint64_t>> clone_overlap;  // overlap w/ next
							     // newest
  std::map<snapid_t, uint64_t> clone_size;
  std::map<snapid_t, std::vector<snapid_t>> clone_snaps;  // descending


  SnapsetMockData(snapid_t seq,
		  std::vector<snapid_t> snaps,
		  std::vector<snapid_t> clones,
		  std::map<snapid_t, interval_set<uint64_t>> clone_overlap,
		  std::map<snapid_t, uint64_t> clone_size,
		  std::map<snapid_t, std::vector<snapid_t>> clone_snaps)
      : seq(seq)
      , snaps(snaps)
      , clones(clones)
      , clone_overlap(clone_overlap)
      , clone_size(clone_size)
      , clone_snaps(clone_snaps)
  {}

  SnapsetMockData(snapid_t seq,
		  std::vector<snapid_t> snaps,
		  std::vector<snapid_t> clones,
		  clone_snaps_cooker func)
      : seq{seq}
      , snaps{snaps}
      , clones(clones)
  {
    auto [clone_size_, clone_snaps_, clone_overlap_] = func();
    clone_size = clone_size_;
    clone_snaps = clone_snaps_;
    clone_overlap = clone_overlap_;
  }

  SnapSet make_snapset() const
  {
    SnapSet ss;
    ss.seq = seq;
    ss.snaps = snaps;
    ss.clones = clones;
    ss.clone_overlap = clone_overlap;
    ss.clone_size = clone_size;
    ss.clone_snaps = clone_snaps;
    return ss;
  }
};

// an object in our "DB" - with its versioned snaps, "data" (size and hash),
// and "omap" (size and hash)

struct RealData {
  // not needed at this level of "data falsification": std::byte data;
  uint64_t size;
  uint32_t hash;
  uint32_t omap_digest;
  uint32_t omap_bytes;
  attr_t omap;
  attr_t attrs;
};

struct RealObj {
  // the ghobject - oid, version, snap, hash, pool
  ghobject_t ghobj;
  RealData data;
  const CorruptFuncList* corrupt_funcs;
  const SnapsetMockData* snapset_mock_data;
};

static inline RealObj crpt_do_nothing(const RealObj& s, int osdn)
{
  return s;
}

struct SmapEntry {
  ghobject_t ghobj;
  ScrubMap::object smobj;
};


ScrubGenerator::SmapEntry make_smobject(
  const ScrubGenerator::RealObj& blueprint,  // the whole set of versions
  int osd_num);


/**
 * returns the object's snap-set
 */
void add_object(ScrubMap& map, const RealObj& obj_versions, int osd_num);

struct RealObjsConf {
  std::vector<RealObj> objs;
};

using RealObjsConfRef = std::unique_ptr<RealObjsConf>;

// RealObjsConf will be "developed" into the following of per-osd sets,
// now with the correct pool ID, and with the corrupting functions
// activated on the data
using RealObjsConfList = std::map<int, RealObjsConfRef>;

RealObjsConfList make_real_objs_conf(int64_t pool_id,
				     const RealObjsConf& blueprint,
				     std::vector<int32_t> active_osds);

/**
 * create the snap-ids set for all clones appearing in the head
 * object's snapset (those will be injected into the scrubber's mock,
 * to be used as the 'snap_mapper')
 */
all_clones_snaps_t all_clones(const RealObj& head_obj);
}  // namespace ScrubGenerator

template <>
struct fmt::formatter<ScrubGenerator::RealObj> {
  constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }

  template <typename FormatContext>
  auto format(const ScrubGenerator::RealObj& rlo, FormatContext& ctx)
  {
    using namespace ScrubGenerator;
    return fmt::format_to(ctx.out(),
			  "RealObj(gh:{}, dt:{}, snaps:{})",
			  rlo.ghobj,
			  rlo.data.size,
			  (rlo.snapset_mock_data ? rlo.snapset_mock_data->snaps
						 : std::vector<snapid_t>{}));
  }
};