1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
11 #include "common/debug.h"
13 #include "include/types.h"
14 #include "include/rados/librados.hpp"
15 #include "common/Mutex.h"
16 #include "common/Cond.h"
17 #include "common/iso_8601.h"
18 #include "common/Thread.h"
19 #include "rgw_common.h"
20 #include "rgw_rados.h"
21 #include "rgw_multi.h"
22 #include "cls/rgw/cls_rgw_types.h"
27 #define HASH_PRIME 7877
28 #define MAX_ID_LEN 255
29 static string lc_oid_prefix
= "lc";
30 static string lc_index_lock_name
= "lc_process";
32 extern const char* LC_STATUS
[];
45 //At present only current object has expiration date
49 LCExpiration(const string
& _days
, const string
& _date
) : days(_days
), date(_date
) {}
51 void encode(bufferlist
& bl
) const {
52 ENCODE_START(3, 2, bl
);
57 void decode(bufferlist::const_iterator
& bl
) {
58 DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, bl
);
65 void dump(Formatter
*f
) const;
66 // static void generate_test_instances(list<ACLOwner*>& o);
67 void set_days(const string
& _days
) { days
= _days
; }
68 string
get_days_str() const {
71 int get_days() const {return atoi(days
.c_str()); }
72 bool has_days() const {
75 void set_date(const string
& _date
) { date
= _date
; }
76 string
get_date() const {
79 bool has_date() const {
83 return days
.empty() && date
.empty();
86 if (!days
.empty() && !date
.empty()) {
88 } else if (!days
.empty() && get_days() <= 0) {
91 //We've checked date in xml parsing
95 WRITE_CLASS_ENCODER(LCExpiration
)
102 string storage_class
;
105 int get_days() const {
106 return atoi(days
.c_str());
109 string
get_date() const {
113 string
get_storage_class() const {
114 return storage_class
;
117 bool has_days() const {
118 return !days
.empty();
121 bool has_date() const {
122 return !date
.empty();
126 return days
.empty() && date
.empty();
130 if (!days
.empty() && !date
.empty()) {
132 } else if (!days
.empty() && get_days() <=0) {
135 //We've checked date in xml parsing
139 void encode(bufferlist
& bl
) const {
140 ENCODE_START(1, 1, bl
);
143 encode(storage_class
, bl
);
147 void decode(bufferlist::const_iterator
& bl
) {
151 decode(storage_class
, bl
);
154 void dump(Formatter
*f
) const;
156 WRITE_CLASS_ENCODER(LCTransition
)
166 const std::string
& get_prefix() const {
170 const RGWObjTags
& get_tags() const {
175 return !(has_prefix() || has_tags());
178 // Determine if we need AND tag when creating xml
179 bool has_multi_condition() const {
180 if (obj_tags
.count() > 1)
182 else if (has_prefix() && has_tags())
188 bool has_prefix() const {
189 return !prefix
.empty();
192 bool has_tags() const {
193 return !obj_tags
.empty();
196 void encode(bufferlist
& bl
) const {
197 ENCODE_START(2, 1, bl
);
199 encode(obj_tags
, bl
);
202 void decode(bufferlist::const_iterator
& bl
) {
206 decode(obj_tags
, bl
);
210 void dump(Formatter
*f
) const;
212 WRITE_CLASS_ENCODER(LCFilter
)
222 LCExpiration expiration
;
223 LCExpiration noncur_expiration
;
224 LCExpiration mp_expiration
;
226 map
<string
, LCTransition
> transitions
;
227 map
<string
, LCTransition
> noncur_transitions
;
228 bool dm_expiration
= false;
235 const string
& get_id() const {
239 const string
& get_status() const {
243 bool is_enabled() const {
244 return status
== "Enabled";
247 void set_enabled(bool flag
) {
248 status
= (flag
? "Enabled" : "Disabled");
251 const string
& get_prefix() const {
255 const LCFilter
& get_filter() const {
259 const LCExpiration
& get_expiration() const {
263 const LCExpiration
& get_noncur_expiration() const {
264 return noncur_expiration
;
267 const LCExpiration
& get_mp_expiration() const {
268 return mp_expiration
;
271 bool get_dm_expiration() const {
272 return dm_expiration
;
275 const map
<string
, LCTransition
>& get_transitions() const {
279 const map
<string
, LCTransition
>& get_noncur_transitions() const {
280 return noncur_transitions
;
283 void set_id(const string
& _id
) {
287 void set_prefix(const string
& _prefix
) {
291 void set_status(const string
& _status
) {
295 void set_expiration(const LCExpiration
& _expiration
) {
296 expiration
= _expiration
;
299 void set_noncur_expiration(const LCExpiration
& _noncur_expiration
) {
300 noncur_expiration
= _noncur_expiration
;
303 void set_mp_expiration(const LCExpiration
& _mp_expiration
) {
304 mp_expiration
= _mp_expiration
;
307 void set_dm_expiration(bool _dm_expiration
) {
308 dm_expiration
= _dm_expiration
;
311 bool add_transition(const LCTransition
& _transition
) {
312 auto ret
= transitions
.emplace(_transition
.get_storage_class(), _transition
);
316 bool add_noncur_transition(const LCTransition
& _noncur_transition
) {
317 auto ret
= noncur_transitions
.emplace(_noncur_transition
.get_storage_class(), _noncur_transition
);
323 void encode(bufferlist
& bl
) const {
324 ENCODE_START(6, 1, bl
);
328 encode(expiration
, bl
);
329 encode(noncur_expiration
, bl
);
330 encode(mp_expiration
, bl
);
331 encode(dm_expiration
, bl
);
333 encode(transitions
, bl
);
334 encode(noncur_transitions
, bl
);
337 void decode(bufferlist::const_iterator
& bl
) {
338 DECODE_START_LEGACY_COMPAT_LEN(6, 1, 1, bl
);
342 decode(expiration
, bl
);
344 decode(noncur_expiration
, bl
);
347 decode(mp_expiration
, bl
);
350 decode(dm_expiration
, bl
);
356 decode(transitions
, bl
);
357 decode(noncur_transitions
, bl
);
361 void dump(Formatter
*f
) const;
363 void init_simple_days_rule(std::string_view _id
, std::string_view _prefix
, int num_days
);
365 WRITE_CLASS_ENCODER(LCRule
)
367 struct transition_action
370 boost::optional
<ceph::real_time
> date
;
371 string storage_class
;
372 transition_action() : days(0) {}
375 /* XXX why not LCRule? */
380 bool dm_expiration
{false};
382 int noncur_expiration
{0};
383 int mp_expiration
{0};
384 boost::optional
<ceph::real_time
> expiration_date
;
385 boost::optional
<RGWObjTags
> obj_tags
;
386 map
<string
, transition_action
> transitions
;
387 map
<string
, transition_action
> noncur_transitions
;
392 lc_op(const std::string id
) : id(id
)
395 void dump(Formatter
*f
) const;
398 class RGWLifecycleConfiguration
402 multimap
<string
, lc_op
> prefix_map
;
403 multimap
<string
, LCRule
> rule_map
;
404 bool _add_rule(const LCRule
& rule
);
405 bool has_same_action(const lc_op
& first
, const lc_op
& second
);
407 explicit RGWLifecycleConfiguration(CephContext
*_cct
) : cct(_cct
) {}
408 RGWLifecycleConfiguration() : cct(NULL
) {}
410 void set_ctx(CephContext
*ctx
) {
414 virtual ~RGWLifecycleConfiguration() {}
416 // int get_perm(string& id, int perm_mask);
417 // int get_group_perm(ACLGroupTypeEnum group, int perm_mask);
418 void encode(bufferlist
& bl
) const {
419 ENCODE_START(1, 1, bl
);
420 encode(rule_map
, bl
);
423 void decode(bufferlist::const_iterator
& bl
) {
424 DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl
);
425 decode(rule_map
, bl
);
426 multimap
<string
, LCRule
>::iterator iter
;
427 for (iter
= rule_map
.begin(); iter
!= rule_map
.end(); ++iter
) {
428 LCRule
& rule
= iter
->second
;
433 void dump(Formatter
*f
) const;
434 static void generate_test_instances(list
<RGWLifecycleConfiguration
*>& o
);
436 void add_rule(const LCRule
& rule
);
438 int check_and_add_rule(const LCRule
& rule
);
442 multimap
<string
, LCRule
>& get_rule_map() { return rule_map
; }
443 multimap
<string
, lc_op
>& get_prefix_map() { return prefix_map
; }
445 void create_default(string id, string name) {
447 grant.set_canon(id, name, RGW_PERM_FULL_CONTROL);
452 WRITE_CLASS_ENCODER(RGWLifecycleConfiguration
)
454 class RGWLC
: public DoutPrefixProvider
{
458 string
*obj_names
{nullptr};
459 std::atomic
<bool> down_flag
= { false };
462 class LCWorker
: public Thread
{
463 const DoutPrefixProvider
*dpp
;
470 LCWorker(const DoutPrefixProvider
* _dpp
, CephContext
*_cct
, RGWLC
*_lc
) : dpp(_dpp
), cct(_cct
), lc(_lc
), lock("LCWorker") {}
471 void *entry() override
;
473 bool should_work(utime_t
& now
);
474 int schedule_next_start_time(utime_t
& start
, utime_t
& now
);
479 RGWLC() : cct(NULL
), store(NULL
), worker(NULL
) {}
485 void initialize(CephContext
*_cct
, RGWRados
*_store
);
489 int process(int index
, int max_secs
);
490 bool if_already_run_today(time_t& start_date
);
491 int list_lc_progress(const string
& marker
, uint32_t max_entries
, map
<string
, int> *progress_map
);
492 int bucket_lc_prepare(int index
);
493 int bucket_lc_process(string
& shard_id
);
494 int bucket_lc_post(int index
, int max_lock_sec
, pair
<string
, int >& entry
, int& result
);
496 void start_processor();
497 void stop_processor();
498 int set_bucket_config(RGWBucketInfo
& bucket_info
,
499 const map
<string
, bufferlist
>& bucket_attrs
,
500 RGWLifecycleConfiguration
*config
);
501 int remove_bucket_config(RGWBucketInfo
& bucket_info
,
502 const map
<string
, bufferlist
>& bucket_attrs
);
504 CephContext
*get_cct() const override
{ return store
->ctx(); }
505 unsigned get_subsys() const;
506 std::ostream
& gen_prefix(std::ostream
& out
) const;
510 int handle_multipart_expiration(RGWRados::Bucket
*target
,
511 const multimap
<string
, lc_op
>& prefix_map
);
516 int fix_lc_shard_entry(RGWRados
*store
, const RGWBucketInfo
& bucket_info
,
517 const map
<std::string
,bufferlist
>& battrs
);
519 } // namespace rgw::lc