]>
Commit | Line | Data |
---|---|---|
1d09f67e TL |
1 | #include <algorithm> |
2 | #include <errno.h> | |
3 | #include <string> | |
4 | #include <vector> | |
5 | ||
6 | #include "gtest/gtest.h" | |
7 | ||
8 | #include "include/rados.h" | |
9 | #include "include/rados/librados.hpp" | |
10 | #include "json_spirit/json_spirit.h" | |
11 | #include "test/librados/test_cxx.h" | |
12 | #include "test/librados/testcase_cxx.h" | |
13 | ||
14 | using namespace librados; | |
15 | ||
16 | using std::string; | |
17 | ||
18 | class LibRadosSnapshotStatsSelfManagedPP : public RadosTestPP { | |
19 | public: | |
20 | LibRadosSnapshotStatsSelfManagedPP() {}; | |
21 | ~LibRadosSnapshotStatsSelfManagedPP() override {}; | |
22 | protected: | |
23 | void SetUp() override { | |
24 | // disable pg autoscaler for the tests | |
25 | string cmd = | |
26 | "{" | |
27 | "\"prefix\": \"config set\", " | |
28 | "\"who\": \"global\", " | |
29 | "\"name\": \"osd_pool_default_pg_autoscale_mode\", " | |
30 | "\"value\": \"off\"" | |
31 | "}"; | |
32 | std::cout << "Setting pg_autoscaler to 'off'" << std::endl; | |
33 | bufferlist inbl; | |
34 | bufferlist outbl; | |
35 | ASSERT_EQ(0, s_cluster.mon_command(cmd, inbl, &outbl, NULL)); | |
36 | ||
37 | // disable scrubs for the test | |
38 | cmd = "{\"prefix\": \"osd set\",\"key\":\"noscrub\"}"; | |
39 | ASSERT_EQ(0, s_cluster.mon_command(cmd, inbl, &outbl, NULL)); | |
40 | cmd = "{\"prefix\": \"osd set\",\"key\":\"nodeep-scrub\"}"; | |
41 | ASSERT_EQ(0, s_cluster.mon_command(cmd, inbl, &outbl, NULL)); | |
42 | ||
43 | RadosTestPP::SetUp(); | |
44 | } | |
45 | ||
46 | void TearDown() override { | |
47 | // re-enable pg autoscaler | |
48 | string cmd = | |
49 | "{" | |
50 | "\"prefix\": \"config set\", " | |
51 | "\"who\": \"global\", " | |
52 | "\"name\": \"osd_pool_default_pg_autoscale_mode\", " | |
53 | "\"value\": \"on\"" | |
54 | "}"; | |
55 | std::cout << "Setting pg_autoscaler to 'on'" << std::endl; | |
56 | bufferlist inbl; | |
57 | bufferlist outbl; | |
58 | ASSERT_EQ(0, s_cluster.mon_command(cmd, inbl, &outbl, NULL)); | |
59 | ||
60 | // re-enable scrubs | |
61 | cmd = "{\"prefix\": \"osd unset\",\"key\":\"noscrub\"}"; | |
62 | ASSERT_EQ(0, s_cluster.mon_command(cmd, inbl, &outbl, NULL)); | |
63 | cmd = string("{\"prefix\": \"osd unset\",\"key\":\"nodeep-scrub\"}"); | |
64 | ASSERT_EQ(0, s_cluster.mon_command(cmd, inbl, &outbl, NULL)); | |
65 | ||
66 | RadosTestPP::TearDown(); | |
67 | } | |
68 | }; | |
69 | ||
70 | class LibRadosSnapshotStatsSelfManagedECPP : public RadosTestECPP { | |
71 | public: | |
72 | LibRadosSnapshotStatsSelfManagedECPP() {}; | |
73 | ~LibRadosSnapshotStatsSelfManagedECPP() override {}; | |
74 | protected: | |
75 | void SetUp() override { | |
76 | // disable pg autoscaler for the tests | |
77 | string cmd = | |
78 | "{" | |
79 | "\"prefix\": \"config set\", " | |
80 | "\"who\": \"global\", " | |
81 | "\"name\": \"osd_pool_default_pg_autoscale_mode\", " | |
82 | "\"value\": \"off\"" | |
83 | "}"; | |
84 | std::cout << "Setting pg_autoscaler to 'off'" << std::endl; | |
85 | bufferlist inbl; | |
86 | bufferlist outbl; | |
87 | ASSERT_EQ(0, s_cluster.mon_command(cmd, inbl, &outbl, NULL)); | |
88 | ||
89 | // disable scrubs for the test | |
90 | cmd = string("{\"prefix\": \"osd set\",\"key\":\"noscrub\"}"); | |
91 | ASSERT_EQ(0, s_cluster.mon_command(cmd, inbl, &outbl, NULL)); | |
92 | cmd = string("{\"prefix\": \"osd set\",\"key\":\"nodeep-scrub\"}"); | |
93 | ASSERT_EQ(0, s_cluster.mon_command(cmd, inbl, &outbl, NULL)); | |
94 | ||
95 | RadosTestECPP::SetUp(); | |
96 | } | |
97 | ||
98 | void TearDown() override { | |
99 | // re-enable pg autoscaler | |
100 | string cmd = | |
101 | "{" | |
102 | "\"prefix\": \"config set\", " | |
103 | "\"who\": \"global\", " | |
104 | "\"name\": \"osd_pool_default_pg_autoscale_mode\", " | |
105 | "\"value\": \"on\"" | |
106 | "}"; | |
107 | std::cout << "Setting pg_autoscaler to 'on'" << std::endl; | |
108 | bufferlist inbl; | |
109 | bufferlist outbl; | |
110 | ASSERT_EQ(0, s_cluster.mon_command(cmd, inbl, &outbl, NULL)); | |
111 | ||
112 | // re-enable scrubs | |
113 | cmd = string("{\"prefix\": \"osd unset\",\"key\":\"noscrub\"}"); | |
114 | ASSERT_EQ(0, s_cluster.mon_command(cmd, inbl, &outbl, NULL)); | |
115 | cmd = string("{\"prefix\": \"osd unset\",\"key\":\"nodeep-scrub\"}"); | |
116 | ASSERT_EQ(0, s_cluster.mon_command(cmd, inbl, &outbl, NULL)); | |
117 | ||
118 | RadosTestECPP::TearDown(); | |
119 | } | |
120 | }; | |
121 | ||
122 | void get_snaptrim_stats(json_spirit::Object& pg_dump, | |
123 | int *objs_trimmed, | |
124 | double *trim_duration) { | |
125 | // pg_map | |
126 | json_spirit::Object pgmap; | |
127 | for (json_spirit::Object::size_type i = 0; i < pg_dump.size(); ++i) { | |
128 | json_spirit::Pair& p = pg_dump[i]; | |
129 | if (p.name_ == "pg_map") { | |
130 | pgmap = p.value_.get_obj(); | |
131 | break; | |
132 | } | |
133 | } | |
134 | ||
135 | // pg_stats array | |
136 | json_spirit::Array pgs; | |
137 | for (json_spirit::Object::size_type i = 0; i < pgmap.size(); ++i) { | |
138 | json_spirit::Pair& p = pgmap[i]; | |
139 | if (p.name_ == "pg_stats") { | |
140 | pgs = p.value_.get_array(); | |
141 | break; | |
142 | } | |
143 | } | |
144 | ||
145 | // snaptrim stats | |
146 | for (json_spirit::Object::size_type j = 0; j < pgs.size(); ++j) { | |
147 | json_spirit::Object& pg_stat = pgs[j].get_obj(); | |
148 | for(json_spirit::Object::size_type k = 0; k < pg_stat.size(); ++k) { | |
149 | json_spirit::Pair& stats = pg_stat[k]; | |
150 | if (stats.name_ == "objects_trimmed") { | |
151 | *objs_trimmed += stats.value_.get_int(); | |
152 | } | |
153 | if (stats.name_ == "snaptrim_duration") { | |
154 | *trim_duration += stats.value_.get_real(); | |
155 | } | |
156 | } | |
157 | } | |
158 | } | |
159 | const int bufsize = 128; | |
160 | ||
161 | TEST_F(LibRadosSnapshotStatsSelfManagedPP, SnaptrimStatsPP) { | |
162 | int num_objs = 10; | |
163 | ||
164 | // create objects | |
165 | char buf[bufsize]; | |
166 | memset(buf, 0xcc, sizeof(buf)); | |
167 | bufferlist bl; | |
168 | bl.append(buf, sizeof(buf)); | |
169 | for (int i = 0; i < num_objs; ++i) { | |
170 | string obj = string("foo") + std::to_string(i); | |
171 | ASSERT_EQ(0, ioctx.write(obj, bl, sizeof(buf), 0)); | |
172 | } | |
173 | ||
174 | std::vector<uint64_t> my_snaps; | |
175 | char buf2[sizeof(buf)]; | |
176 | memset(buf2, 0xdd, sizeof(buf2)); | |
177 | bufferlist bl2; | |
178 | bl2.append(buf2, sizeof(buf2)); | |
179 | for (int snap = 0; snap < 1; ++snap) { | |
180 | // create a snapshot, clone | |
181 | std::vector<uint64_t> ns(1); | |
182 | ns.insert(ns.end(), my_snaps.begin(), my_snaps.end()); | |
183 | my_snaps.swap(ns); | |
184 | ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0])); | |
185 | ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); | |
186 | for (int i = 0; i < num_objs; ++i) { | |
187 | string obj = string("foo") + std::to_string(i); | |
188 | ASSERT_EQ(0, ioctx.write(obj, bl2, sizeof(buf2), 0)); | |
189 | } | |
190 | } | |
191 | ||
192 | // wait for maps to settle | |
193 | cluster.wait_for_latest_osdmap(); | |
194 | ||
195 | // remove snaps - should trigger snaptrim | |
196 | for (unsigned snap = 0; snap < my_snaps.size(); ++snap) { | |
197 | ioctx.selfmanaged_snap_remove(my_snaps[snap]); | |
198 | } | |
199 | ||
200 | // sleep for few secs for the trim stats to populate | |
201 | std::cout << "Waiting for snaptrim stats to be generated" << std::endl; | |
202 | sleep(30); | |
203 | ||
204 | // Dump pg stats and determine if snaptrim stats are getting set | |
205 | int objects_trimmed = 0; | |
206 | double snaptrim_duration = 0.0; | |
207 | int tries = 0; | |
208 | do { | |
209 | string cmd = string("{\"prefix\": \"pg dump\",\"format\":\"json\"}"); | |
210 | bufferlist inbl; | |
211 | bufferlist outbl; | |
212 | ASSERT_EQ(0, cluster.mon_command(cmd, inbl, &outbl, NULL)); | |
213 | string outstr(outbl.c_str(), outbl.length()); | |
214 | json_spirit::Value v; | |
215 | ASSERT_NE(0, json_spirit::read(outstr, v)) << "unable to parse json." << '\n' << outstr; | |
216 | ||
217 | // pg_map | |
218 | json_spirit::Object& obj = v.get_obj(); | |
219 | get_snaptrim_stats(obj, &objects_trimmed, &snaptrim_duration); | |
220 | if (objects_trimmed < num_objs) { | |
221 | tries++; | |
222 | objects_trimmed = 0; | |
223 | std::cout << "Still waiting for all objects to be trimmed... " <<std::endl; | |
224 | sleep(30); | |
225 | } | |
226 | } while(objects_trimmed < num_objs && tries < 5); | |
227 | ||
228 | // final check for objects trimmed | |
229 | ASSERT_EQ(objects_trimmed, num_objs); | |
230 | std::cout << "Snaptrim duration: " << snaptrim_duration << std::endl; | |
231 | ASSERT_GT(snaptrim_duration, 0.0); | |
232 | ||
233 | // clean-up remaining objects | |
234 | ioctx.snap_set_read(librados::SNAP_HEAD); | |
235 | for (int i = 0; i < num_objs; ++i) { | |
236 | string obj = string("foo") + std::to_string(i); | |
237 | ASSERT_EQ(0, ioctx.remove(obj)); | |
238 | } | |
239 | } | |
240 | ||
241 | // EC testing | |
242 | TEST_F(LibRadosSnapshotStatsSelfManagedECPP, SnaptrimStatsECPP) { | |
243 | int num_objs = 10; | |
244 | int bsize = alignment; | |
245 | ||
246 | // create objects | |
247 | char *buf = (char *)new char[bsize]; | |
248 | memset(buf, 0xcc, bsize); | |
249 | bufferlist bl; | |
250 | bl.append(buf, bsize); | |
251 | for (int i = 0; i < num_objs; ++i) { | |
252 | string obj = string("foo") + std::to_string(i); | |
253 | ASSERT_EQ(0, ioctx.write(obj, bl, bsize, 0)); | |
254 | } | |
255 | ||
256 | std::vector<uint64_t> my_snaps; | |
257 | char *buf2 = (char *)new char[bsize]; | |
258 | memset(buf2, 0xdd, bsize); | |
259 | bufferlist bl2; | |
260 | bl2.append(buf2, bsize); | |
261 | for (int snap = 0; snap < 1; ++snap) { | |
262 | // create a snapshot, clone | |
263 | std::vector<uint64_t> ns(1); | |
264 | ns.insert(ns.end(), my_snaps.begin(), my_snaps.end()); | |
265 | my_snaps.swap(ns); | |
266 | ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0])); | |
267 | ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); | |
268 | for (int i = 0; i < num_objs; ++i) { | |
269 | string obj = string("foo") + std::to_string(i); | |
270 | ASSERT_EQ(0, ioctx.write(obj, bl2, bsize, bsize)); | |
271 | } | |
272 | } | |
273 | ||
274 | // wait for maps to settle | |
275 | cluster.wait_for_latest_osdmap(); | |
276 | ||
277 | // remove snaps - should trigger snaptrim | |
278 | for (unsigned snap = 0; snap < my_snaps.size(); ++snap) { | |
279 | ioctx.selfmanaged_snap_remove(my_snaps[snap]); | |
280 | } | |
281 | ||
282 | // sleep for few secs for the trim stats to populate | |
283 | std::cout << "Waiting for snaptrim stats to be generated" << std::endl; | |
284 | sleep(30); | |
285 | ||
286 | // Dump pg stats and determine if snaptrim stats are getting set | |
287 | int objects_trimmed = 0; | |
288 | double snaptrim_duration = 0.0; | |
289 | int tries = 0; | |
290 | do { | |
291 | string cmd = string("{\"prefix\": \"pg dump\",\"format\":\"json\"}"); | |
292 | bufferlist inbl; | |
293 | bufferlist outbl; | |
294 | ASSERT_EQ(0, cluster.mon_command(cmd, inbl, &outbl, NULL)); | |
295 | string outstr(outbl.c_str(), outbl.length()); | |
296 | json_spirit::Value v; | |
297 | ASSERT_NE(0, json_spirit::read(outstr, v)) << "unable to parse json." << '\n' << outstr; | |
298 | ||
299 | // pg_map | |
300 | json_spirit::Object& obj = v.get_obj(); | |
301 | get_snaptrim_stats(obj, &objects_trimmed, &snaptrim_duration); | |
302 | if (objects_trimmed < num_objs) { | |
303 | tries++; | |
304 | objects_trimmed = 0; | |
305 | std::cout << "Still waiting for all objects to be trimmed... " <<std::endl; | |
306 | sleep(30); | |
307 | } | |
308 | } while(objects_trimmed < num_objs && tries < 5); | |
309 | ||
310 | // final check for objects trimmed | |
311 | ASSERT_EQ(objects_trimmed, num_objs); | |
312 | std::cout << "Snaptrim duration: " << snaptrim_duration << std::endl; | |
313 | ASSERT_GT(snaptrim_duration, 0.0); | |
314 | ||
315 | // clean-up remaining objects | |
316 | ioctx.snap_set_read(LIBRADOS_SNAP_HEAD); | |
317 | for (int i = 0; i < num_objs; ++i) { | |
318 | string obj = string("foo") + std::to_string(i); | |
319 | ASSERT_EQ(0, ioctx.remove(obj)); | |
320 | } | |
321 | ||
322 | delete[] buf; | |
323 | delete[] buf2; | |
324 | } |