Repository: rucio/rucio

Issue:
Reaper not processing all Epoch tombstone replicas when no space is needed
Motivation
----------
Reaper not processing all Epoch tombstone replicas when no space is needed





Discussion:
I always thought this is "by design". I think we even have tests ensuring this is the case. 
https://github.com/rucio/rucio/blob/9ae4c7cdaff12db9f69259314164cb41311e54ae/lib/rucio/tests/test_reaper.py#L93
The Epoch ones are "special". To flag a replica as "needs to be deleted right now" we just give them an epoch tombstone (Since we don't have a special flag for it otherwise) 

Resolving patch:
diff --git a/lib/rucio/core/replica.py b/lib/rucio/core/replica.py
--- a/lib/rucio/core/replica.py
+++ b/lib/rucio/core/replica.py
@@ -2715,7 +2715,7 @@ def list_and_mark_unlocked_replicas(limit, bytes_=None, rse_id=None, delay_secon
         )
 
         for scope, name, path, bytes_, tombstone, state, datatype in session.execute(stmt):
-            if len(rows) >= limit or (needed_space is not None and total_bytes > needed_space):
+            if len(rows) >= limit or (not only_delete_obsolete and needed_space is not None and total_bytes > needed_space):
                 break
             if state != ReplicaState.UNAVAILABLE:
                 total_bytes += bytes_
@@ -2723,7 +2723,7 @@ def list_and_mark_unlocked_replicas(limit, bytes_=None, rse_id=None, delay_secon
             rows.append({'scope': scope, 'name': name, 'path': path,
                          'bytes': bytes_, 'tombstone': tombstone,
                          'state': state, 'datatype': datatype})
-        if len(rows) >= limit or (needed_space is not None and total_bytes > needed_space):
+        if len(rows) >= limit or (not only_delete_obsolete and needed_space is not None and total_bytes > needed_space):
             break
 
     if rows:
@@ -2800,7 +2800,7 @@ def list_and_mark_unlocked_replicas_no_temp_table(limit, bytes_=None, rse_id=Non
             if tombstone != OBSOLETE and only_delete_obsolete:
                 break
 
-            if needed_space is not None and total_bytes > needed_space:
+            if not only_delete_obsolete and needed_space is not None and total_bytes > needed_space:
                 break
 
             if state != ReplicaState.UNAVAILABLE:
@@ -2827,7 +2827,7 @@ def list_and_mark_unlocked_replicas_no_temp_table(limit, bytes_=None, rse_id=Non
                 if tombstone != OBSOLETE and only_delete_obsolete:
                     break
 
-                if needed_space is not None and total_bytes > needed_space:
+                if not only_delete_obsolete and needed_space is not None and total_bytes > needed_space:
                     break
 
                 if state != ReplicaState.UNAVAILABLE:


Test patch:
diff --git a/lib/rucio/tests/test_reaper.py b/lib/rucio/tests/test_reaper.py
--- a/lib/rucio/tests/test_reaper.py
+++ b/lib/rucio/tests/test_reaper.py
@@ -428,7 +428,6 @@ def test_archive_of_deleted_dids(vo, did_factory, root_account, core_config_mock
     rse_core.set_rse_limits(rse_id=rse_id, name='MinFreeSpace', value=50 * file_size)
     assert len(list(replica_core.list_replicas(dids=dids, rse_expression=rse_name))) == nb_files
 
-    # Check first if the reaper does not delete anything if no space is needed
     reaper_cache_region.invalidate()
     rse_core.set_rse_usage(rse_id=rse_id, source='storage', used=nb_files * file_size, free=323000000000)
     reaper(once=True, rses=[], include_rses=rse_name, exclude_rses=None, greedy=True)