]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librados/snapshots_stats_cxx.cc
import quincy 17.2.0
[ceph.git] / ceph / src / test / librados / snapshots_stats_cxx.cc
CommitLineData
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
14using namespace librados;
15
16using std::string;
17
18class LibRadosSnapshotStatsSelfManagedPP : public RadosTestPP {
19public:
20 LibRadosSnapshotStatsSelfManagedPP() {};
21 ~LibRadosSnapshotStatsSelfManagedPP() override {};
22protected:
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
70class LibRadosSnapshotStatsSelfManagedECPP : public RadosTestECPP {
71public:
72 LibRadosSnapshotStatsSelfManagedECPP() {};
73 ~LibRadosSnapshotStatsSelfManagedECPP() override {};
74protected:
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
122void 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}
159const int bufsize = 128;
160
161TEST_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
242TEST_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}