]>
Commit | Line | Data |
---|---|---|
1e59de90 | 1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
7c673cae FG |
2 | // vim: ts=8 sw=2 smarttab |
3 | ||
4 | #include "include/types.h" | |
5 | #include "cls/log/cls_log_types.h" | |
6 | #include "cls/log/cls_log_client.h" | |
7 | ||
8 | #include "include/utime.h" | |
9 | #include "common/Clock.h" | |
10 | #include "global/global_context.h" | |
11 | ||
12 | #include "gtest/gtest.h" | |
11fdf7f2 | 13 | #include "test/librados/test_cxx.h" |
7c673cae FG |
14 | |
15 | #include <errno.h> | |
16 | #include <string> | |
17 | #include <vector> | |
18 | ||
20effc67 TL |
19 | using namespace std; |
20 | ||
9f95a23c TL |
21 | /// creates a temporary pool and initializes an IoCtx for each test |
22 | class cls_log : public ::testing::Test { | |
23 | librados::Rados rados; | |
24 | std::string pool_name; | |
25 | protected: | |
26 | librados::IoCtx ioctx; | |
7c673cae | 27 | |
9f95a23c TL |
28 | void SetUp() { |
29 | pool_name = get_temp_pool_name(); | |
30 | /* create pool */ | |
31 | ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); | |
32 | ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); | |
33 | } | |
34 | void TearDown() { | |
35 | /* remove pool */ | |
36 | ioctx.close(); | |
37 | ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); | |
38 | } | |
39 | }; | |
7c673cae FG |
40 | |
41 | static int read_bl(bufferlist& bl, int *i) | |
42 | { | |
11fdf7f2 | 43 | auto iter = bl.cbegin(); |
7c673cae FG |
44 | |
45 | try { | |
11fdf7f2 | 46 | decode(*i, iter); |
7c673cae FG |
47 | } catch (buffer::error& err) { |
48 | std::cout << "failed to decode buffer" << std::endl; | |
49 | return -EIO; | |
50 | } | |
51 | ||
52 | return 0; | |
53 | } | |
54 | ||
55 | void add_log(librados::ObjectWriteOperation *op, utime_t& timestamp, string& section, string&name, int i) | |
56 | { | |
57 | bufferlist bl; | |
11fdf7f2 | 58 | encode(i, bl); |
7c673cae FG |
59 | |
60 | cls_log_add(*op, timestamp, section, name, bl); | |
61 | } | |
62 | ||
63 | ||
64 | string get_name(int i) | |
65 | { | |
66 | string name_prefix = "data-source"; | |
67 | ||
68 | char buf[16]; | |
69 | snprintf(buf, sizeof(buf), "%d", i); | |
70 | return name_prefix + buf; | |
71 | } | |
72 | ||
73 | void generate_log(librados::IoCtx& ioctx, string& oid, int max, utime_t& start_time, bool modify_time) | |
74 | { | |
75 | string section = "global"; | |
76 | ||
9f95a23c | 77 | librados::ObjectWriteOperation op; |
7c673cae FG |
78 | |
79 | int i; | |
80 | ||
81 | for (i = 0; i < max; i++) { | |
82 | uint32_t secs = start_time.sec(); | |
83 | if (modify_time) | |
84 | secs += i; | |
85 | ||
86 | utime_t ts(secs, start_time.nsec()); | |
87 | string name = get_name(i); | |
88 | ||
9f95a23c | 89 | add_log(&op, ts, section, name, i); |
7c673cae FG |
90 | } |
91 | ||
9f95a23c | 92 | ASSERT_EQ(0, ioctx.operate(oid, &op)); |
7c673cae FG |
93 | } |
94 | ||
95 | utime_t get_time(utime_t& start_time, int i, bool modify_time) | |
96 | { | |
97 | uint32_t secs = start_time.sec(); | |
98 | if (modify_time) | |
99 | secs += i; | |
100 | return utime_t(secs, start_time.nsec()); | |
101 | } | |
102 | ||
103 | void check_entry(cls_log_entry& entry, utime_t& start_time, int i, bool modified_time) | |
104 | { | |
105 | string section = "global"; | |
106 | string name = get_name(i); | |
107 | utime_t ts = get_time(start_time, i, modified_time); | |
108 | ||
109 | ASSERT_EQ(section, entry.section); | |
110 | ASSERT_EQ(name, entry.name); | |
111 | ASSERT_EQ(ts, entry.timestamp); | |
112 | } | |
113 | ||
9f95a23c TL |
114 | static int log_list(librados::IoCtx& ioctx, const std::string& oid, |
115 | utime_t& from, utime_t& to, | |
116 | const string& in_marker, int max_entries, | |
117 | list<cls_log_entry>& entries, | |
118 | string *out_marker, bool *truncated) | |
119 | { | |
120 | librados::ObjectReadOperation rop; | |
121 | cls_log_list(rop, from, to, in_marker, max_entries, | |
122 | entries, out_marker, truncated); | |
123 | bufferlist obl; | |
124 | return ioctx.operate(oid, &rop, &obl); | |
125 | } | |
7c673cae | 126 | |
9f95a23c TL |
127 | static int log_list(librados::IoCtx& ioctx, const std::string& oid, |
128 | utime_t& from, utime_t& to, int max_entries, | |
129 | list<cls_log_entry>& entries, bool *truncated) | |
7c673cae | 130 | { |
9f95a23c TL |
131 | std::string marker; |
132 | return log_list(ioctx, oid, from, to, marker, max_entries, | |
133 | entries, &marker, truncated); | |
134 | } | |
7c673cae | 135 | |
9f95a23c TL |
136 | static int log_list(librados::IoCtx& ioctx, const std::string& oid, |
137 | list<cls_log_entry>& entries) | |
138 | { | |
139 | utime_t from, to; | |
140 | bool truncated{false}; | |
141 | return log_list(ioctx, oid, from, to, 0, entries, &truncated); | |
142 | } | |
7c673cae | 143 | |
9f95a23c TL |
144 | TEST_F(cls_log, test_log_add_same_time) |
145 | { | |
7c673cae FG |
146 | /* add chains */ |
147 | string oid = "obj"; | |
148 | ||
149 | /* create object */ | |
150 | ASSERT_EQ(0, ioctx.create(oid, true)); | |
151 | ||
152 | /* generate log */ | |
153 | utime_t start_time = ceph_clock_now(); | |
9f95a23c | 154 | utime_t to_time = get_time(start_time, 1, true); |
7c673cae FG |
155 | generate_log(ioctx, oid, 10, start_time, false); |
156 | ||
7c673cae FG |
157 | list<cls_log_entry> entries; |
158 | bool truncated; | |
159 | ||
160 | /* check list */ | |
9f95a23c TL |
161 | { |
162 | ASSERT_EQ(0, log_list(ioctx, oid, start_time, to_time, 0, | |
163 | entries, &truncated)); | |
164 | ASSERT_EQ(10, (int)entries.size()); | |
165 | ASSERT_EQ(0, (int)truncated); | |
166 | } | |
7c673cae FG |
167 | list<cls_log_entry>::iterator iter; |
168 | ||
169 | /* need to sort returned entries, all were using the same time as key */ | |
170 | map<int, cls_log_entry> check_ents; | |
171 | ||
172 | for (iter = entries.begin(); iter != entries.end(); ++iter) { | |
173 | cls_log_entry& entry = *iter; | |
174 | ||
175 | int num; | |
176 | ASSERT_EQ(0, read_bl(entry.data, &num)); | |
177 | ||
178 | check_ents[num] = entry; | |
179 | } | |
180 | ||
181 | ASSERT_EQ(10, (int)check_ents.size()); | |
182 | ||
183 | map<int, cls_log_entry>::iterator ei; | |
184 | ||
185 | /* verify entries are as expected */ | |
186 | ||
187 | int i; | |
188 | ||
189 | for (i = 0, ei = check_ents.begin(); i < 10; i++, ++ei) { | |
190 | cls_log_entry& entry = ei->second; | |
191 | ||
192 | ASSERT_EQ(i, ei->first); | |
193 | check_entry(entry, start_time, i, false); | |
194 | } | |
195 | ||
7c673cae | 196 | /* check list again, now want to be truncated*/ |
9f95a23c TL |
197 | { |
198 | ASSERT_EQ(0, log_list(ioctx, oid, start_time, to_time, 1, | |
199 | entries, &truncated)); | |
200 | ASSERT_EQ(1, (int)entries.size()); | |
201 | ASSERT_EQ(1, (int)truncated); | |
202 | } | |
7c673cae FG |
203 | } |
204 | ||
9f95a23c | 205 | TEST_F(cls_log, test_log_add_different_time) |
7c673cae | 206 | { |
7c673cae FG |
207 | /* add chains */ |
208 | string oid = "obj"; | |
209 | ||
210 | /* create object */ | |
211 | ASSERT_EQ(0, ioctx.create(oid, true)); | |
212 | ||
213 | /* generate log */ | |
214 | utime_t start_time = ceph_clock_now(); | |
215 | generate_log(ioctx, oid, 10, start_time, true); | |
216 | ||
7c673cae FG |
217 | list<cls_log_entry> entries; |
218 | bool truncated; | |
219 | ||
220 | utime_t to_time = utime_t(start_time.sec() + 10, start_time.nsec()); | |
221 | ||
9f95a23c TL |
222 | { |
223 | /* check list */ | |
224 | ASSERT_EQ(0, log_list(ioctx, oid, start_time, to_time, 0, | |
225 | entries, &truncated)); | |
226 | ASSERT_EQ(10, (int)entries.size()); | |
227 | ASSERT_EQ(0, (int)truncated); | |
228 | } | |
7c673cae FG |
229 | |
230 | list<cls_log_entry>::iterator iter; | |
231 | ||
232 | /* returned entries should be sorted by time */ | |
233 | map<int, cls_log_entry> check_ents; | |
234 | ||
235 | int i; | |
236 | ||
237 | for (i = 0, iter = entries.begin(); iter != entries.end(); ++iter, ++i) { | |
238 | cls_log_entry& entry = *iter; | |
239 | ||
240 | int num; | |
241 | ||
242 | ASSERT_EQ(0, read_bl(entry.data, &num)); | |
243 | ||
244 | ASSERT_EQ(i, num); | |
245 | ||
246 | check_entry(entry, start_time, i, true); | |
247 | } | |
248 | ||
7c673cae | 249 | /* check list again with shifted time */ |
9f95a23c TL |
250 | { |
251 | utime_t next_time = get_time(start_time, 1, true); | |
252 | ASSERT_EQ(0, log_list(ioctx, oid, next_time, to_time, 0, | |
253 | entries, &truncated)); | |
254 | ASSERT_EQ(9u, entries.size()); | |
255 | ASSERT_FALSE(truncated); | |
256 | } | |
7c673cae | 257 | |
9f95a23c | 258 | string marker; |
7c673cae FG |
259 | i = 0; |
260 | do { | |
9f95a23c TL |
261 | string old_marker = std::move(marker); |
262 | ASSERT_EQ(0, log_list(ioctx, oid, start_time, to_time, old_marker, 1, | |
263 | entries, &marker, &truncated)); | |
7c673cae FG |
264 | ASSERT_NE(old_marker, marker); |
265 | ASSERT_EQ(1, (int)entries.size()); | |
266 | ||
267 | ++i; | |
268 | ASSERT_GE(10, i); | |
269 | } while (truncated); | |
270 | ||
271 | ASSERT_EQ(10, i); | |
7c673cae FG |
272 | } |
273 | ||
9f95a23c TL |
274 | int do_log_trim(librados::IoCtx& ioctx, const std::string& oid, |
275 | const std::string& from_marker, const std::string& to_marker) | |
7c673cae | 276 | { |
9f95a23c TL |
277 | librados::ObjectWriteOperation op; |
278 | cls_log_trim(op, {}, {}, from_marker, to_marker); | |
279 | return ioctx.operate(oid, &op); | |
280 | } | |
7c673cae | 281 | |
9f95a23c TL |
282 | int do_log_trim(librados::IoCtx& ioctx, const std::string& oid, |
283 | const utime_t& from_time, const utime_t& to_time) | |
284 | { | |
285 | librados::ObjectWriteOperation op; | |
286 | cls_log_trim(op, from_time, to_time, "", ""); | |
287 | return ioctx.operate(oid, &op); | |
288 | } | |
7c673cae | 289 | |
9f95a23c TL |
290 | TEST_F(cls_log, trim_by_time) |
291 | { | |
7c673cae FG |
292 | /* add chains */ |
293 | string oid = "obj"; | |
294 | ||
295 | /* create object */ | |
296 | ASSERT_EQ(0, ioctx.create(oid, true)); | |
297 | ||
298 | /* generate log */ | |
299 | utime_t start_time = ceph_clock_now(); | |
300 | generate_log(ioctx, oid, 10, start_time, true); | |
301 | ||
7c673cae FG |
302 | list<cls_log_entry> entries; |
303 | bool truncated; | |
304 | ||
305 | /* check list */ | |
306 | ||
307 | /* trim */ | |
308 | utime_t to_time = get_time(start_time, 10, true); | |
309 | ||
310 | for (int i = 0; i < 10; i++) { | |
311 | utime_t trim_time = get_time(start_time, i, true); | |
312 | ||
313 | utime_t zero_time; | |
7c673cae | 314 | |
9f95a23c TL |
315 | ASSERT_EQ(0, do_log_trim(ioctx, oid, zero_time, trim_time)); |
316 | ASSERT_EQ(-ENODATA, do_log_trim(ioctx, oid, zero_time, trim_time)); | |
7c673cae | 317 | |
9f95a23c TL |
318 | ASSERT_EQ(0, log_list(ioctx, oid, start_time, to_time, 0, |
319 | entries, &truncated)); | |
320 | ASSERT_EQ(9u - i, entries.size()); | |
321 | ASSERT_FALSE(truncated); | |
322 | } | |
323 | } | |
7c673cae | 324 | |
9f95a23c TL |
325 | TEST_F(cls_log, trim_by_marker) |
326 | { | |
327 | string oid = "obj"; | |
328 | ASSERT_EQ(0, ioctx.create(oid, true)); | |
7c673cae | 329 | |
9f95a23c TL |
330 | utime_t start_time = ceph_clock_now(); |
331 | generate_log(ioctx, oid, 10, start_time, true); | |
7c673cae | 332 | |
9f95a23c TL |
333 | utime_t zero_time; |
334 | std::vector<cls_log_entry> log1; | |
335 | { | |
336 | list<cls_log_entry> entries; | |
337 | ASSERT_EQ(0, log_list(ioctx, oid, entries)); | |
338 | ASSERT_EQ(10u, entries.size()); | |
7c673cae | 339 | |
9f95a23c TL |
340 | log1.assign(std::make_move_iterator(entries.begin()), |
341 | std::make_move_iterator(entries.end())); | |
342 | } | |
343 | // trim front of log | |
344 | { | |
345 | const std::string from = ""; | |
346 | const std::string to = log1[0].id; | |
347 | ASSERT_EQ(0, do_log_trim(ioctx, oid, from, to)); | |
348 | list<cls_log_entry> entries; | |
349 | ASSERT_EQ(0, log_list(ioctx, oid, entries)); | |
350 | ASSERT_EQ(9u, entries.size()); | |
351 | EXPECT_EQ(log1[1].id, entries.begin()->id); | |
352 | ASSERT_EQ(-ENODATA, do_log_trim(ioctx, oid, from, to)); | |
353 | } | |
354 | // trim back of log | |
355 | { | |
356 | const std::string from = log1[8].id; | |
357 | const std::string to = "9"; | |
358 | ASSERT_EQ(0, do_log_trim(ioctx, oid, from, to)); | |
359 | list<cls_log_entry> entries; | |
360 | ASSERT_EQ(0, log_list(ioctx, oid, entries)); | |
361 | ASSERT_EQ(8u, entries.size()); | |
362 | EXPECT_EQ(log1[8].id, entries.rbegin()->id); | |
363 | ASSERT_EQ(-ENODATA, do_log_trim(ioctx, oid, from, to)); | |
364 | } | |
365 | // trim a key from the middle | |
366 | { | |
367 | const std::string from = log1[3].id; | |
368 | const std::string to = log1[4].id; | |
369 | ASSERT_EQ(0, do_log_trim(ioctx, oid, from, to)); | |
370 | list<cls_log_entry> entries; | |
371 | ASSERT_EQ(0, log_list(ioctx, oid, entries)); | |
372 | ASSERT_EQ(7u, entries.size()); | |
373 | ASSERT_EQ(-ENODATA, do_log_trim(ioctx, oid, from, to)); | |
374 | } | |
375 | // trim full log | |
376 | { | |
377 | const std::string from = ""; | |
378 | const std::string to = "9"; | |
379 | ASSERT_EQ(0, do_log_trim(ioctx, oid, from, to)); | |
380 | list<cls_log_entry> entries; | |
381 | ASSERT_EQ(0, log_list(ioctx, oid, entries)); | |
382 | ASSERT_EQ(0u, entries.size()); | |
383 | ASSERT_EQ(-ENODATA, do_log_trim(ioctx, oid, from, to)); | |
384 | } | |
7c673cae | 385 | } |