Skip to content

Commit df3f396

Browse files
authored
Merge pull request #5954 from chaen/cherry-pick-2-16f27a4f6-integration
[sweep:integration] DFC allows to dump more than one SE at the time
2 parents 3a510bc + 759b8da commit df3f396

File tree

9 files changed

+79
-48
lines changed

9 files changed

+79
-48
lines changed

src/DIRAC/DataManagementSystem/DB/FileCatalogComponents/FileManager/FileManagerBase.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,12 +1333,12 @@ def setFileMode(self, path, mode):
13331333
"""
13341334
return self._setFileParameter(path, "Mode", mode)
13351335

1336-
def getSEDump(self, seName):
1336+
def getSEDump(self, seNames):
13371337
"""
13381338
Return all the files at a given SE, together with checksum and size
13391339
1340-
:param seName: name of the StorageElement
1340+
:param seName: list of storageElement names
13411341
1342-
:returns: S_OK with list of tuples (lfn, checksum, size)
1342+
:returns: S_OK with list of tuples (SEName, lfn, checksum, size)
13431343
"""
13441344
return S_ERROR("To be implemented on derived class")

src/DIRAC/DataManagementSystem/DB/FileCatalogComponents/FileManager/FileManagerPs.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -921,18 +921,23 @@ def _getFileLFNs(self, fileIDs):
921921

922922
return S_OK({"Successful": successful, "Failed": failed})
923923

924-
def getSEDump(self, seName):
924+
def getSEDump(self, seNames):
925925
"""
926926
Return all the files at a given SE, together with checksum and size
927927
928-
:param seName: name of the StorageElement
928+
:param seName: list of StorageElement names
929929
930-
:returns: S_OK with list of tuples (lfn, checksum, size)
930+
:returns: S_OK with list of tuples (SEName, lfn, checksum, size)
931931
"""
932932

933-
res = self.db.seManager.findSE(seName)
934-
if not res["OK"]:
935-
return res
936-
seID = res["Value"]
933+
seIDs = []
934+
935+
for seName in seNames:
936+
res = self.db.seManager.findSE(seName)
937+
if not res["OK"]:
938+
return res
939+
seIDs.append(res["Value"])
940+
941+
formatedSEIds = intListToString(seIDs)
937942

938-
return self.db.executeStoredProcedureWithCursor("ps_get_se_dump", (seID,))
943+
return self.db.executeStoredProcedureWithCursor("ps_get_se_dump", (formatedSEIds,))

src/DIRAC/DataManagementSystem/DB/FileCatalogDB.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,12 +1171,12 @@ def _checkPathPermissions(self, operation, lfns, credDict):
11711171
successful[lfn] = lfns[lfn]
11721172
return S_OK({"Successful": successful, "Failed": failed})
11731173

1174-
def getSEDump(self, seName):
1174+
def getSEDump(self, seNames):
11751175
"""
1176-
Return all the files at a given SE, together with checksum and size
1176+
Return all the files at given SEs, together with checksum and size
11771177
1178-
:param seName: name of the StorageElement
1178+
:param seName: list of StorageElement names
11791179
1180-
:returns: S_OK with list of tuples (lfn, checksum, size)
1180+
:returns: S_OK with list of tuples (SEName, lfn, checksum, size)
11811181
"""
1182-
return self.fileManager.getSEDump(seName)
1182+
return self.fileManager.getSEDump(seNames)

src/DIRAC/DataManagementSystem/DB/FileCatalogWithFkAndPsDB.sql

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1941,21 +1941,26 @@ DELIMITER ;
19411941

19421942

19431943

1944-
-- ps_get_se_dump : dump all the lfns in an SE, with checksum and size
1945-
-- se_id : storageElement's ID
1946-
-- output : LFN, Checksum, Size
1944+
-- ps_get_se_dump : dump all the lfns in list of SEs, with checksum and size
1945+
-- se_id : storageElement IDs
1946+
-- output : SEName, LFN, Checksum, Size
19471947

19481948
DROP PROCEDURE IF EXISTS ps_get_se_dump;
19491949
DELIMITER //
19501950
CREATE PROCEDURE ps_get_se_dump
1951-
(IN se_id INT)
1951+
(IN se_ids TEXT)
19521952
BEGIN
19531953

1954-
SELECT SQL_NO_CACHE CONCAT(d.Name, '/', f.FileName), f.Checksum, f.Size
1955-
FROM FC_Files f
1956-
JOIN FC_Replicas r on f.FileID = r.FileID
1957-
JOIN FC_DirectoryList d on d.DirID = f.DirID
1958-
WHERE SEID = se_id;
1954+
SET @sql = CONCAT('SELECT SEName, CONCAT(d.Name, "/", f.FileName), f.Checksum, f.Size
1955+
FROM FC_Files f
1956+
JOIN FC_Replicas r on f.FileID = r.FileID
1957+
JOIN FC_DirectoryList d on d.DirID = f.DirID
1958+
JOIN FC_StorageElements s on r.SEID = s.SEID
1959+
WHERE s.SEID IN (', se_ids, ')');
1960+
1961+
PREPARE stmt FROM @sql;
1962+
EXECUTE stmt;
1963+
DEALLOCATE PREPARE stmt;
19591964

19601965
END //
19611966
DELIMITER ;

src/DIRAC/DataManagementSystem/Service/FileCatalogHandler.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"""
55

66
import csv
7+
import json
78
import os
89
from io import StringIO
910

@@ -695,19 +696,19 @@ def export_getDatasetFiles(self, datasets):
695696
"""Get lfns in the given dataset"""
696697
return self.fileCatalogDB.datasetManager.getDatasetFiles(datasets, self.getRemoteCredentials())
697698

698-
def getSEDump(self, seName):
699+
def getSEDump(self, seNames):
699700
"""
700-
Return all the files at a given SE, together with checksum and size
701+
Return all the files at given SEs, together with checksum and size
701702
702-
:param seName: name of the StorageElement
703+
:param seNames: StorageElement names
703704
704-
:returns: S_OK with list of tuples (lfn, checksum, size)
705+
:returns: S_OK with list of tuples (SEName, lfn, checksum, size)
705706
"""
706-
return self.fileCatalogDB.getSEDump(seName)["Value"]
707+
return self.fileCatalogDB.getSEDump(seNames)
707708

708709

709710
class FileCatalogHandler(FileCatalogHandlerMixin, RequestHandler):
710-
def transfer_toClient(self, seName, token, fileHelper):
711+
def transfer_toClient(self, jsonSENames, token, fileHelper):
711712
"""This method used to transfer the SEDump to the client,
712713
formated as CSV with '|' separation
713714
@@ -718,9 +719,17 @@ def transfer_toClient(self, seName, token, fileHelper):
718719
719720
"""
720721

721-
retVal = self.getSEDump(seName)
722+
seNames = json.loads(jsonSENames)
723+
csvOutput = None
724+
res = self.getSEDump(seNames)
722725

723726
try:
727+
if not res["OK"]:
728+
ret = fileHelper.stringToNetwork(json.dumps(res))
729+
return ret
730+
731+
retVal = res["Value"]
732+
724733
csvOutput = StringIO()
725734
writer = csv.writer(csvOutput, delimiter="|")
726735
for lfn in retVal:
@@ -735,4 +744,5 @@ def transfer_toClient(self, seName, token, fileHelper):
735744
self.log.exception("Exception while sending seDump", repr(e))
736745
return S_ERROR("Exception while sending seDump: %s" % repr(e))
737746
finally:
738-
csvOutput.close()
747+
if csvOutput is not None:
748+
csvOutput.close()

src/DIRAC/DataManagementSystem/Service/TornadoFileCatalogHandler.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@
1010
1111
"""
1212
# imports
13+
import json
1314
import csv
1415

1516
from io import StringIO
1617

1718
# from DIRAC
1819

1920
from DIRAC import gLogger, S_ERROR
21+
from DIRAC.Core.Utilities.ReturnValues import returnValueOrRaise
2022
from DIRAC.DataManagementSystem.Service.FileCatalogHandler import FileCatalogHandlerMixin
2123

2224
from DIRAC.Core.Tornado.Server.TornadoService import TornadoService
@@ -35,20 +37,22 @@ class TornadoFileCatalogHandler(FileCatalogHandlerMixin, TornadoService):
3537
# This is needed because the mixin class uses `cls.log`
3638
log = sLog
3739

38-
def export_streamToClient(self, seName):
39-
"""This method used to transfer the SEDump to the client,
40+
def export_streamToClient(self, jsonSENames):
41+
"""This method is used to transfer the SEDump to the client,
4042
formated as CSV with '|' separation
4143
42-
:param seName: name of the se to dump
44+
:param jsonSENames: json formated names of the SEs to dump
4345
4446
:returns: the result of the FileHelper
4547
4648
4749
"""
48-
49-
retVal = self.getSEDump(seName)
50+
seNames = json.loads(jsonSENames)
51+
csvOutput = None
5052

5153
try:
54+
retVal = returnValueOrRaise(self.getSEDump(seNames))
55+
5256
csvOutput = StringIO()
5357
writer = csv.writer(csvOutput, delimiter="|")
5458
writer.writerows(retVal)
@@ -60,4 +64,5 @@ def export_streamToClient(self, seName):
6064
sLog.exception("Exception while sending seDump", repr(e))
6165
return S_ERROR("Exception while sendind seDump: %s" % repr(e))
6266
finally:
63-
csvOutput.close()
67+
if csvOutput is not None:
68+
csvOutput.close()

src/DIRAC/Resources/Catalog/FileCatalogClient.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
""" The FileCatalogClient is a class representing the client of the DIRAC File Catalog
22
"""
3+
import json
34
import os
45

56
from DIRAC import S_OK, S_ERROR
@@ -45,6 +46,7 @@ class FileCatalogClient(FileCatalogClientBase):
4546
"getDatasetParameters",
4647
"getDatasetFiles",
4748
"getDatasetAnnotation",
49+
"getSEDump",
4850
]
4951

5052
WRITE_METHODS = [
@@ -655,17 +657,21 @@ def getDatasetFiles(self, datasets, timeout=120):
655657

656658
#############################################################################
657659

658-
def getSEDump(self, seName, outputFilename):
660+
def getSEDump(self, seNames, outputFilename):
659661
"""
660-
Dump the content of an SE in the given file.
661-
The file contains a list of [lfn,checksum,size] dumped as csv,
662+
Dump the content of SEs in the given file.
663+
The file contains a list of [SEName, lfn,checksum,size] dumped as csv,
662664
separated by '|'
663665
664-
:param seName: name of the StorageElement
666+
:param seName: list of StorageElement names
665667
:param outputFilename: path to the file where to dump it
666668
667669
:returns: result from the TransferClient
668670
"""
671+
if isinstance(seNames, str):
672+
seNames = seNames.split(",")
669673

670-
dfc = TransferClient(self.serverURL)
671-
return dfc.receiveFile(outputFilename, seName)
674+
seNames = json.dumps(seNames)
675+
676+
dfc = TransferClient(self.serverURL, timeout=3600)
677+
return dfc.receiveFile(outputFilename, seNames)

tests/Integration/DataManagementSystem/Test_Client_DFC.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ def test_fileOperations(self):
339339

340340
with open(expectedDumpFn, "w") as expectedDumpFd:
341341
csvWriter = csv.writer(expectedDumpFd, delimiter="|")
342-
csvWriter.writerow([testFile, "0", 123])
342+
csvWriter.writerow(["testSE", testFile, "0", 123])
343343

344344
actualDumpFn = expectedDumpFn + "real"
345345
result = self.dfc.getSEDump("testSE", actualDumpFn)

tests/Integration/DataManagementSystem/Test_FileCatalogDB.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,10 +435,10 @@ def test_fileOperations(self):
435435

436436
# ADD SOMETHING ABOUT FILE ANCESTORS AND DESCENDENTS
437437

438-
result = self.db.getSEDump("testSE")
438+
result = self.db.getSEDump(["testSE"])
439439
self.assertTrue(result["OK"], "Error when getting SE dump %s" % result)
440440
self.assertEqual(
441-
result["Value"], ((testFile, "0", 123),), "Did not get the expected SE Dump %s" % result["Value"]
441+
result["Value"], (("testSE", testFile, "0", 123),), "Did not get the expected SE Dump %s" % result["Value"]
442442
)
443443

444444
result = self.db.removeFile([testFile, nonExistingFile], credDict)

0 commit comments

Comments
 (0)