1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
11 #include "common/debug.h"
13 #include "include/types.h"
14 #include "include/rados/librados.hpp"
15 #include "common/ceph_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 "cls/rgw/cls_rgw_types.h"
23 #include "rgw_rados.h"
28 #define HASH_PRIME 7877
29 #define MAX_ID_LEN 255
30 static string lc_oid_prefix
= "lc";
31 static string lc_index_lock_name
= "lc_process";
33 extern const char* LC_STATUS
[];
46 //At present only current object has expiration date
50 LCExpiration(const string
& _days
, const string
& _date
) : days(_days
), date(_date
) {}
52 void encode(bufferlist
& bl
) const {
53 ENCODE_START(3, 2, bl
);
58 void decode(bufferlist::const_iterator
& bl
) {
59 DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, bl
);
66 void dump(Formatter
*f
) const;
67 // static void generate_test_instances(list<ACLOwner*>& o);
68 void set_days(const string
& _days
) { days
= _days
; }
69 string
get_days_str() const {
72 int get_days() const {return atoi(days
.c_str()); }
73 bool has_days() const {
76 void set_date(const string
& _date
) { date
= _date
; }
77 string
get_date() const {
80 bool has_date() const {
84 return days
.empty() && date
.empty();
87 if (!days
.empty() && !date
.empty()) {
89 } else if (!days
.empty() && get_days() <= 0) {
92 //We've checked date in xml parsing
96 WRITE_CLASS_ENCODER(LCExpiration
)
103 string storage_class
;
106 int get_days() const {
107 return atoi(days
.c_str());
110 string
get_date() const {
114 string
get_storage_class() const {
115 return storage_class
;
118 bool has_days() const {
119 return !days
.empty();
122 bool has_date() const {
123 return !date
.empty();
127 return days
.empty() && date
.empty();
131 if (!days
.empty() && !date
.empty()) {
133 } else if (!days
.empty() && get_days() < 0) {
136 //We've checked date in xml parsing
140 void encode(bufferlist
& bl
) const {
141 ENCODE_START(1, 1, bl
);
144 encode(storage_class
, bl
);
148 void decode(bufferlist::const_iterator
& bl
) {
152 decode(storage_class
, bl
);
155 void dump(Formatter
*f
) const {
156 f
->dump_string("days", days
);
157 f
->dump_string("date", date
);
158 f
->dump_string("storage_class", storage_class
);
161 WRITE_CLASS_ENCODER(LCTransition
)
171 const std::string
& get_prefix() const {
175 const RGWObjTags
& get_tags() const {
180 return !(has_prefix() || has_tags());
183 // Determine if we need AND tag when creating xml
184 bool has_multi_condition() const {
185 if (obj_tags
.count() > 1)
190 bool has_prefix() const {
191 return !prefix
.empty();
194 bool has_tags() const {
195 return !obj_tags
.empty();
198 void encode(bufferlist
& bl
) const {
199 ENCODE_START(2, 1, bl
);
201 encode(obj_tags
, bl
);
204 void decode(bufferlist::const_iterator
& bl
) {
208 decode(obj_tags
, bl
);
212 void dump(Formatter
*f
) const;
214 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) {}
373 void dump(Formatter
*f
) const {
375 f
->dump_int("days", days
);
378 f
->dump_stream("date") << ut
;
383 /* XXX why not LCRule? */
388 bool dm_expiration
{false};
390 int noncur_expiration
{0};
391 int mp_expiration
{0};
392 boost::optional
<ceph::real_time
> expiration_date
;
393 boost::optional
<RGWObjTags
> obj_tags
;
394 map
<string
, transition_action
> transitions
;
395 map
<string
, transition_action
> noncur_transitions
;
400 lc_op(const std::string id
) : id(id
)
403 void dump(Formatter
*f
) const;
406 class RGWLifecycleConfiguration
410 multimap
<string
, lc_op
> prefix_map
;
411 multimap
<string
, LCRule
> rule_map
;
412 bool _add_rule(const LCRule
& rule
);
413 bool has_same_action(const lc_op
& first
, const lc_op
& second
);
415 explicit RGWLifecycleConfiguration(CephContext
*_cct
) : cct(_cct
) {}
416 RGWLifecycleConfiguration() : cct(NULL
) {}
418 void set_ctx(CephContext
*ctx
) {
422 virtual ~RGWLifecycleConfiguration() {}
424 // int get_perm(string& id, int perm_mask);
425 // int get_group_perm(ACLGroupTypeEnum group, int perm_mask);
426 void encode(bufferlist
& bl
) const {
427 ENCODE_START(1, 1, bl
);
428 encode(rule_map
, bl
);
431 void decode(bufferlist::const_iterator
& bl
) {
432 DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl
);
433 decode(rule_map
, bl
);
434 multimap
<string
, LCRule
>::iterator iter
;
435 for (iter
= rule_map
.begin(); iter
!= rule_map
.end(); ++iter
) {
436 LCRule
& rule
= iter
->second
;
441 void dump(Formatter
*f
) const;
442 static void generate_test_instances(list
<RGWLifecycleConfiguration
*>& o
);
444 void add_rule(const LCRule
& rule
);
446 int check_and_add_rule(const LCRule
& rule
);
450 multimap
<string
, LCRule
>& get_rule_map() { return rule_map
; }
451 multimap
<string
, lc_op
>& get_prefix_map() { return prefix_map
; }
453 void create_default(string id, string name) {
455 grant.set_canon(id, name, RGW_PERM_FULL_CONTROL);
460 WRITE_CLASS_ENCODER(RGWLifecycleConfiguration
)
462 class RGWLC
: public DoutPrefixProvider
{
464 rgw::sal::RGWRadosStore
*store
;
465 std::unique_ptr
<rgw::sal::Lifecycle
> sal_lc
;
467 string
*obj_names
{nullptr};
468 std::atomic
<bool> down_flag
= { false };
475 class LCWorker
: public Thread
477 const DoutPrefixProvider
*dpp
;
482 std::condition_variable cond
;
483 WorkPool
* workpool
{nullptr};
487 using lock_guard
= std::lock_guard
<std::mutex
>;
488 using unique_lock
= std::unique_lock
<std::mutex
>;
490 LCWorker(const DoutPrefixProvider
* dpp
, CephContext
*_cct
, RGWLC
*_lc
,
492 RGWLC
* get_lc() { return lc
; }
493 void *entry() override
;
495 bool should_work(utime_t
& now
);
496 int schedule_next_start_time(utime_t
& start
, utime_t
& now
);
499 friend class RGWRados
;
504 friend class RGWRados
;
506 std::vector
<std::unique_ptr
<RGWLC::LCWorker
>> workers
;
508 RGWLC() : cct(nullptr), store(nullptr) {}
511 void initialize(CephContext
*_cct
, rgw::sal::RGWRadosStore
*_store
);
514 int process(LCWorker
* worker
, bool once
);
515 int process(int index
, int max_secs
, LCWorker
* worker
, bool once
);
516 bool if_already_run_today(time_t start_date
);
517 bool expired_session(time_t started
);
518 time_t thread_stop_at();
519 int list_lc_progress(string
& marker
, uint32_t max_entries
,
520 vector
<rgw::sal::Lifecycle::LCEntry
>&, int& index
);
521 int bucket_lc_prepare(int index
, LCWorker
* worker
);
522 int bucket_lc_process(string
& shard_id
, LCWorker
* worker
, time_t stop_at
,
524 int bucket_lc_post(int index
, int max_lock_sec
,
525 rgw::sal::Lifecycle::LCEntry
& entry
, int& result
, LCWorker
* worker
);
527 void start_processor();
528 void stop_processor();
529 int set_bucket_config(RGWBucketInfo
& bucket_info
,
530 const map
<string
, bufferlist
>& bucket_attrs
,
531 RGWLifecycleConfiguration
*config
);
532 int remove_bucket_config(RGWBucketInfo
& bucket_info
,
533 const map
<string
, bufferlist
>& bucket_attrs
);
535 CephContext
*get_cct() const override
{ return cct
; }
536 rgw::sal::Lifecycle
*get_lc() const { return sal_lc
.get(); }
537 unsigned get_subsys() const;
538 std::ostream
& gen_prefix(std::ostream
& out
) const;
542 int handle_multipart_expiration(rgw::sal::RGWBucket
* target
,
543 const multimap
<string
, lc_op
>& prefix_map
,
544 LCWorker
* worker
, time_t stop_at
, bool once
);
549 int fix_lc_shard_entry(rgw::sal::RGWRadosStore
*store
,
550 rgw::sal::Lifecycle
* sal_lc
,
551 const RGWBucketInfo
& bucket_info
,
552 const map
<std::string
,bufferlist
>& battrs
);
554 std::string
s3_expiration_header(
555 DoutPrefixProvider
* dpp
,
556 const rgw_obj_key
& obj_key
,
557 const RGWObjTags
& obj_tagset
,
558 const ceph::real_time
& mtime
,
559 const std::map
<std::string
, buffer::list
>& bucket_attrs
);
561 bool s3_multipart_abort_header(
562 DoutPrefixProvider
* dpp
,
563 const rgw_obj_key
& obj_key
,
564 const ceph::real_time
& mtime
,
565 const std::map
<std::string
, buffer::list
>& bucket_attrs
,
566 ceph::real_time
& abort_date
,
567 std::string
& rule_id
);
569 } // namespace rgw::lc