@@ -1513,53 +1513,61 @@ def setJobCommandStatus(self, jobID, command, status):
15131513 def fillJobsHistorySummary (self ):
15141514 """Fill the JobsHistorySummary table with the summary of the jobs in a final state"""
15151515
1516+ # Create the staging table
1517+ createStagingTable_sql = "CREATE TABLE IF NOT EXISTS JobsHistorySummary_staging LIKE JobsHistorySummary"
1518+ if not (result := self ._update (createStagingTable_sql ))["OK" ]:
1519+ return result
1520+
1521+ # Insert the data into the staging table
15161522 defString = "Status, Site, Owner, OwnerGroup, JobGroup, JobType, ApplicationStatus, MinorStatus"
15171523 valuesString = "COUNT(JobID), SUM(RescheduleCounter)"
15181524 final_states = "', '" .join (JobStatus .JOB_FINAL_STATES + JobStatus .JOB_REALLY_FINAL_STATES )
15191525 final_states = f"'{ final_states } '"
1520-
15211526 query = (
1522- f"INSERT INTO JobsHistorySummary SELECT { defString } , { valuesString } "
1527+ f"INSERT INTO JobsHistorySummary_staging SELECT { defString } , { valuesString } "
15231528 f"FROM Jobs WHERE Status IN ({ final_states } ) AND LastUpdateTime < UTC_DATE() "
15241529 f"GROUP BY { defString } "
15251530 )
1526- result = self ._update (query )
1527- if not result ["OK" ]:
1531+ if not (result := self ._update (query ))["OK" ]:
15281532 return result
1529- return S_OK (result ["Value" ])
1533+
1534+ # Atomic swap
1535+ sql = (
1536+ "RENAME TABLE JobsHistorySummary TO JobsHistorySummary_old,"
1537+ "JobsHistorySummary_staging TO JobsHistorySummary;"
1538+ "DROP TABLE JobsHistorySummary_old;"
1539+ )
1540+ return self ._update (sql )
15301541
15311542 def getSummarySnapshot (self , requestedFields = False ):
15321543 """Get the summary snapshot for a given combination"""
15331544 if not requestedFields :
15341545 requestedFields = ["Status" , "MinorStatus" , "Site" , "Owner" , "OwnerGroup" , "JobGroup" ]
1535- valueFields = ["COUNT(JobID)" , "SUM(RescheduleCounter)" ]
15361546 defString = ", " .join (requestedFields )
1537- valueString = ", " .join (valueFields )
15381547 final_states = "', '" .join (JobStatus .JOB_FINAL_STATES + JobStatus .JOB_REALLY_FINAL_STATES )
15391548 final_states = f"'{ final_states } '"
15401549
1541- query = f"SELECT { defString } , { valueString } FROM ("
1550+ query = f"SELECT { defString } , SUM(JobCount) AS JobCount, SUM(RescheduleSum) AS RescheduleSum FROM ("
15421551 # All jobs that are NOT in a final state
15431552 query += (
1544- f"SELECT { defString } , { valueString } , COUNT(JobID), SUM(RescheduleCounter) "
1553+ f"SELECT { defString } , COUNT(JobID) AS JobCount , SUM(RescheduleCounter) AS RescheduleSum "
15451554 f"FROM Jobs WHERE STATUS NOT IN ({ final_states } ) "
1546- f"GROUP BY { defString } , { valueString } "
1555+ f"GROUP BY { defString } "
15471556 )
15481557 query += "UNION ALL "
15491558 # Recent jobs only (today) that are in a final state
15501559 query += (
1551- f"SELECT { defString } , { valueString } , COUNT(JobID), SUM(RescheduleCounter) "
1560+ f"SELECT { defString } , COUNT(JobID) AS JobCount , SUM(RescheduleCounter) AS RescheduleSum "
15521561 f"FROM Jobs WHERE Status IN ({ final_states } ) AND LastUpdateTime >= UTC_DATE() "
1553- f"GROUP BY { defString } , { valueString } "
1562+ f"GROUP BY { defString } "
15541563 )
15551564 query += "UNION ALL "
15561565 # Cached history (of jobs in a final state)
1557- query += f"SELECT * FROM JobsHistorySummary) AS combined GROUP BY { defString } , { valueString } "
1566+ query += (
1567+ f"SELECT { defString } , JobCount, RescheduleSum FROM JobsHistorySummary) AS combined GROUP BY { defString } "
1568+ )
15581569
1559- result = self ._query (query )
1560- if not result ["OK" ]:
1561- return result
1562- return S_OK (((requestedFields + valueFields ), result ["Value" ]))
1570+ return self ._query (query )
15631571
15641572 def removeInfoFromHeartBeatLogging (self , status , delTime , maxLines ):
15651573 """Remove HeartBeatLoggingInfo from DB.
0 commit comments