diff --git a/castor/db/oracleStager.sql b/castor/db/oracleStager.sql index 8bdc6243d562ad8e2ef9e9a57db9518565b62a76..aa1720f9fd613c4348ccb45a8b3c60fbb5db4baa 100644 --- a/castor/db/oracleStager.sql +++ b/castor/db/oracleStager.sql @@ -3353,20 +3353,11 @@ BEGIN IF inDoSchedule THEN RETURN 0; -- do not answer client, the diskserver will ELSE - -- Check whether it was the last subrequest in the request - DECLARE - varRemainingSR INTEGER; - BEGIN - SELECT /*+ INDEX_RS_ASC(Subrequest I_Subrequest_Request)*/ 1 INTO varRemainingSR - FROM SubRequest - WHERE request = varReqId - AND status IN (0, 1, 2, 3, 4, 5, 7, 10, 12, 13) -- all but FINISHED, FAILED_FINISHED, ARCHIVED - AND answered = 0 - AND ROWNUM < 2; - RETURN 1; -- answer but this is not the last one - EXCEPTION WHEN NO_DATA_FOUND THEN - RETURN 2; -- answer anf this is the last answer - END; + -- first lock the request. Note that we are always in a case of PrepareToPut as + -- we will answer the client. + SELECT id INTO varReqId FROM StagePrepareToPutRequest WHERE id = varReqId FOR UPDATE; + -- now do the check on whether we were the last subrequest + RETURN wasLastSubRequest(varReqId); END IF; END; / @@ -3751,6 +3742,28 @@ BEGIN END; / +/* PL/SQL method implementing wasLastSubRequest + * returns whether the given request still has ongoing subrequests + * output is 1 if not, 2 if yes + * WARNING : you need to hold a lock on the given request for this function + * to be safe. + */ +CREATE OR REPLACE FUNCTION wasLastSubRequest(inReqId IN INTEGER) RETURN INTEGER AS + -- Check whether it was the last subrequest in the request + varRemainingSR INTEGER; +BEGIN + SELECT /*+ INDEX_RS_ASC(Subrequest I_Subrequest_Request)*/ 1 INTO varRemainingSR + FROM SubRequest + WHERE request = inReqId + AND status IN (0, 1, 2, 3, 4, 5, 7, 10, 12, 13) -- all but FINISHED, FAILED_FINISHED, ARCHIVED + AND answered = 0 + AND ROWNUM < 2; + RETURN 1; -- answer but this is not the last one +EXCEPTION WHEN NO_DATA_FOUND THEN + RETURN 2; -- answer and this is the last answer +END; +/ + /* PL/SQL method implementing handlePrepareToGet * returns whether the client should be answered */ @@ -3763,15 +3776,17 @@ RETURN INTEGER AS varEgid NUMBER; varSvcClassId NUMBER; varReqUUID VARCHAR(2048); + varReqId INTEGER; varSrUUID VARCHAR(2048); + varIsAnswered INTEGER; BEGIN -- lock the castorFile to be safe in case of concurrent subrequests SELECT nsOpenTime INTO varNsOpenTime FROM CastorFile WHERE id = inCfId FOR UPDATE; -- retrieve the svcClass, user and log data for this subrequest SELECT /*+ INDEX(Subrequest PK_Subrequest_Id)*/ Request.euid, Request.egid, Request.svcClass, - Request.reqId, SubRequest.subreqId - INTO varEuid, varEgid, varSvcClassId, varReqUUID, varSrUUID + Request.reqId, Request.id, SubRequest.subreqId, SubRequest.answered + INTO varEuid, varEgid, varSvcClassId, varReqUUID, varReqId, varSrUUID, varIsAnswered FROM (SELECT /*+ INDEX(StageGetRequest PK_StageGetRequest_Id) */ id, euid, egid, svcClass, reqId from StagePrepareToGetRequest) Request, SubRequest @@ -3829,20 +3844,26 @@ BEGIN 'SUBREQID=' || varSrUUID); -- update SubRequest archiveSubReq(inSrId, dconst.SUBREQUEST_FINISHED); - -- all went fine, we should answer to client - RETURN 1; + -- all went fine, answer to client if needed + IF varIsAnswered > 0 THEN + RETURN 0; + END IF; + ELSE + IF triggerD2dOrRecall(inCfId, varNsOpenTime, inSrId, inFileId, inNsHost, varEuid, varEgid, + varSvcClassId, inFileSize, varReqUUID, varSrUUID) != 0 THEN + -- recall started, we are done, update subrequest and answer to client + UPDATE SubRequest SET status = dconst.SUBREQUEST_WAITTAPERECALL, answered=1 WHERE id = inSrId; + ELSE + -- could not start recall, SubRequest has been marked as FAILED, no need to answer + RETURN 0; + END IF; END IF; + -- first lock the request. Note that we are always in a case of PrepareToPut as + -- we will answer the client. + SELECT id INTO varReqId FROM StagePrepareToGetRequest WHERE id = varReqId FOR UPDATE; + -- now do the check on whether we were the last subrequest + RETURN wasLastSubRequest(varReqId); END; - - IF triggerD2dOrRecall(inCfId, varNsOpenTime, inSrId, inFileId, inNsHost, varEuid, varEgid, - varSvcClassId, inFileSize, varReqUUID, varSrUUID) != 0 THEN - -- recall started, we are done, update subrequest and answer to client - UPDATE SubRequest SET status = dconst.SUBREQUEST_WAITTAPERECALL WHERE id = inSrId; - RETURN 1; - ELSE - -- could not start recall, SubRequest has been marked as FAILED, no need to answer - RETURN 0; - END IF; END; / diff --git a/castor/db/stager_oracle_create.sql b/castor/db/stager_oracle_create.sql index 82cb2dd7b3541f3adb1cbcc95c1cc1be85459b13..b68eca92d7903d8fdd62e9c33c14c7cec5c46c5a 100644 --- a/castor/db/stager_oracle_create.sql +++ b/castor/db/stager_oracle_create.sql @@ -6981,20 +6981,11 @@ BEGIN IF inDoSchedule THEN RETURN 0; -- do not answer client, the diskserver will ELSE - -- Check whether it was the last subrequest in the request - DECLARE - varRemainingSR INTEGER; - BEGIN - SELECT /*+ INDEX_RS_ASC(Subrequest I_Subrequest_Request)*/ 1 INTO varRemainingSR - FROM SubRequest - WHERE request = varReqId - AND status IN (0, 1, 2, 3, 4, 5, 7, 10, 12, 13) -- all but FINISHED, FAILED_FINISHED, ARCHIVED - AND answered = 0 - AND ROWNUM < 2; - RETURN 1; -- answer but this is not the last one - EXCEPTION WHEN NO_DATA_FOUND THEN - RETURN 2; -- answer anf this is the last answer - END; + -- first lock the request. Note that we are always in a case of PrepareToPut as + -- we will answer the client. + SELECT id INTO varReqId FROM StagePrepareToPutRequest WHERE id = varReqId FOR UPDATE; + -- now do the check on whether we were the last subrequest + RETURN wasLastSubRequest(varReqId); END IF; END; / @@ -7379,6 +7370,28 @@ BEGIN END; / +/* PL/SQL method implementing wasLastSubRequest + * returns whether the given request still has ongoing subrequests + * output is 1 if not, 2 if yes + * WARNING : you need to hold a lock on the given request for this function + * to be safe. + */ +CREATE OR REPLACE FUNCTION wasLastSubRequest(inReqId IN INTEGER) RETURN INTEGER AS + -- Check whether it was the last subrequest in the request + varRemainingSR INTEGER; +BEGIN + SELECT /*+ INDEX_RS_ASC(Subrequest I_Subrequest_Request)*/ 1 INTO varRemainingSR + FROM SubRequest + WHERE request = inReqId + AND status IN (0, 1, 2, 3, 4, 5, 7, 10, 12, 13) -- all but FINISHED, FAILED_FINISHED, ARCHIVED + AND answered = 0 + AND ROWNUM < 2; + RETURN 1; -- answer but this is not the last one +EXCEPTION WHEN NO_DATA_FOUND THEN + RETURN 2; -- answer and this is the last answer +END; +/ + /* PL/SQL method implementing handlePrepareToGet * returns whether the client should be answered */ @@ -7391,15 +7404,17 @@ RETURN INTEGER AS varEgid NUMBER; varSvcClassId NUMBER; varReqUUID VARCHAR(2048); + varReqId INTEGER; varSrUUID VARCHAR(2048); + varIsAnswered INTEGER; BEGIN -- lock the castorFile to be safe in case of concurrent subrequests SELECT nsOpenTime INTO varNsOpenTime FROM CastorFile WHERE id = inCfId FOR UPDATE; -- retrieve the svcClass, user and log data for this subrequest SELECT /*+ INDEX(Subrequest PK_Subrequest_Id)*/ Request.euid, Request.egid, Request.svcClass, - Request.reqId, SubRequest.subreqId - INTO varEuid, varEgid, varSvcClassId, varReqUUID, varSrUUID + Request.reqId, Request.id, SubRequest.subreqId, SubRequest.answered + INTO varEuid, varEgid, varSvcClassId, varReqUUID, varReqId, varSrUUID, varIsAnswered FROM (SELECT /*+ INDEX(StageGetRequest PK_StageGetRequest_Id) */ id, euid, egid, svcClass, reqId from StagePrepareToGetRequest) Request, SubRequest @@ -7457,20 +7472,26 @@ BEGIN 'SUBREQID=' || varSrUUID); -- update SubRequest archiveSubReq(inSrId, dconst.SUBREQUEST_FINISHED); - -- all went fine, we should answer to client - RETURN 1; + -- all went fine, answer to client if needed + IF varIsAnswered > 0 THEN + RETURN 0; + END IF; + ELSE + IF triggerD2dOrRecall(inCfId, varNsOpenTime, inSrId, inFileId, inNsHost, varEuid, varEgid, + varSvcClassId, inFileSize, varReqUUID, varSrUUID) != 0 THEN + -- recall started, we are done, update subrequest and answer to client + UPDATE SubRequest SET status = dconst.SUBREQUEST_WAITTAPERECALL, answered=1 WHERE id = inSrId; + ELSE + -- could not start recall, SubRequest has been marked as FAILED, no need to answer + RETURN 0; + END IF; END IF; + -- first lock the request. Note that we are always in a case of PrepareToPut as + -- we will answer the client. + SELECT id INTO varReqId FROM StagePrepareToGetRequest WHERE id = varReqId FOR UPDATE; + -- now do the check on whether we were the last subrequest + RETURN wasLastSubRequest(varReqId); END; - - IF triggerD2dOrRecall(inCfId, varNsOpenTime, inSrId, inFileId, inNsHost, varEuid, varEgid, - varSvcClassId, inFileSize, varReqUUID, varSrUUID) != 0 THEN - -- recall started, we are done, update subrequest and answer to client - UPDATE SubRequest SET status = dconst.SUBREQUEST_WAITTAPERECALL WHERE id = inSrId; - RETURN 1; - ELSE - -- could not start recall, SubRequest has been marked as FAILED, no need to answer - RETURN 0; - END IF; END; /