diff --git a/.gitattributes b/.gitattributes index 5fa260b9c2caa97136c18806ea2c3f6693fe43e8..cb380abc268d3f217f96ec37412b0a275c66e339 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4717,10 +4717,12 @@ SAS/ResourceAssignment/ResourceAssignmentDatabase/radbpglistener.ini -text SAS/ResourceAssignment/ResourceAssignmentDatabase/radbpglistener.py -text SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/CMakeLists.txt -text SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/radb_common_testing.py -text -SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/radb_performance_test.py -text SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb.py -text SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb.run -text SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb.sh -text +SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_performance.py -text +SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_performance.run -text +SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_performance.sh -text SAS/ResourceAssignment/ResourceAssignmentEditor/CMakeLists.txt -text SAS/ResourceAssignment/ResourceAssignmentEditor/bin/CMakeLists.txt -text SAS/ResourceAssignment/ResourceAssignmentEditor/bin/raewebservice -text diff --git a/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/CMakeLists.txt b/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/CMakeLists.txt index 439c9ccb70041b11f720e5bdb0aaebdd9b4f2a6b..53b213e6335d06d5824dd7b31cc18867ceaa69b5 100644 --- a/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/CMakeLists.txt +++ b/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/CMakeLists.txt @@ -6,4 +6,5 @@ find_python_module(testing.postgresql) find_python_module(mock) lofar_add_test(t_radb) +lofar_add_test(t_radb_performance) diff --git a/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/radb_performance_test.py b/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_performance.py similarity index 66% rename from SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/radb_performance_test.py rename to SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_performance.py index 6deed79207f1fff7f89c2bd30f72393789f9046a..ac386e33fde51a926dd98d2f0155aa4d9e33b511 100755 --- a/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/radb_performance_test.py +++ b/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_performance.py @@ -48,6 +48,14 @@ class ResourceAssignmentDatabaseTest(radb_common_testing.RADBCommonTest): MAX_CAPACITY=1000 self.radb._executeQuery('update resource_monitoring.resource_capacity set (available, total) = (%s, %s);', (MAX_CAPACITY,MAX_CAPACITY)) + # pretend that we have an almost unlimited amount of storage space + self.radb._executeQuery('update resource_monitoring.resource_capacity set (available, total) = (%s, %s) ' \ + 'where resource_id in (select id from virtual_instrument.resource_view where type_name = \'storage\');', + (1e9*MAX_CAPACITY,1e9*MAX_CAPACITY)) + + # keep a list of storage-type resource(ids), so we can create long lasting claims for these. + storage_resource_ids = set(r['id'] for r in self.radb.getResources(resource_types='storage')) + now = datetime.utcnow() now -= timedelta(minutes=now.minute, seconds=now.second, microseconds=now.microsecond) # round to full hour spec_ids = [] @@ -55,7 +63,7 @@ class ResourceAssignmentDatabaseTest(radb_common_testing.RADBCommonTest): with open(filename, 'w') as file: file.write('#tasks, #claims, #claims_per_resource, #inserted_claims, elapsed_insert\n') counter = 0 - for repeat_nr in range(1): + for repeat_nr in range(10): # it is not common to claim a single resource multiple times for the same task, but it can happen, so test for it. for num_claims_per_resource in [1, 2, 5, 10, 20, 50]: # let's test over a feasible range of #claims. A lofar observation usually has ~200 claims. @@ -80,58 +88,83 @@ class ResourceAssignmentDatabaseTest(radb_common_testing.RADBCommonTest): claims = [{'resource_id': q/num_claims_per_resource, 'starttime': task['starttime'], - 'endtime': task['endtime'], #TODO: extend storage claims into the future + 'endtime': task['endtime'], 'status': 'tentative', 'claim_size': claim_factor*MAX_CAPACITY/num_claims_per_resource} for q in range(num_claims_to_insert)] + # extend claims on storage resources + for claim in claims: + if claim['resource_id'] in storage_resource_ids: + claim['endtime'] += timedelta(days=100) + start = datetime.utcnow() self.radb.insertResourceClaims(task_id, claims, 'foo', 1, 1) elapsed_insert = totalSeconds(datetime.utcnow() - start) num_tasks = self.radb._executeQuery('select count(id) from resource_allocation.task;', fetch=_FETCH_ONE)['count'] num_claims = self.radb._executeQuery('select count(id) from resource_allocation.resource_claim;', fetch=_FETCH_ONE)['count'] + has_storage_claims = len(self.radb.getResourceClaims(task_ids=task_id, resource_type='storage')) > 0 # enforce perfomance criterion: inserting claims should take less than ELAPSED_TRESHOLD sec self.assertLess(elapsed_insert, ELAPSED_TRESHOLD, msg="insertResourceClaims took longer than allowed. (%ssec > %ssec) num_tasks=%s num_claims=%s num_claims_to_insert=%s num_claims_per_resource=%s" %( elapsed_insert, ELAPSED_TRESHOLD, num_tasks, num_claims, num_claims_to_insert, num_claims_per_resource)) - if claim_factor == 1: - # no oversubscription, so expect all claims to be claimable... + if claim_factor == 2: + # (deliberate) oversubscription of resources + # so, expect the claims and task to be in conflict + self.assertGreater(len(self.radb.getResourceClaims(task_ids=task_id, status='conflict')), 0) + self.assertEqual('conflict', self.radb.getTask(task_id)['status']) + + # solve oversubscription start = datetime.utcnow() - self.radb.updateTaskAndResourceClaims(task_id=task_id, claim_status='claimed') + self.radb.updateResourceClaims(where_task_ids=task_id, claim_size=MAX_CAPACITY/num_claims_per_resource) elapsed_status_update = totalSeconds(datetime.utcnow() - start) - # are they indeed claimed? - self.assertEqual(num_claims_to_insert, len(self.radb.getResourceClaims(task_ids=task_id, status='claimed'))) - # enforce perfomance criterion: updating claims should take less than ELAPSED_TRESHOLD sec - self.assertLess(elapsed_status_update, ELAPSED_TRESHOLD, msg="updateTaskAndResourceClaims took longer than allowed. (%ssec > %ssec) num_tasks=%s num_claims=%s num_claims_to_insert=%s num_claims_per_resource=%s" % ( - elapsed_status_update, ELAPSED_TRESHOLD, num_tasks, num_claims, num_claims_to_insert, num_claims_per_resource)) - - # ... and proceed with cycling through the task status - for task_status in ['scheduled', 'queued', 'active', 'completing', 'finished']: - # update the task status - start = datetime.utcnow() - self.radb.updateTaskAndResourceClaims(task_id=task_id, task_status=task_status) - elapsed_status_update = totalSeconds(datetime.utcnow() - start) - - # check task status - self.assertEqual(task_status, self.radb.getTask(task_id)['status']) - - # enforce perfomance criterion: inserting claims should take less than ELAPSED_TRESHOLD sec - self.assertLess(elapsed_status_update, ELAPSED_TRESHOLD, msg="updateTaskAndResourceClaims took longer than allowed. (%ssec > %ssec) num_tasks=%s num_claims=%s num_claims_to_insert=%s num_claims_per_resource=%s task_status=%s" % ( - elapsed_status_update, ELAPSED_TRESHOLD, num_tasks, num_claims, num_claims_to_insert, num_claims_per_resource, task_status)) - - # task should now be finished - self.assertEqual('finished', self.radb.getTask(task_id)['status']) - # and all claims should be removed. - # self.assertEqual(0, len(self.radb.getResourceClaims(task_ids=task_id))) - else: - # (deliberate) oversubscription of resources - # so, expect the claims and task to be in conflict - self.assertEqual(num_claims_to_insert, len(self.radb.getResourceClaims(task_ids=task_id, status='conflict'))) - self.assertEqual('conflict', self.radb.getTask(task_id)['status']) + self.assertLess(elapsed_status_update, ELAPSED_TRESHOLD, + msg="updateResourceClaims took longer than allowed. (%ssec > %ssec) num_tasks=%s num_claims=%s num_claims_to_insert=%s num_claims_per_resource=%s" % ( + elapsed_status_update, ELAPSED_TRESHOLD, num_tasks, num_claims, num_claims_to_insert, num_claims_per_resource)) + + # check if not oversubscribed anymore + self.assertEqual(0, len(self.radb.getResourceClaims(task_ids=task_id, status='conflict'))) + self.assertEqual('approved', self.radb.getTask(task_id)['status']) + + # no oversubscription (anymore), so expect all claims to be claimable... + start = datetime.utcnow() + self.radb.updateTaskAndResourceClaims(task_id=task_id, claim_status='claimed') + elapsed_status_update = totalSeconds(datetime.utcnow() - start) + + # are they indeed claimed? + self.assertEqual(num_claims_to_insert, len(self.radb.getResourceClaims(task_ids=task_id, status='claimed'))) + + # enforce perfomance criterion: updating claims should take less than ELAPSED_TRESHOLD sec + self.assertLess(elapsed_status_update, ELAPSED_TRESHOLD, msg="updateTaskAndResourceClaims took longer than allowed. (%ssec > %ssec) num_tasks=%s num_claims=%s num_claims_to_insert=%s num_claims_per_resource=%s" % ( + elapsed_status_update, ELAPSED_TRESHOLD, num_tasks, num_claims, num_claims_to_insert, num_claims_per_resource)) + + # ... and proceed with cycling through the task status + for task_status in ['scheduled', 'queued', 'active', 'completing', 'finished']: + # update the task status + start = datetime.utcnow() + self.radb.updateTaskAndResourceClaims(task_id=task_id, task_status=task_status) + elapsed_status_update = totalSeconds(datetime.utcnow() - start) + + # check task status + self.assertEqual(task_status, self.radb.getTask(task_id)['status']) + + # enforce perfomance criterion: updating task status should take less than ELAPSED_TRESHOLD sec + self.assertLess(elapsed_status_update, ELAPSED_TRESHOLD, msg="updateTaskAndResourceClaims took longer than allowed. (%ssec > %ssec) num_tasks=%s num_claims=%s num_claims_to_insert=%s num_claims_per_resource=%s task_status=%s" % ( + elapsed_status_update, ELAPSED_TRESHOLD, num_tasks, num_claims, num_claims_to_insert, num_claims_per_resource, task_status)) + + # task should now be finished + self.assertEqual('finished', self.radb.getTask(task_id)['status']) + # and all non-long-lasting (storage) claims should be removed. + self.assertEqual(0, len(list(c for c in self.radb.getResourceClaims(task_ids=task_id) if c['endtime'] <= task['endtime']))) + + if has_storage_claims: + # and all long-lasting (storage) claims should still be there. + # (they are removed by the cleanupservice ending/removing the storage claims) + self.assertGreater(len(list(c for c in self.radb.getResourceClaims(task_ids=task_id) if c['endtime'] > task['endtime'])), 0) logger.info('TEST RESULT: radb now contains %d tasks, %d claims, insert of %d claims with %d claims per resource takes on average %.3fsec', num_tasks, num_claims, num_claims_to_insert, num_claims_per_resource, elapsed_insert) diff --git a/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_performance.run b/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_performance.run new file mode 100755 index 0000000000000000000000000000000000000000..ca855f9d9e93e0c79e069b1c00053666b66a80ce --- /dev/null +++ b/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_performance.run @@ -0,0 +1,5 @@ +#!/bin/bash + +# Run the unit test +source python-coverage.sh +python_coverage_test "ResourceAssignmentDatabase/*" t_radb_performance.py diff --git a/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_performance.sh b/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_performance.sh new file mode 100755 index 0000000000000000000000000000000000000000..a6bb3bf30765da05105acd8340ea52c6f1dbf0e5 --- /dev/null +++ b/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_performance.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +./runctest.sh t_radb_performance