Repository: rucio/rucio

Issue:
Make abacus collection replica more memory aware
Motivation
----------
Currently the abacus-collection-replica algorithm loads the entire table size to operate on. This should be limited.


Discussion:

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
@@ -2620,11 +2620,12 @@ def mark_unlocked_replicas(rse_id, bytes, session=None):
 
 
 @transactional_session
-def get_cleaned_updated_collection_replicas(total_workers, worker_number, session=None):
+def get_cleaned_updated_collection_replicas(total_workers, worker_number, limit=None, session=None):
     """
     Get update request for collection replicas.
     :param total_workers:      Number of total workers.
     :param worker_number:      id of the executing worker.
+    :param limit:              Maximum numberws to return.
     :param session:            Database session in use.
     :returns:                  List of update requests for collection replicas.
     """
@@ -2675,6 +2676,8 @@ def get_cleaned_updated_collection_replicas(total_workers, worker_number, sessio
                                                                                  models.CollectionReplica.rse_id == models.UpdatedCollectionReplica.rse_id))).delete(synchronize_session=False)
 
     query = session.query(models.UpdatedCollectionReplica)
+    if limit:
+        query = query.limit(limit)
     return [update_request.to_dict() for update_request in query.all()]
 
 
diff --git a/lib/rucio/daemons/abacus/collection_replica.py b/lib/rucio/daemons/abacus/collection_replica.py
--- a/lib/rucio/daemons/abacus/collection_replica.py
+++ b/lib/rucio/daemons/abacus/collection_replica.py
@@ -17,6 +17,7 @@
 # - Hannes Hansen <hannes.jakob.hansen@cern.ch>, 2018-2019
 # - Thomas Beermann <thomas.beermann@cern.ch>, 2020
 # - Benedikt Ziemons <benedikt.ziemons@cern.ch>, 2020
+# - Martin Barisits <martin.barisits@cern.ch>, 2020
 
 """
 Abacus-Collection-Replica is a daemon to update collection replica.
@@ -46,7 +47,7 @@
                     format='%(asctime)s\t%(process)d\t%(levelname)s\t%(message)s')
 
 
-def collection_replica_update(once=False):
+def collection_replica_update(once=False, limit=1000):
     """
     Main loop to check and update the collection replicas.
     """
@@ -70,7 +71,8 @@ def collection_replica_update(once=False):
             # Select a bunch of collection replicas for to update for this worker
             start = time.time()  # NOQA
             replicas = get_cleaned_updated_collection_replicas(total_workers=heartbeat['nr_threads'] - 1,
-                                                               worker_number=heartbeat['assign_thread'])
+                                                               worker_number=heartbeat['assign_thread'],
+                                                               limit=limit)
 
             logging.debug('Index query time %f size=%d' % (time.time() - start, len(replicas)))
             # If the list is empty, sent the worker to sleep
@@ -84,6 +86,9 @@ def collection_replica_update(once=False):
                     start_time = time.time()
                     update_collection_replica(replica)
                     logging.debug('collection_replica_update[%s/%s]: update of collection replica "%s" took %f' % (heartbeat['assign_thread'], heartbeat['nr_threads'] - 1, replica['id'], time.time() - start_time))
+                if limit and len(replicas) < limit and not once:
+                    time.sleep(10)
+
         except Exception:
             logging.error(traceback.format_exc())
         if once:


Test patch: