Skip to content

Commit 42ee938

Browse files
committed
NC | lifecycle | add newer noncurrent versions rule
Signed-off-by: nadav mizrahi <[email protected]>
1 parent 20d8f05 commit 42ee938

File tree

2 files changed

+412
-108
lines changed

2 files changed

+412
-108
lines changed

src/manage_nsfs/nc_lifecycle.js

Lines changed: 131 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -415,16 +415,22 @@ class NCLifecycle {
415415
async get_candidates(bucket_json, lifecycle_rule, object_sdk) {
416416
const candidates = { abort_mpu_candidates: [], delete_candidates: [] };
417417
const rule_state = this.lifecycle_run_status.buckets_statuses[bucket_json.name].rules_statuses[lifecycle_rule.id]?.state || {};
418+
const versions_list = undefined;
418419
if (lifecycle_rule.expiration) {
419420
candidates.delete_candidates = await this.get_candidates_by_expiration_rule(lifecycle_rule, bucket_json,
420-
object_sdk, rule_state);
421+
object_sdk);
421422
if (lifecycle_rule.expiration.days || lifecycle_rule.expiration.expired_object_delete_marker) {
422423
const dm_candidates = await this.get_candidates_by_expiration_delete_marker_rule(lifecycle_rule, bucket_json);
423424
candidates.delete_candidates = candidates.delete_candidates.concat(dm_candidates);
424425
}
425426
}
426427
if (lifecycle_rule.noncurrent_version_expiration) {
427-
const non_current_candidates = await this.get_candidates_by_noncurrent_version_expiration_rule(lifecycle_rule, bucket_json);
428+
const non_current_candidates = await this.get_candidates_by_noncurrent_version_expiration_rule(
429+
lifecycle_rule,
430+
bucket_json,
431+
object_sdk,
432+
{versions_list}
433+
);
428434
candidates.delete_candidates = candidates.delete_candidates.concat(non_current_candidates);
429435
}
430436
if (lifecycle_rule.abort_incomplete_multipart_upload) {
@@ -472,12 +478,12 @@ class NCLifecycle {
472478
* @param {Object} bucket_json
473479
* @returns {Promise<Object[]>}
474480
*/
475-
async get_candidates_by_expiration_rule(lifecycle_rule, bucket_json, object_sdk, rule_state) {
481+
async get_candidates_by_expiration_rule(lifecycle_rule, bucket_json, object_sdk) {
476482
const is_gpfs = nb_native().fs.gpfs;
477483
if (is_gpfs && config.NC_LIFECYCLE_GPFS_ILM_ENABLED) {
478484
return this.get_candidates_by_expiration_rule_gpfs(lifecycle_rule, bucket_json);
479485
} else {
480-
return this.get_candidates_by_expiration_rule_posix(lifecycle_rule, bucket_json, object_sdk, rule_state);
486+
return this.get_candidates_by_expiration_rule_posix(lifecycle_rule, bucket_json, object_sdk);
481487
}
482488
}
483489

@@ -490,26 +496,41 @@ class NCLifecycle {
490496
return [];
491497
}
492498

499+
async load_objects_list(object_sdk, lifecycle_rule, bucket_json, rule_state) {
500+
const objects_list = await object_sdk.list_objects({
501+
bucket: bucket_json.name,
502+
prefix: lifecycle_rule.filter?.prefix,
503+
key_marker: rule_state.key_marker,
504+
limit: config.NC_LIFECYCLE_LIST_BATCH_SIZE
505+
});
506+
if (objects_list.is_truncated) {
507+
rule_state.key_marker = objects_list.next_marker;
508+
rule_state.is_finished = false;
509+
} else {
510+
rule_state.is_finished = true;
511+
}
512+
const bucket_state = this.lifecycle_run_status.buckets_statuses[bucket_json.name].state;
513+
bucket_state.num_processed_objects += objects_list.objects.length;
514+
return objects_list;
515+
}
516+
493517
/**
494518
*
495519
* @param {*} lifecycle_rule
496520
* @param {Object} bucket_json
497521
* @returns {Promise<Object[]>}
498522
*/
499-
async get_candidates_by_expiration_rule_posix(lifecycle_rule, bucket_json, object_sdk, rule_state) {
523+
async get_candidates_by_expiration_rule_posix(lifecycle_rule, bucket_json, object_sdk) {
524+
const rule_state = this.lifecycle_run_status.buckets_statuses[bucket_json.name].rules_statuses[lifecycle_rule.id].state.expire;
525+
if (rule_state.is_finished) return [];
500526
const expiration = this._get_expiration_time(lifecycle_rule.expiration);
501527
if (expiration < 0) return [];
502528
const filter_func = this._build_lifecycle_filter({filter: lifecycle_rule.filter, expiration});
503529

504530
const filtered_objects = [];
505531
// TODO list_objects does not accept a filter and works in batch sizes of 1000. should handle batching
506532
// also should maybe create a helper function or add argument for a filter in list object
507-
const objects_list = await object_sdk.list_objects({
508-
bucket: bucket_json.name,
509-
prefix: lifecycle_rule.filter?.prefix,
510-
key_marker: rule_state.key_marker,
511-
limit: config.NC_LIFECYCLE_LIST_BATCH_SIZE
512-
});
533+
const objects_list = await this.load_objects_list(object_sdk, lifecycle_rule, bucket_json, rule_state);
513534
objects_list.objects.forEach(obj => {
514535
const lifecycle_object = this._get_lifecycle_object_info_from_list_object_entry(obj);
515536
if (filter_func(lifecycle_object)) {
@@ -518,14 +539,6 @@ class NCLifecycle {
518539
filtered_objects.push(candidate);
519540
}
520541
});
521-
522-
const bucket_state = this.lifecycle_run_status.buckets_statuses[bucket_json.name].state;
523-
bucket_state.num_processed_objects += objects_list.objects.length;
524-
if (objects_list.is_truncated) {
525-
rule_state.key_marker = objects_list.next_marker;
526-
} else {
527-
rule_state.is_finished = true;
528-
}
529542
return filtered_objects;
530543
}
531544

@@ -543,6 +556,63 @@ class NCLifecycle {
543556
/////////////////////////////////////////////
544557
//////// NON CURRENT VERSION HELPERS ////////
545558
/////////////////////////////////////////////
559+
/**
560+
* load versions list bacth and update state for the next cycle
561+
* @param {Object} object_sdk
562+
* @param {Object} bucket_json
563+
* @param {Object} rule_state
564+
* @returns
565+
*/
566+
async load_versions_list(object_sdk, bucket_json, rule_state) {
567+
const list_versions = await object_sdk.list_object_versions({
568+
bucket: bucket_json.name,
569+
prefix: rule_state.filter?.prefix,
570+
limit: config.NC_LIFECYCLE_LIST_BATCH_SIZE,
571+
key_marker: rule_state.key_marker_versioned,
572+
version_id_marker: rule_state.version_id_marker
573+
});
574+
if (list_versions.is_truncated) {
575+
rule_state.is_finished = false;
576+
rule_state.key_marker_versioned = list_versions.next_marker;
577+
rule_state.version_id_marker = list_versions.next_version_id_marker;
578+
} else {
579+
rule_state.is_finished = true;
580+
}
581+
const bucket_state = this.lifecycle_run_status.buckets_statuses[bucket_json.name].state;
582+
bucket_state.num_processed_objects += list_versions.objects.length;
583+
return list_versions;
584+
}
585+
586+
/**
587+
* check if object is delete candidate based on newer noncurrent versions rule
588+
* @param {Object} object_info
589+
* @param {Object} newer_noncurrent_state
590+
* @param {Number} num_newer_versions
591+
* @returns
592+
*/
593+
filter_newer_versions(object_info, newer_noncurrent_state, num_newer_versions) {
594+
if (object_info.is_latest) {
595+
newer_noncurrent_state.version_count = 0; //latest
596+
newer_noncurrent_state.current_version = object_info.key;
597+
return false;
598+
}
599+
newer_noncurrent_state.version_count += 1;
600+
if (newer_noncurrent_state.version_count > num_newer_versions) {
601+
return true;
602+
}
603+
return false;
604+
}
605+
606+
/**
607+
* check if object is delete candidate based on number of noncurrent days rule
608+
* @param {Object} object_info
609+
* @param {Number} num_non_current_days
610+
* @returns
611+
*/
612+
filter_noncurrent_days(object_info, num_non_current_days) {
613+
//TODO implement
614+
return true;
615+
}
546616

547617
/**
548618
* get_candidates_by_noncurrent_version_expiration_rule processes the noncurrent version expiration rule
@@ -553,11 +623,31 @@ class NCLifecycle {
553623
* @param {Object} bucket_json
554624
* @returns {Promise<Object[]>}
555625
*/
556-
async get_candidates_by_noncurrent_version_expiration_rule(lifecycle_rule, bucket_json) {
557-
// TODO - implement
558-
return [];
559-
}
626+
async get_candidates_by_noncurrent_version_expiration_rule(lifecycle_rule, bucket_json, object_sdk, {versions_list}) {
627+
const rule_state = this.lifecycle_run_status.buckets_statuses[bucket_json.name].rules_statuses[lifecycle_rule.id].state.noncurrent;
628+
if (rule_state.is_finished) return [];
629+
630+
if (!versions_list) {
631+
versions_list = await this.load_versions_list(object_sdk, bucket_json, rule_state);
632+
}
633+
634+
const filter_func = this._build_lifecycle_filter({filter: lifecycle_rule.filter, expiration: 0});
635+
const num_newer_versions = lifecycle_rule.noncurrent_version_expiration.newer_noncurrent_versions;
636+
const num_non_current_days = lifecycle_rule.noncurrent_version_expiration.noncurrent_days;
637+
const delete_candidates = [];
638+
639+
for (const entry of versions_list.objects) {
640+
const lifecycle_info = this._get_lifecycle_object_info_from_list_object_entry(entry);
641+
if ((num_newer_versions === undefined || this.filter_newer_versions(entry, rule_state, num_newer_versions)) &&
642+
(num_non_current_days === undefined || this.filter_noncurrent_days(entry, num_non_current_days))) {
643+
if (filter_func(lifecycle_info)) {
644+
delete_candidates.push({key: entry.key, version_id: entry.version_id});
645+
}
646+
}
647+
}
560648

649+
return delete_candidates;
650+
}
561651
////////////////////////////////////
562652
///////// ABORT MPU HELPERS ////////
563653
////////////////////////////////////
@@ -733,6 +823,11 @@ class NCLifecycle {
733823
this.init_bucket_status(bucket_name);
734824
}
735825
}
826+
if (op_times.end_time) {
827+
if (op_name === TIMED_OPS.PROCESS_RULE) {
828+
this.update_rule_status_is_finished(bucket_name, rule_id);
829+
}
830+
}
736831
this._update_times_on_status({ op_name, op_times, bucket_name, rule_id });
737832
this._update_error_on_status({ error, bucket_name, rule_id });
738833
if (bucket_name && rule_id) {
@@ -879,12 +974,23 @@ class NCLifecycle {
879974
*/
880975
init_rule_status(bucket_name, rule_id) {
881976
this.lifecycle_run_status.buckets_statuses[bucket_name].rules_statuses[rule_id] ??= {};
882-
this.lifecycle_run_status.buckets_statuses[bucket_name].rules_statuses[rule_id].state ??= {};
977+
this.lifecycle_run_status.buckets_statuses[bucket_name].rules_statuses[rule_id].state ??= {expire: {}, noncurrent: {}};
883978
this.lifecycle_run_status.buckets_statuses[bucket_name].rules_statuses[rule_id].rule_process_times = {};
884979
this.lifecycle_run_status.buckets_statuses[bucket_name].rules_statuses[rule_id].rule_stats = {};
885980
return this.lifecycle_run_status.buckets_statuses[bucket_name].rules_statuses[rule_id];
886981
}
887982

983+
/**
984+
* updates the rule state if all actions finished
985+
* @param {string} bucket_name
986+
* @param {string} rule_id
987+
*/
988+
update_rule_status_is_finished(bucket_name, rule_id) {
989+
const rule_state = this.lifecycle_run_status.buckets_statuses[bucket_name].rules_statuses[rule_id].state;
990+
rule_state.is_finished = (rule_state.expire.is_finished === undefined || rule_state.expire.is_finished === true) &&
991+
(rule_state.noncurrent.is_finished === undefined || rule_state.noncurrent.is_finished === true);
992+
}
993+
888994
/**
889995
*
890996
* @param {Object[]} buckets
@@ -908,7 +1014,7 @@ class NCLifecycle {
9081014
}
9091015
}
9101016
}
911-
}
1017+
}
9121018
}
9131019

9141020
//////////////////

0 commit comments

Comments
 (0)