diff --git a/castor/db/oracleCommon.schema.sql b/castor/db/oracleCommon.schema.sql index 9203825711be084f19c123492b6f1389f07e91ae..c8b2aa2bb3f79242d497ac9290f8a99842c735e8 100644 --- a/castor/db/oracleCommon.schema.sql +++ b/castor/db/oracleCommon.schema.sql @@ -399,11 +399,12 @@ CREATE GLOBAL TEMPORARY TABLE FilesToMigrateHelper fileTransactionId NUMBER, fileSize NUMBER, fSeq INTEGER) ON COMMIT DELETE ROWS; -CREATE GLOBAL TEMPORARY TABLE FileMigrationResultsHelper - (reqId VARCHAR2(36) CONSTRAINT PK_SetSegsHelper_ReqId PRIMARY KEY, - fileId NUMBER, lastModTime NUMBER, copyNo NUMBER, oldCopyNo NUMBER, transfSize NUMBER, - comprSize NUMBER, vid VARCHAR2(6), fSeq NUMBER, blockId RAW(4), checksumType VARCHAR2(16), checksum NUMBER) - ON COMMIT DELETE ROWS; +/* The following would be a temporary table, except that as it is used through a distributed + transaction and Oracle does not support temporary tables in such context, it is defined as + a normal table. See ns_setOrReplaceSegments for more details */ +CREATE TABLE FileMigrationResultsHelper + (reqId VARCHAR2(36), fileId NUMBER, lastModTime NUMBER, copyNo NUMBER, oldCopyNo NUMBER, transfSize NUMBER, + comprSize NUMBER, vid VARCHAR2(6), fSeq NUMBER, blockId RAW(4), checksumType VARCHAR2(16), checksum NUMBER); /* Indexes related to most used entities */ diff --git a/castor/db/oracleCommon.sql b/castor/db/oracleCommon.sql index 66ea38618ca33a3bb7b2add43c0354e0e2b19e24..d176f61c237875772ed4d45e1be09f36493353a2 100644 --- a/castor/db/oracleCommon.sql +++ b/castor/db/oracleCommon.sql @@ -34,7 +34,7 @@ END; /* Returns a time interval in seconds */ CREATE OR REPLACE FUNCTION getSecs(startTime IN TIMESTAMP, endTime IN TIMESTAMP) RETURN NUMBER IS BEGIN - RETURN EXTRACT(SECOND FROM (endTime - startTime)); + RETURN TRUNC(EXTRACT(SECOND FROM (endTime - startTime)), 6); END; / @@ -352,6 +352,7 @@ BEGIN END; / +/* A wrapper to run DB jobs and catch+log any exception they may throw */ CREATE OR REPLACE PROCEDURE startDbJob(jobCode VARCHAR2, source VARCHAR2) AS BEGIN EXECUTE IMMEDIATE jobCode; diff --git a/castor/db/oracleTapeGateway.sql b/castor/db/oracleTapeGateway.sql index 60ee71644ba7f6d6d9137b6a20c490eb267f9679..4de48414ca359f0f0ff9162ea11c21ba45514105 100644 --- a/castor/db/oracleTapeGateway.sql +++ b/castor/db/oracleTapeGateway.sql @@ -595,7 +595,6 @@ END; /* Attempt to retry a migration. Fail it in case it should not be retried anymore */ CREATE OR REPLACE PROCEDURE retryOrFailMigration(inMountTrId IN NUMBER, inFileId IN VARCHAR2, inNsHost IN VARCHAR2, inErrorCode IN NUMBER, inReqId IN VARCHAR2) AS - PRAGMA AUTONOMOUS_TRANSACTION; -- See tg_setBulkFileMigrationResult() varFileTrId NUMBER; BEGIN -- For the time being, we ignore the error code and apply the same policy to any @@ -619,7 +618,6 @@ BEGIN failFileMigration(inMountTrId, inFileId, inErrorCode, inReqId); -- ELSE we have one more retry, which has been logged upstream END IF; - COMMIT; END; / @@ -682,8 +680,7 @@ END; / /* delete MigrationMount */ -CREATE OR REPLACE -PROCEDURE tg_deleteMigrationMount(inMountId IN NUMBER) AS +CREATE OR REPLACE PROCEDURE tg_deleteMigrationMount(inMountId IN NUMBER) AS BEGIN DELETE FROM MigrationMount WHERE id=inMountId; END; @@ -765,16 +762,14 @@ END; / /* flag tape as full for a given session */ -CREATE OR REPLACE -PROCEDURE tg_flagTapeFull (inMountTransactionId IN NUMBER) AS +CREATE OR REPLACE PROCEDURE tg_flagTapeFull (inMountTransactionId IN NUMBER) AS BEGIN UPDATE MigrationMount SET full = 1 WHERE mountTransactionId = inMountTransactionId; END; / /* Find the VID of the tape used in a tape session */ -CREATE OR REPLACE -PROCEDURE tg_getMigrationMountVid ( +CREATE OR REPLACE PROCEDURE tg_getMigrationMountVid ( inMountTransactionId IN NUMBER, outVid OUT NOCOPY VARCHAR2, outTapePool OUT NOCOPY VARCHAR2) AS @@ -789,6 +784,7 @@ BEGIN END; / + /* insert new Migration Mount */ CREATE OR REPLACE PROCEDURE insertMigrationMount(inTapePoolId IN NUMBER, outMountId OUT INTEGER) AS @@ -828,7 +824,8 @@ EXCEPTION WHEN NO_DATA_FOUND THEN END; / -/* resurrect tapes */ + +/* DB job to start new migration mounts */ CREATE OR REPLACE PROCEDURE startMigrationMounts AS varNbPreExistingMounts INTEGER; varTotalNbMounts INTEGER := 0; @@ -923,7 +920,7 @@ BEGIN END; / -/* startRecallMounts */ +/* DB job to start new recall mounts */ CREATE OR REPLACE PROCEDURE startRecallMounts AS varNbMounts INTEGER; varNbExtraMounts INTEGER := 0; @@ -1081,6 +1078,38 @@ BEGIN END; / +/* Wrapper procedure for the setOrReplaceSegmentsForFiles call in the NS DB. Because we can't, + * pass arrays, and temporary tables are forbidden with distributed transactions, we use standard + * tables on the Stager DB (while the NS table is still temporary) to pass the data + * and we wrap everything in an autonomous transaction to isolate the caller. + */ +CREATE OR REPLACE PROCEDURE ns_setOrReplaceSegments(inReqId IN VARCHAR2, + outNSTimeInfos OUT "numList", + outNSErrorCodes OUT "numList", + outNSMsgs OUT strListTable, + outNSFileIds OUT "numList", + outNSParams OUT strListTable) AS +PRAGMA AUTONOMOUS_TRANSACTION; +BEGIN + -- "Bulk" transfer data to the NS DB + INSERT /*+ APPEND */ INTO SetSegmentsForFilesHelper@RemoteNS + SELECT * FROM FileMigrationResultsHelper + WHERE reqId = inReqId; + DELETE FROM FileMigrationResultsHelper + WHERE reqId = inReqId; + -- This call autocommits all segments in the NameServer + setOrReplaceSegmentsForFiles@RemoteNS(inReqId); + -- Retrieve results from the NS DB in bulk and clean data + SELECT timeinfo, ec, msg, fileId, params + BULK COLLECT INTO outNSTimeInfos, outNSErrorCodes, outNSMsgs, outNSFileIds, outNSParams + FROM ResultsLogHelper@RemoteNS + WHERE reqId = inReqId; + DELETE FROM ResultsLogHelper@RemoteNS + WHERE reqId = inReqId; + -- this commits the remote transaction + COMMIT; +END; +/ /* Commit a set of succeeded/failed migration processes to the NS and stager db. * Locks are taken on the involved castorfiles one by one, then to the dependent entities. @@ -1142,7 +1171,8 @@ BEGIN strtoRaw4(inBlockIds(i)), inChecksumTypes(i), inChecksums(i)); EXCEPTION WHEN NO_DATA_FOUND THEN -- Log 'unable to identify migration, giving up' - varParams := 'mountTransactionId='|| to_char(inMountTrId) ||' '|| inLogContext; + varParams := 'mountTransactionId='|| to_char(inMountTrId) ||' fileTransactionId='|| to_char(inFileTrIds(i)) + ||' '|| inLogContext; logToDLF(varReqid, dlf.LVL_ERROR, dlf.MIGRATION_NOT_FOUND, inFileIds(i), varNsHost, 'tapegatewayd', varParams); END; ELSE @@ -1151,25 +1181,15 @@ BEGIN ||' ErrorMessage="'|| inErrorMsgs(i) ||'" VID='|| varVid ||' copyNb='|| to_char(varCopyNo) ||' '|| inLogContext; logToDLF(varReqid, dlf.LVL_WARNING, dlf.MIGRATION_RETRY, inFileIds(i), varNsHost, 'tapegatewayd', varParams); - -- The following call commits in an autonomous transaction! retryOrFailMigration(inMountTrId, inFileIds(i), varNsHost, inErrorCodes(i), varReqId); + COMMIT; END IF; END LOOP; + -- Commit all the entries in FileMigrationResultsHelper so that the next call can take them + COMMIT; - -- "Bulk" transfer data to the NS DB (FORALL is not supported here) - INSERT INTO SetSegmentsForFilesHelper@RemoteNS - SELECT * FROM FileMigrationResultsHelper; - - -- This call autocommits all segments in the NameServer - setOrReplaceSegmentsForFiles@RemoteNS(varReqId); - - -- Retrieve results from the NS DB in bulk and clean result data - SELECT timeinfo, ec, msg, fileId, params - BULK COLLECT INTO varNSTimeInfos, varNSErrorCodes, varNSMsgs, varNSFileIds, varNSParams - FROM ResultsLogHelper@RemoteNS - WHERE reqId = varReqId; - DELETE FROM ResultsLogHelper@RemoteNS - WHERE reqId = varReqId; + -- The following procedure wraps the remote calls in an autonomous transaction + ns_setOrReplaceSegments(varReqId, varNSTimeInfos, varNSErrorCodes, varNSMsgs, varNSFileIds, varNSParams); -- Process the results FOR i IN varNSFileIds.FIRST .. varNSFileIds.LAST LOOP @@ -1179,7 +1199,8 @@ BEGIN CASE varNSErrorCodes(i) WHEN 0 THEN dlf.LVL_SYSTEM ELSE dlf.LVL_ERROR END, varNSMsgs(i), varNSFileIds(i), varNsHost, 'nsd', varNSParams(i)); - -- Now process file by file, depending on the result + -- Now process file by file, depending on the result. Skip pure log entries with fileId = 0. + IF varNSFileIds(i) = 0 THEN CONTINUE; END IF; CASE WHEN varNSErrorCodes(i) = 0 THEN -- All right, commit the migration in the stager diff --git a/ns/oracleTrailer.sql b/ns/oracleTrailer.sql index e5568d66b37ed6cadfdf36065984251b12ad4c9f..2c7eccf83bd3c8671118068a068505f6c29399ae 100644 --- a/ns/oracleTrailer.sql +++ b/ns/oracleTrailer.sql @@ -507,18 +507,22 @@ BEGIN END IF; varCount := varCount + 1; END LOOP; - -- Final logging - varParams := 'Function="setOrRepackSegmentsForFiles" NbFiles='|| varCount - ||' ElapsedTime='|| getSecs(varStartTime, SYSTIMESTAMP) - ||' AvgProcessingTime='|| getSecs(varStartTime, SYSTIMESTAMP)/varCount; - tmpDlfLog(inReqId, 0, 'Bulk processing complete', 0, varParams); + IF varCount > 0 THEN + -- Final logging + varParams := 'Function="setOrRepackSegmentsForFiles" NbFiles='|| varCount + ||' ElapsedTime='|| getSecs(varStartTime, SYSTIMESTAMP) + ||' AvgProcessingTime='|| getSecs(varStartTime, SYSTIMESTAMP)/varCount; + tmpDlfLog(inReqId, 0, 'Bulk processing complete', 0, varParams); + END IF; -- Clean input data DELETE FROM SetSegmentsForFilesHelper WHERE reqId = inReqId; COMMIT; - -- Return logs to the stager. Unfortunately we can't OPEN CURSOR FOR ... + -- Return results and logs to the stager. Unfortunately we can't OPEN CURSOR FOR ... -- because we would get ORA-24338: 'statement handle not executed' at run time. - -- So the stager will remotely open the ResultsLogHelper table. + -- Moreover, temporary tables are not supported with distributed transactions, + -- so the stager will remotely open the ResultsLogHelper table, and we clean + -- the tables by hand using the reqId key. END; / diff --git a/upgrades/cns_2.1.12-4_to_2.1.13-0.sql b/upgrades/cns_2.1.12-4_to_2.1.13-0.sql index e31ee1c33aef4cf3ed65fe062177773095190264..5b498c127108e9d169cd9d3bba997197c9622782 100644 --- a/upgrades/cns_2.1.12-4_to_2.1.13-0.sql +++ b/upgrades/cns_2.1.12-4_to_2.1.13-0.sql @@ -58,11 +58,29 @@ COMMIT; /* Schema changes go here */ /**************************/ +-- Temporary tables to store intermediate data to be passed from/to the stager. +-- We keep the data on commit and truncate it explicitly afterwards as we +-- want to use it over multiple commits (e.g. on bulk multi-file operations). +CREATE GLOBAL TEMPORARY TABLE SetSegmentsForFilesHelper + (reqId VARCHAR2(36), + fileId NUMBER, lastModTime NUMBER, copyNo NUMBER, oldCopyNo NUMBER, transfSize NUMBER, + comprSize NUMBER, vid VARCHAR2(6), fseq NUMBER, blockId RAW(4), checksumType VARCHAR2(16), checksum NUMBER) + ON COMMIT PRESERVE ROWS; + +CREATE INDEX I_SetSegsHelper_ReqId ON SetSegmentsForFilesHelper(reqId); + +CREATE GLOBAL TEMPORARY TABLE ResultsLogHelper + (reqId VARCHAR2(36), + timeinfo NUMBER, ec INTEGER, fileId NUMBER, msg VARCHAR2(2048), params VARCHAR2(4000)) + ON COMMIT PRESERVE ROWS; + +CREATE INDEX I_ResultsLogHelper_ReqId ON ResultsLogHelper(reqId); + + /* Package holding type declarations for the NameServer PL/SQL API */ CREATE OR REPLACE PACKAGE castorns AS TYPE cnumList IS TABLE OF INTEGER INDEX BY BINARY_INTEGER; - TYPE Log_Cur IS REF CURSOR RETURN ResultsLogHelper%ROWTYPE; TYPE Segment_Rec IS RECORD ( fileId NUMBER, lastModTime NUMBER, @@ -72,11 +90,10 @@ CREATE OR REPLACE PACKAGE castorns AS vid VARCHAR2(6), fseq INTEGER, blockId RAW(4), - checksum_name VARCHAR2(2), + checksum_name VARCHAR2(16), checksum INTEGER ); TYPE Segment_Cur IS REF CURSOR RETURN Segment_Rec; - TYPE SegmentList IS TABLE OF Segment_Rec; END castorns; / @@ -87,22 +104,10 @@ CREATE OR REPLACE TYPE numList IS TABLE OF INTEGER; / /** - * Package containing the definition of all DLF levels and messages for the SQL-to-DLF API. - * The actual logging is performed by the stagers, the NS PL/SQL code pushes logs to the callers. + * Package containing the definition of some relevant (s)errno values and messages. + * The actual logging is performed by the stagers. */ -CREATE OR REPLACE PACKAGE dlf AS - /* message levels */ - LVL_EMERGENCY CONSTANT PLS_INTEGER := 0; /* LOG_EMERG System is unusable */ - LVL_ALERT CONSTANT PLS_INTEGER := 1; /* LOG_ALERT Action must be taken immediately */ - LVL_CRIT CONSTANT PLS_INTEGER := 2; /* LOG_CRIT Critical conditions */ - LVL_ERROR CONSTANT PLS_INTEGER := 3; /* LOG_ERR Error conditions */ - LVL_WARNING CONSTANT PLS_INTEGER := 4; /* LOG_WARNING Warning conditions */ - LVL_USER_ERROR CONSTANT PLS_INTEGER := 5; /* LOG_NOTICE Normal but significant condition */ - LVL_AUTH CONSTANT PLS_INTEGER := 5; /* LOG_NOTICE Normal but significant condition */ - LVL_SECURITY CONSTANT PLS_INTEGER := 5; /* LOG_NOTICE Normal but significant condition */ - LVL_SYSTEM CONSTANT PLS_INTEGER := 6; /* LOG_INFO Informational */ - LVL_DEBUG CONSTANT PLS_INTEGER := 7; /* LOG_DEBUG Debug-level messages */ - +CREATE OR REPLACE PACKAGE serrno AS /* (s)errno values */ ENOENT CONSTANT PLS_INTEGER := 2; /* No such file or directory */ EACCES CONSTANT PLS_INTEGER := 13; /* Permission denied */ @@ -113,9 +118,9 @@ CREATE OR REPLACE PACKAGE dlf AS SECHECKSUM CONSTANT PLS_INTEGER := 1037; /* Bad checksum */ ENSFILECHG CONSTANT PLS_INTEGER := 1402; /* File has been overwritten, request ignored */ ENSNOSEG CONSTANT PLS_INTEGER := 1403; /* Segment had been deleted */ - ENSISLINK CONSTANT PLS_INTEGER := 1404; /* Is a symbolic link */ ENSTOOMANYSEGS CONSTANT PLS_INTEGER := 1406; /* Too many copies on tape */ ENSOVERWHENREP CONSTANT PLS_INTEGER := 1407; /* Cannot overwrite valid segment when replacing */ + ERTWRONGSIZE CONSTANT PLS_INTEGER := 1613; /* (Recalled) file size incorrect */ /* messages */ ENOENT_MSG CONSTANT VARCHAR2(2048) := 'No such file or directory'; @@ -123,13 +128,13 @@ CREATE OR REPLACE PACKAGE dlf AS EEXIST_MSG CONSTANT VARCHAR2(2048) := 'File exists'; EISDIR_MSG CONSTANT VARCHAR2(2048) := 'Is a directory'; SEINTERNAL_MSG CONSTANT VARCHAR2(2048) := 'Internal error'; - SECHECKSUM_MSG CONSTANT VARCHAR2(2048) := 'Checksum mismatch between segment and file'; + SECHECKSUM_MSG CONSTANT VARCHAR2(2048) := 'Checksum mismatch between file and segment'; ENSFILECHG_MSG CONSTANT VARCHAR2(2048) := 'File has been overwritten, request ignored'; ENSNOSEG_MSG CONSTANT VARCHAR2(2048) := 'Segment had been deleted'; ENSTOOMANYSEGS_MSG CONSTANT VARCHAR2(2048) := 'Too many copies on tape'; - ENSISLINK_MSG CONSTANT VARCHAR2(2048) := 'Is a symbolic link'; ENSOVERWHENREP_MSG CONSTANT VARCHAR2(2048) := 'Cannot overwrite valid segment when replacing'; -END dlf; + ERTWRONGSIZE_MSG CONSTANT VARCHAR2(2048) := 'Incorrect file size'; +END serrno; / @@ -176,20 +181,20 @@ END; / /* A small procedure to add a line to the temporary DLF log */ -CREATE OR REPLACE PROCEDURE tmpDlfLog(inLvl IN INTEGER, inReqid IN VARCHAR2, inMsg IN VARCHAR2, +CREATE OR REPLACE PROCEDURE tmpDlfLog(inReqId IN VARCHAR2, inEC IN INTEGER, inMsg IN VARCHAR2, inFileId IN NUMBER, inParams IN VARCHAR2) AS BEGIN - INSERT INTO ResultsLogHelper (timeinfo, lvl, reqid, msg, fileId, params) - VALUES (getTime(), inLvl, inReqid, inMsg, inFileId, inParams); + INSERT INTO ResultsLogHelper (reqId, timeinfo, ec, msg, fileId, params) + VALUES (inReqId, getTime(), inEC, inMsg, inFileId, inParams); END; / /* A function to extract the full path of a file in one go */ -CREATE OR REPLACE FUNCTION getPathForFileid(fid IN NUMBER) RETURN VARCHAR2 IS +CREATE OR REPLACE FUNCTION getPathForFileid(varFid IN NUMBER) RETURN VARCHAR2 IS CURSOR c IS SELECT /*+ NO_CONNECT_BY_COST_BASED */ name FROM cns_file_metadata - START WITH fileid = fid + START WITH fileid = varFid CONNECT BY fileid = PRIOR parent_fileid ORDER BY level DESC; p VARCHAR2(2048) := ''; @@ -211,23 +216,25 @@ END; * This procedure creates a segment for a given file. * Return code: * 0 in case of success - * ENOENT if the file does not exist (e.g. it had been dropped). + * ENOENT if the file does not exist (e.g. it has been dropped meanwhile). * EISDIR if the file is a directory. * EEXIST if the file already has a valid segment on the same tape. * ENSFILECHG if the file has been modified meanwhile. * SEINTERNAL if another segment exists on the given tape at the given fseq location. * ENSTOOMANYSEGS if this copy exceeds the number of copies allowed by the file's fileclass. - * This also applies if a segment is attached to a file which fileclass allows 0 copies. + * This also applies if inSegEntry refers to a file which fileclass allows 0 copies. */ -CREATE OR REPLACE PROCEDURE setSegmentForFile(segEntry IN castorns.Segment_Rec, +CREATE OR REPLACE PROCEDURE setSegmentForFile(inSegEntry IN castorns.Segment_Rec, + inReqId IN VARCHAR2, rc OUT INTEGER, msg OUT NOCOPY VARCHAR2) AS - fid NUMBER; - fmode NUMBER(6); - fLastMTime NUMBER; - fClassId NUMBER; - fcNbCopies NUMBER; - fCkSumName VARCHAR2(2); - fCkSum VARCHAR2(32); + varFid NUMBER; + varFmode NUMBER(6); + varFLastMTime NUMBER; + varFSize NUMBER; + varFClassId NUMBER; + varFCNbCopies NUMBER; + varFCksumName VARCHAR2(2); + varFCksum VARCHAR2(32); varNb INTEGER; varBlockId VARCHAR2(8); varParams VARCHAR2(2048); @@ -238,31 +245,39 @@ BEGIN rc := 0; msg := ''; -- Get file data and lock the entry, exit if not found - SELECT fileId, filemode, mtime, fileClass, csumType, csumValue - INTO fid, fmode, fLastMTime, fClassId, fCkSumName, fCkSum + SELECT fileId, filemode, mtime, fileClass, fileSize, csumType, csumValue + INTO varFid, varFmode, varFLastMTime, varFClassId, varFSize, varFCksumName, varFCksum FROM Cns_file_metadata - WHERE fileId = segEntry.fileId FOR UPDATE; + WHERE fileId = inSegEntry.fileId FOR UPDATE; -- Is it a directory? - IF bitand(fmode, 4*8*8*8*8) > 0 THEN -- 040000 == S_IFDIR - rc := dlf.EISDIR; - msg := dlf.EISDIR_MSG; + IF bitand(varFmode, 4*8*8*8*8) > 0 THEN -- 040000 == S_IFDIR + rc := serrno.EISDIR; + msg := serrno.EISDIR_MSG; ROLLBACK; RETURN; END IF; -- Has the file been changed meanwhile? - IF fLastMTime > segEntry.lastModTime AND segEntry.lastModTime > 0 THEN - rc := dlf.ENSFILECHG; - msg := dlf.ENSFILECHG_MSG; + IF varFLastMTime > inSegEntry.lastModTime AND inSegEntry.lastModTime > 0 THEN + rc := serrno.ENSFILECHG; + msg := serrno.ENSFILECHG_MSG; ROLLBACK; RETURN; END IF; -- Cross check file and segment checksums when adler32 (AD in the file entry): -- unfortunately we have to play with different representations... - IF fCkSumName = 'AD' AND segEntry.checksum_name = 'adler32' AND - segEntry.checksum != to_number(fCkSum, 'XXXXXXXX') THEN - rc := dlf.SECHECKSUM; - msg := dlf.SECHECKSUM_MSG || ' : ' - || to_char(segEntry.checksum, 'XXXXXXXX') || ' vs ' || fCkSum; + IF varFCksumName = 'AD' AND inSegEntry.checksum_name = 'adler32' AND + inSegEntry.checksum != to_number(varFCksum, 'XXXXXXXX') THEN + rc := serrno.SECHECKSUM; + msg := serrno.SECHECKSUM_MSG ||' : ' + || varFCksum ||' vs '|| to_char(inSegEntry.checksum, 'XXXXXXXX'); + ROLLBACK; + RETURN; + END IF; + -- Cross check segment (transfered) size and file size + IF varFSize != inSegEntry.segSize THEN + rc := serrno.ERTWRONGSIZE; + msg := serrno.ERTWRONGSIZE ||' : expected ' + || to_char(varFSize) ||', got '|| to_char(inSegEntry.segSize); ROLLBACK; RETURN; END IF; @@ -270,9 +285,9 @@ BEGIN -- on a tape that already holds a valid copy SELECT count(*) INTO varNb FROM Cns_seg_metadata - WHERE s_fileid = fid AND s_status = '-' AND vid = segEntry.vid; + WHERE s_fileid = varFid AND s_status = '-' AND vid = inSegEntry.vid; IF varNb > 0 THEN - rc := dlf.EEXIST; + rc := serrno.EEXIST; msg := 'File already has a copy on the tape'; ROLLBACK; RETURN; @@ -283,89 +298,56 @@ BEGIN BEGIN INSERT INTO Cns_seg_metadata (s_fileId, copyNo, fsec, segSize, s_status, vid, fseq, blockId, compression, side, checksum_name, checksum) - VALUES (fid, segEntry.copyNo, 1, segEntry.segSize, '-', - segEntry.vid, segEntry.fseq, segEntry.blockId, trunc(segEntry.segSize*100/segEntry.comprSize), - 0, segEntry.checksum_name, segEntry.checksum); + VALUES (varFid, inSegEntry.copyNo, 1, inSegEntry.segSize, '-', + inSegEntry.vid, inSegEntry.fseq, inSegEntry.blockId, trunc(inSegEntry.segSize*100/inSegEntry.comprSize), + 0, inSegEntry.checksum_name, inSegEntry.checksum); EXCEPTION WHEN CONSTRAINT_VIOLATED THEN -- We assume the PK was violated, i.e. a previous segment already exists and we need to update it. -- XXX This won't happen anymore once we will drop previous versions of the segments at -- XXX file creation/truncation time! UPDATE Cns_seg_metadata - SET fsec = 1, segSize = segEntry.segSize, s_status = '-', - vid = segEntry.vid, fseq = segEntry.fseq, blockId = segEntry.blockId, - compression = trunc(segEntry.segSize*100/segEntry.comprSize), - side = 0, checksum_name = segEntry.checksum_name, - checksum = segEntry.checksum - WHERE s_fileId = fid - AND copyNo = segEntry.copyNo; + SET fsec = 1, segSize = inSegEntry.segSize, s_status = '-', + vid = inSegEntry.vid, fseq = inSegEntry.fseq, blockId = inSegEntry.blockId, + compression = trunc(inSegEntry.segSize*100/inSegEntry.comprSize), + side = 0, checksum_name = inSegEntry.checksum_name, + checksum = inSegEntry.checksum + WHERE s_fileId = varFid + AND copyNo = inSegEntry.copyNo; IF SQL%ROWCOUNT = 0 THEN -- The update failed, thus the CONSTRAINT_VIOLATED was due to an existing segment at that fseq position. -- This is forbidden! - rc := dlf.SEINTERNAL; - msg := 'A file already exists at fseq '|| segEntry.fseq ||' on VID '|| segEntry.vid; + rc := serrno.SEINTERNAL; + msg := 'A file already exists at fseq '|| inSegEntry.fseq ||' on VID '|| inSegEntry.vid; ROLLBACK; RETURN; END IF; END; -- Finally check for too many segments for this file - SELECT nbCopies INTO fcNbCopies + SELECT nbCopies INTO varFCNbCopies FROM Cns_class_metadata - WHERE classid = fClassId; + WHERE classid = varFClassId; SELECT count(*) INTO varNb FROM Cns_seg_metadata - WHERE s_fileid = fid AND s_status = '-'; - IF varNb > fcNbCopies THEN - rc := dlf.ENSTOOMANYSEGS; - msg := dlf.ENSTOOMANYSEGS_MSG ||', VID='|| segEntry.vid; + WHERE s_fileid = varFid AND s_status = '-'; + IF varNb > varFCNbCopies THEN + rc := serrno.ENSTOOMANYSEGS; + msg := serrno.ENSTOOMANYSEGS_MSG ||', VID='|| inSegEntry.vid; ROLLBACK; RETURN; END IF; -- Update file status - UPDATE Cns_file_metadata SET status = 'm' WHERE fileid = fid; + UPDATE Cns_file_metadata SET status = 'm' WHERE fileid = varFid; COMMIT; - SELECT segEntry.blockId INTO varBlockId FROM Dual; -- to_char() of a RAW type does not work. This does the trick... - varParams := 'CopyNo='|| segEntry.copyNo ||' Fsec=1 SegmentSize='|| segEntry.segSize - ||' Compression='|| trunc(segEntry.segSize*100/segEntry.comprSize) ||' TPVID='|| segEntry.vid - ||' Fseq='|| segEntry.fseq ||' BlockId="' || varBlockId - ||'" ChecksumType="'|| segEntry.checksum_name ||'" ChecksumValue=' || fCkSum; - tmpDlfLog(dlf.LVL_SYSTEM, uuidGen(), 'New segment information', fid, varParams); + SELECT inSegEntry.blockId INTO varBlockId FROM Dual; -- to_char() of a RAW type does not work. This does the trick... + varParams := 'CopyNo='|| inSegEntry.copyNo ||' Fsec=1 SegmentSize='|| inSegEntry.segSize + ||' Compression='|| trunc(inSegEntry.segSize*100/inSegEntry.comprSize) ||' TPVID='|| inSegEntry.vid + ||' Fseq='|| inSegEntry.fseq ||' BlockId="' || varBlockId + ||'" ChecksumType="'|| inSegEntry.checksum_name ||'" ChecksumValue=' || varFCksum; + tmpDlfLog(inReqId, 0, 'New segment information', varFid, varParams); EXCEPTION WHEN NO_DATA_FOUND THEN -- The file entry was not found, just give up - rc := dlf.ENOENT; - msg := dlf.ENOENT_MSG; -END; -/ - -/** - * This procedure creates segments for multiple files by calling setSegmentForFile in a loop. - * The output is a log table ready to be sent to DLF from a stager database. - */ -CREATE OR REPLACE PROCEDURE setSegmentsForFiles(segs IN castorns.SegmentList, logs OUT castorns.Log_Cur) AS - varRC INTEGER; - varParams VARCHAR2(1000); - varStartTime TIMESTAMP; - varReqid VARCHAR2(36); -BEGIN - varStartTime := SYSTIMESTAMP; - varReqid := uuidGen(); - -- First clean any previous log - EXECUTE IMMEDIATE 'TRUNCATE TABLE ResultsLogHelper'; - -- Loop over all files. Each call commits or rollbacks each file. - FOR i IN segs.FIRST .. segs.LAST LOOP - setSegmentForFile(segs(i), varRC, varParams); - IF varRC != 0 THEN - varParams := 'ErrorCode='|| to_char(varRC) ||' ErrorMessage="'|| varParams || '"'; - tmpDlfLog(dlf.LVL_ERROR, varReqid, 'Error creating/updating segment', segs(i).fileId, varParams); - END IF; - END LOOP; - -- Final logging - UPDATE ResultsLogHelper SET reqid = varReqid; - varParams := 'Function="setSegmentsForFiles" NbFiles='|| segs.COUNT - ||' ElapsedTime='|| getSecs(varStartTime, SYSTIMESTAMP); - tmpDlfLog(dlf.LVL_SYSTEM, varReqid, 'Bulk processing complete', 0, varParams); - -- Return logs to the stager - OPEN logs FOR - SELECT timeinfo, lvl, reqid, msg, fileId, params FROM ResultsLogHelper; + rc := serrno.ENOENT; + msg := serrno.ENOENT_MSG; END; / @@ -378,24 +360,25 @@ END; * last case is only accepted if the second replaced copy was invalid. * Return code: * 0 in case of success - * ENOENT if the file does not exist (e.g. it had been dropped). + * ENOENT if the file does not exist (e.g. it has been dropped meanwhile). * EISDIR if the file is a directory. * EEXIST if the file already has a valid segment on the same tape. * ENSFILECHG if the file has been modified meanwhile. * SEINTERNAL if another segment exists on the given tape at the given fseq location. - * ENSNOSEG if the to-be-replaced segment was not found - * ENSOVERWHENREP if the oldCopyNo refers to a valid segment and the new segEntry has a different copyNo. + * ENSNOSEG if the to-be-replaced segment was not found. + * ENSOVERWHENREP if inOldCopyNo refers to a valid segment and the new inSegEntry has a different copyNo. */ -CREATE OR REPLACE PROCEDURE repackSegmentForFile(oldCopyNo IN INTEGER, segEntry IN castorns.Segment_Rec, - rc OUT INTEGER, msg OUT NOCOPY VARCHAR2) AS - varReqid VARCHAR2(36); - fid NUMBER; - fmode NUMBER(6); - fLastMTime NUMBER; - fClassId NUMBER; - fcNbCopies NUMBER; - fCkSumName VARCHAR2(2); - fCkSum VARCHAR2(32); +CREATE OR REPLACE PROCEDURE replaceSegmentForFile(inOldCopyNo IN INTEGER, inSegEntry IN castorns.Segment_Rec, + inReqId IN VARCHAR2, + rc OUT INTEGER, msg OUT NOCOPY VARCHAR2) AS + varFid NUMBER; + varFmode NUMBER(6); + varFLastMTime NUMBER; + varFSize NUMBER; + varFClassId NUMBER; + varFCNbCopies NUMBER; + varFCksumName VARCHAR2(2); + varFCksum VARCHAR2(32); varNb INTEGER; varStatus INTEGER; varBlockId VARCHAR2(8); @@ -408,33 +391,40 @@ CREATE OR REPLACE PROCEDURE repackSegmentForFile(oldCopyNo IN INTEGER, segEntry BEGIN rc := 0; msg := ''; - varReqid := uuidGen(); -- Get file data and lock the entry, exit if not found SELECT fileId, filemode, mtime, fileClass, csumType, csumValue - INTO fid, fmode, fLastMTime, fClassId, fCkSumName, fCkSum + INTO varFid, varFmode, varFLastMTime, varFClassId, varFCksumName, varFCksum FROM Cns_file_metadata - WHERE fileId = segEntry.fileId FOR UPDATE; + WHERE fileId = inSegEntry.fileId FOR UPDATE; -- Is it a directory? - IF bitand(fmode, 4*8*8*8*8) > 0 THEN -- 040000 == S_IFDIR - rc := dlf.EISDIR; - msg := dlf.EISDIR_MSG; + IF bitand(varFmode, 4*8*8*8*8) > 0 THEN -- 040000 == S_IFDIR + rc := serrno.EISDIR; + msg := serrno.EISDIR_MSG; ROLLBACK; RETURN; END IF; -- Has the file been changed meanwhile? - IF fLastMTime > segEntry.lastModTime AND segEntry.lastModTime > 0 THEN - rc := dlf.ENSFILECHG; - msg := dlf.ENSFILECHG_MSG; + IF varFLastMTime > inSegEntry.lastModTime AND inSegEntry.lastModTime > 0 THEN + rc := serrno.ENSFILECHG; + msg := serrno.ENSFILECHG_MSG; ROLLBACK; RETURN; END IF; -- Cross check file and segment checksums when adler32 (AD in the file entry): -- unfortunately we have to play with different representations... - IF fCkSumName = 'AD' AND segEntry.checksum_name = 'adler32' AND - segEntry.checksum != to_number(fCkSum, 'XXXXXXXX') THEN - rc := dlf.SECHECKSUM; - msg := dlf.SECHECKSUM_MSG || ' : ' - || to_char(segEntry.checksum, 'XXXXXXXX') || ' vs ' || fCkSum; + IF varFCksumName = 'AD' AND inSegEntry.checksum_name = 'adler32' AND + inSegEntry.checksum != to_number(varFCksum, 'XXXXXXXX') THEN + rc := serrno.SECHECKSUM; + msg := serrno.SECHECKSUM_MSG ||' : ' + || varFCksum ||' vs '|| to_char(inSegEntry.checksum, 'XXXXXXXX'); + ROLLBACK; + RETURN; + END IF; + -- Cross check segment (transfered) size and file size + IF varFSize != inSegEntry.segSize THEN + rc := serrno.ERTWRONGSIZE; + msg := serrno.ERTWRONGSIZE ||' : expected ' + || to_char(varFSize) ||', got '|| to_char(inSegEntry.segSize); ROLLBACK; RETURN; END IF; @@ -442,9 +432,9 @@ BEGIN -- on a tape that already holds a valid copy SELECT count(*) INTO varNb FROM Cns_seg_metadata - WHERE s_fileid = fid AND s_status = '-' AND vid = segEntry.vid; + WHERE s_fileid = varFid AND s_status = '-' AND vid = inSegEntry.vid; IF varNb > 0 THEN - rc := dlf.EEXIST; + rc := serrno.EEXIST; msg := 'File already has a copy on the tape'; ROLLBACK; RETURN; @@ -455,20 +445,20 @@ BEGIN BEGIN SELECT s_status INTO varStatus FROM Cns_seg_metadata - WHERE s_fileid = fid AND copyNo = segEntry.copyNo; + WHERE s_fileid = varFid AND copyNo = inSegEntry.copyNo; -- Check status of segment to be replaced in case it's a different copyNo - IF segEntry.copyNo != oldCopyNo THEN + IF inSegEntry.copyNo != inOldCopyNo THEN IF varStatus = '-' THEN -- We are asked to overwrite a valid segment and replace another one. -- This is forbidden. - rc := dlf.ENSOVERWHENREP; - msg := dlf.ENSOVERWHENREP_MSG; + rc := serrno.ENSOVERWHENREP; + msg := serrno.ENSOVERWHENREP_MSG; ROLLBACK; RETURN; END IF; -- OK, the segment being overwritten is invalid DELETE FROM Cns_seg_metadata - WHERE s_fileid = fid AND copyNo = segEntry.copyNo + WHERE s_fileid = varFid AND copyNo = inSegEntry.copyNo RETURNING copyNo, segSize, compression, vid, fseq, blockId, checksum_name, checksum INTO varOwSeg.copyNo, varOwSeg.segSize, varOwSeg.comprSize, varOwSeg.vid, varOwSeg.fseq, varOwSeg.blockId, varOwSeg.checksum_name, varOwSeg.checksum; @@ -478,19 +468,19 @@ BEGIN ||' Compression='|| varOwSeg.comprSize ||' TPVID='|| varOwSeg.vid ||' Fseq='|| varOwSeg.fseq ||' BlockId="' || varBlockId ||'" ChecksumType="'|| varOwSeg.checksum_name ||'" ChecksumValue=' || varOwSeg.checksum; - tmpDlfLog(dlf.LVL_SYSTEM, varReqid, 'Unlinking segment (overwritten)', fid, varParams); + tmpDlfLog(inReqId, 0, 'Unlinking segment (overwritten)', varFid, varParams); END IF; EXCEPTION WHEN NO_DATA_FOUND THEN -- Previous segment not found, give up - rc := dlf.ENSNOSEG; - msg := dlf.ENSNOSEG_MSG; + rc := serrno.ENSNOSEG; + msg := serrno.ENSNOSEG_MSG; ROLLBACK; RETURN; END; -- We're done with the pre-checks. Remove and log old segment metadata DELETE FROM Cns_seg_metadata - WHERE s_fileid = fid AND copyNo = oldCopyNo + WHERE s_fileid = varFid AND copyNo = inOldCopyNo RETURNING copyNo, segSize, compression, vid, fseq, blockId, checksum_name, checksum INTO varRepSeg.copyNo, varRepSeg.segSize, varRepSeg.comprSize, varRepSeg.vid, varRepSeg.fseq, varRepSeg.blockId, varRepSeg.checksum_name, varRepSeg.checksum; @@ -499,68 +489,95 @@ BEGIN ||' Compression='|| varRepSeg.comprSize ||' TPVID='|| varRepSeg.vid ||' Fseq='|| varRepSeg.fseq ||' BlockId="' || varBlockId ||'" ChecksumType="'|| varRepSeg.checksum_name ||'" ChecksumValue=' || varRepSeg.checksum; - tmpDlfLog(dlf.LVL_SYSTEM, varReqid, 'Unlinking segment (replaced)', fid, varParams); + tmpDlfLog(inReqId, 0, 'Unlinking segment (replaced)', varFid, varParams); -- Insert new segment metadata and deal with possible collisions with the fseq position BEGIN INSERT INTO Cns_seg_metadata (s_fileId, copyNo, fsec, segSize, s_status, vid, fseq, blockId, compression, side, checksum_name, checksum) - VALUES (fid, segEntry.copyNo, 1, segEntry.segSize, '-', - segEntry.vid, segEntry.fseq, segEntry.blockId, trunc(segEntry.segSize*100/segEntry.comprSize), - 0, segEntry.checksum_name, segEntry.checksum); + VALUES (varFid, inSegEntry.copyNo, 1, inSegEntry.segSize, '-', + inSegEntry.vid, inSegEntry.fseq, inSegEntry.blockId, trunc(inSegEntry.segSize*100/inSegEntry.comprSize), + 0, inSegEntry.checksum_name, inSegEntry.checksum); EXCEPTION WHEN CONSTRAINT_VIOLATED THEN -- There must already be an existing segment at that fseq position for a different file. -- This is forbidden! Abort the entire operation. - rc := dlf.SEINTERNAL; - msg := 'A file already exists at fseq '|| segEntry.fseq ||' on VID '|| segEntry.vid; + rc := serrno.SEINTERNAL; + msg := 'A file already exists at fseq '|| inSegEntry.fseq ||' on VID '|| inSegEntry.vid; ROLLBACK; RETURN; END; -- All right, commit and log COMMIT; - SELECT segEntry.blockId INTO varBlockId FROM Dual; -- to_char() of a RAW type does not work. This does the trick... - varParams := 'CopyNo='|| segEntry.copyNo ||' Fsec=1 SegmentSize='|| segEntry.segSize - ||' Compression='|| trunc(segEntry.segSize*100/segEntry.comprSize) ||' TPVID='|| segEntry.vid - ||' Fseq='|| segEntry.fseq ||' BlockId="' || varBlockId - ||'" ChecksumType="'|| segEntry.checksum_name ||'" ChecksumValue=' || fCkSum; - tmpDlfLog(dlf.LVL_SYSTEM, varReqid, 'New segment information', fid, varParams); + SELECT inSegEntry.blockId INTO varBlockId FROM Dual; -- to_char() of a RAW type does not work. This does the trick... + varParams := 'CopyNo='|| inSegEntry.copyNo ||' Fsec=1 SegmentSize='|| inSegEntry.segSize + ||' Compression='|| trunc(inSegEntry.segSize*100/inSegEntry.comprSize) ||' TPVID='|| inSegEntry.vid + ||' Fseq='|| inSegEntry.fseq ||' BlockId="' || varBlockId + ||'" ChecksumType="'|| inSegEntry.checksum_name ||'" ChecksumValue=' || varFCksum; + tmpDlfLog(inReqId, 0, 'New segment information', varFid, varParams); EXCEPTION WHEN NO_DATA_FOUND THEN -- The file entry was not found, just give up - rc := dlf.ENOENT; - msg := dlf.ENOENT_MSG; + rc := serrno.ENOENT; + msg := serrno.ENOENT_MSG; END; / /** - * This procedure replaces segments for multiple files by calling repackSegmentForFile in a loop. - * The output is a log table ready to be sent to DLF from a stager database. + * This procedure sets or replaces segments for multiple files by calling either setSegmentForFile + * or replaceSegmentForFile in a loop, the choice depending on the inOldCopyNos values: + * when 0, a normal migration is assumed and setSegmentForFile is called. + * The output is a set of arrays of logs to be sent to DLF from a stager database. */ -CREATE OR REPLACE PROCEDURE repackSegmentsForFiles(oldCopyNos IN castorns.cnumList, segs IN castorns.SegmentList, - logs OUT castorns.Log_Cur) AS +CREATE OR REPLACE PROCEDURE setOrReplaceSegmentsForFiles(inReqId IN VARCHAR2) AS varRC INTEGER; varParams VARCHAR2(1000); varStartTime TIMESTAMP; - varReqid VARCHAR2(36); + varSeg castorns.Segment_Rec; + varCount INTEGER; BEGIN varStartTime := SYSTIMESTAMP; - varReqid := uuidGen(); - -- First clean any previous log - EXECUTE IMMEDIATE 'TRUNCATE TABLE ResultsLogHelper'; + varCount := 0; -- Loop over all files. Each call commits or rollbacks each file. - FOR i IN segs.FIRST .. segs.LAST LOOP - repackSegmentForFile(oldCopyNos(i), segs(i), varRC, varParams); + FOR s IN (SELECT fileId, lastModTime, copyNo, oldCopyNo, transfSize, comprSize, + vid, fseq, blockId, checksumType, checksum + FROM SetSegmentsForFilesHelper + WHERE reqId = inReqId) LOOP + varSeg.fileId := s.fileId; + varSeg.lastModTime := s.lastModTime; + varSeg.copyNo := s.copyNo; + varSeg.segSize := s.transfSize; + varSeg.comprSize := s.comprSize; + varSeg.vid := s.vid; + varSeg.fseq := s.fseq; + varSeg.blockId := s.blockId; + varSeg.checksum_name := s.checksumType; + varSeg.checksum := s.checksum; + IF s.oldCopyNo = 0 THEN + setSegmentForFile(varSeg, inReqId, varRC, varParams); + ELSE + replaceSegmentForFile(s.oldCopyNo, varSeg, inReqId, varRC, varParams); + END IF; IF varRC != 0 THEN - varParams := 'ErrorCode='|| to_char(varRC) ||' ErrorMessage="'|| varParams || '"'; - tmpDlfLog(dlf.LVL_ERROR, varReqid, 'Error replacing segment', segs(i).fileId, varParams); + varParams := 'ErrorCode='|| to_char(varRC) ||' ErrorMessage="'|| varParams ||'"'; + tmpDlfLog(inReqId, varRC, 'Error creating/replacing segment', s.fileId, varParams); + COMMIT; END IF; + varCount := varCount + 1; END LOOP; - -- Final logging - UPDATE ResultsLogHelper SET reqid = varReqid; - varParams := 'Function="repackSegmentsForFiles" NbFiles='|| segs.COUNT - ||' ElapsedTime='|| getSecs(varStartTime, SYSTIMESTAMP); - tmpDlfLog(dlf.LVL_SYSTEM, varReqid, 'Bulk processing complete', 0, varParams); - -- Return logs to the stager - OPEN logs FOR - SELECT timeinfo, lvl, reqid, msg, fileId, params FROM ResultsLogHelper; + IF varCount > 0 THEN + -- Final logging + varParams := 'Function="setOrRepackSegmentsForFiles" NbFiles='|| varCount + ||' ElapsedTime='|| getSecs(varStartTime, SYSTIMESTAMP) + ||' AvgProcessingTime='|| getSecs(varStartTime, SYSTIMESTAMP)/varCount; + tmpDlfLog(inReqId, 0, 'Bulk processing complete', 0, varParams); + END IF; + -- Clean input data + DELETE FROM SetSegmentsForFilesHelper + WHERE reqId = inReqId; + COMMIT; + -- Return results and logs to the stager. Unfortunately we can't OPEN CURSOR FOR ... + -- because we would get ORA-24338: 'statement handle not executed' at run time. + -- Moreover, temporary tables are not supported with distributed transactions, + -- so the stager will remotely open the ResultsLogHelper table, and we clean + -- the tables by hand using the reqId key. END; / @@ -570,7 +587,7 @@ END; CREATE OR REPLACE PROCEDURE setSegChecksumWhenNull(fid IN INTEGER, copyNb IN INTEGER, cksumType IN VARCHAR2, - cksumValue IN INTEGER) IS + cksumValue IN INTEGER) AS BEGIN UPDATE Cns_seg_metadata SET checksum_name = cksumType, checksum = cksumValue diff --git a/upgrades/stager_2.1.12-4_to_2.1.13-0.sql b/upgrades/stager_2.1.12-4_to_2.1.13-0.sql index ee4b35430d9097ebe818888ad138121ff8804beb..7e474f8e5fe2947b0cc3969e8920855699651dd2 100644 --- a/upgrades/stager_2.1.12-4_to_2.1.13-0.sql +++ b/upgrades/stager_2.1.12-4_to_2.1.13-0.sql @@ -263,11 +263,9 @@ CREATE GLOBAL TEMPORARY TABLE FilesToMigrateHelper fileTransactionId NUMBER, fileSize NUMBER, fSeq INTEGER) ON COMMIT DELETE ROWS; -CREATE GLOBAL TEMPORARY TABLE FileMigrationResultsHelper - (reqId VARCHAR2(36) CONSTRAINT PK_SetSegsHelper_ReqId PRIMARY KEY, - fileId NUMBER, lastModTime NUMBER, copyNo NUMBER, oldCopyNo NUMBER, transfSize NUMBER, - comprSize NUMBER, vid VARCHAR2(6), fSeq NUMBER, blockId RAW(4), checksumType VARCHAR2(2), checksum NUMBER) - ON COMMIT DELETE ROWS; +CREATE TABLE FileMigrationResultsHelper + (reqId VARCHAR2(36), fileId NUMBER, lastModTime NUMBER, copyNo NUMBER, oldCopyNo NUMBER, transfSize NUMBER, + comprSize NUMBER, vid VARCHAR2(6), fSeq NUMBER, blockId RAW(4), checksumType VARCHAR2(16), checksum NUMBER); /* Drop obsoleted code */ @@ -301,7 +299,7 @@ DROP FUNCTION triggerRepackRecall; /* Resurrect all subrequest that were waiting so that we trigger new recalls after we have */ /* dropped all recall related tables */ /* also cleanup all diskcopies in WAITTAPERECALL as they should no exist anymore */ -DELETE FROM DiskCopy WHERE status = dconst.DISKCOPY_WAITTAPERECALL; +DELETE FROM DiskCopy WHERE status = dconst.DISKCOPY_WAITTAPERECALL; UPDATE SubRequest SET status = dconst.SUBREQUEST_RESTART WHERE status IN (dconst.SUBREQUEST_WAITTAPERECALL, dconst.SUBREQUEST_WAITSUBREQ); COMMIT;