Commit e8c63c74 authored by Eric Cano's avatar Eric Cano
Browse files

Merge remote-tracking branch 'origin/master' into repack-dev

parents 216bd16d edb9d135
......@@ -879,6 +879,91 @@ TEST_P(cta_catalogue_CatalogueTest, deleteTapePool) {
ASSERT_TRUE(m_catalogue->getTapePools().empty());
}
TEST_P(cta_catalogue_CatalogueTest, deleteTapePool_notEmpty) {
using namespace cta;
ASSERT_TRUE(m_catalogue->getTapes().empty());
const std::string vid = "vid";
ASSERT_FALSE(m_catalogue->tapeExists(vid));
const std::string mediaType = "media_type";
const std::string vendor = "vendor";
const std::string logicalLibraryName = "logical_library_name";
const std::string tapePoolName = "tape_pool_name";
const std::string vo = "vo";
const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000;
const bool disabledValue = true;
const bool fullValue = false;
const std::string comment = "Create tape";
m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName,
"Create logical library");
m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool");
{
const auto pools = m_catalogue->getTapePools();
ASSERT_EQ(1, pools.size());
const auto &pool = pools.front();
ASSERT_EQ(tapePoolName, pool.name);
ASSERT_EQ(vo, pool.vo);
ASSERT_EQ(0, pool.nbTapes);
ASSERT_EQ(0, pool.capacityBytes);
ASSERT_EQ(0, pool.dataBytes);
ASSERT_EQ(0, pool.nbPhysicalFiles);
}
m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes,
disabledValue, fullValue, comment);
ASSERT_TRUE(m_catalogue->tapeExists(vid));
const auto tapes = m_catalogue->getTapes();
ASSERT_EQ(1, tapes.size());
{
const auto tape = tapes.front();
ASSERT_EQ(vid, tape.vid);
ASSERT_EQ(mediaType, tape.mediaType);
ASSERT_EQ(vendor, tape.vendor);
ASSERT_EQ(logicalLibraryName, tape.logicalLibraryName);
ASSERT_EQ(tapePoolName, tape.tapePoolName);
ASSERT_EQ(vo, tape.vo);
ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
ASSERT_TRUE(disabledValue == tape.disabled);
ASSERT_TRUE(fullValue == tape.full);
ASSERT_EQ(comment, tape.comment);
ASSERT_FALSE(tape.labelLog);
ASSERT_FALSE(tape.lastReadLog);
ASSERT_FALSE(tape.lastWriteLog);
const auto creationLog = tape.creationLog;
ASSERT_EQ(m_admin.username, creationLog.username);
ASSERT_EQ(m_admin.host, creationLog.host);
const auto lastModificationLog = tape.lastModificationLog;
ASSERT_EQ(creationLog, lastModificationLog);
}
{
const auto pools = m_catalogue->getTapePools();
ASSERT_EQ(1, pools.size());
const auto &pool = pools.front();
ASSERT_EQ(tapePoolName, pool.name);
ASSERT_EQ(vo, pool.vo);
ASSERT_EQ(1, pool.nbTapes);
ASSERT_EQ(capacityInBytes, pool.capacityBytes);
ASSERT_EQ(0, pool.dataBytes);
ASSERT_EQ(0, pool.nbPhysicalFiles);
}
ASSERT_THROW(m_catalogue->deleteTapePool(tapePoolName), exception::UserError);
}
TEST_P(cta_catalogue_CatalogueTest, createTapePool_emptyStringTapePoolName) {
using namespace cta;
......
......@@ -858,14 +858,20 @@ bool RdbmsCatalogue::archiveRouteExists(rdbms::Conn &conn, const std::string &di
//------------------------------------------------------------------------------
void RdbmsCatalogue::deleteTapePool(const std::string &name) {
try {
const char *const sql = "DELETE FROM TAPE_POOL WHERE TAPE_POOL_NAME = :TAPE_POOL_NAME";
auto conn = m_connPool.getConn();
auto stmt = conn.createStmt(sql);
stmt.bindString(":TAPE_POOL_NAME", name);
stmt.executeNonQuery();
const uint64_t nbTapesInPool = getNbTapesInPool(conn, name);
if(0 == stmt.getNbAffectedRows()) {
throw exception::UserError(std::string("Cannot delete tape-pool ") + name + " because it does not exist");
if(0 == nbTapesInPool) {
const char *const sql = "DELETE FROM TAPE_POOL WHERE TAPE_POOL_NAME = :TAPE_POOL_NAME";
auto stmt = conn.createStmt(sql);
stmt.bindString(":TAPE_POOL_NAME", name);
stmt.executeNonQuery();
if(0 == stmt.getNbAffectedRows()) {
throw exception::UserError(std::string("Cannot delete tape-pool ") + name + " because it does not exist");
}
} else {
throw exception::UserError(std::string("Cannot delete tape-pool ") + name + " because it is not empty");
}
} catch(exception::UserError &) {
throw;
......@@ -5490,6 +5496,32 @@ void RdbmsCatalogue::checkTapeItemWrittenFieldsAreSet(const std::string& calling
}
}
//------------------------------------------------------------------------------
// getNbTapesInPool
//------------------------------------------------------------------------------
uint64_t RdbmsCatalogue::getNbTapesInPool(rdbms::Conn &conn, const std::string &name) const {
try {
const char *const sql =
"SELECT "
"COUNT(*) AS NB_TAPES "
"FROM "
"TAPE "
"WHERE "
"TAPE.TAPE_POOL_NAME = :TAPE_POOL_NAME";
auto stmt = conn.createStmt(sql);
stmt.bindString(":TAPE_POOL_NAME", name);
auto rset = stmt.executeQuery();
if(!rset.next()) {
throw exception::Exception("Result set of SELECT COUNT(*) is empty");
}
return rset.columnUint64("NB_TAPES");
} catch(exception::UserError &) {
throw;
} catch(exception::Exception &ex) {
ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
throw;
}
}
} // namespace catalogue
} // namespace cta
......@@ -1220,6 +1220,17 @@ protected:
*/
bool isNonCachedAdmin(const common::dataStructures::SecurityIdentity &admin) const;
/**
* Returns the number of tapes in the specified tape pool.
*
* If the tape pool does not exist then this method returns 0.
*
* @param conn The database connection.
* @param name The name of the tape pool.
* @return The number of tapes in the specified tape pool.
*/
uint64_t getNbTapesInPool(rdbms::Conn &conn, const std::string &name) const;
/**
* Cached versions of tape copy to tape tape pool mappings for specific
* storage classes.
......
......@@ -26,6 +26,11 @@
#include "CtaAdminCmd.hpp"
// synchronisation flag between main thread and stream handler thread
std::atomic<bool> isHeaderSent(false);
// Define XRootD SSI Alert message callback
namespace XrdSsiPb {
......@@ -54,6 +59,9 @@ void IStreamBuffer<cta::xrd::Data>::DataCallback(cta::xrd::Data record) const
using namespace cta::xrd;
using namespace cta::admin;
// Wait for primary response to be handled before allowing stream response
while(!isHeaderSent) { std::this_thread::yield(); }
// Output results in JSON format for parsing by a script
if(CtaAdminCmd::isJson())
{
......@@ -232,6 +240,8 @@ void CtaAdminCmd::send() const
case HeaderType::NONE:
default: break;
}
// Allow stream processing to commence
isHeaderSent = true;
break;
case Response::RSP_ERR_PROTOBUF: throw XrdSsiPb::PbException(response.message_txt());
case Response::RSP_ERR_USER:
......
/*****************************************************************************
* castorns_ctamigration_schema.sql
*
* This file is part of the Castor/CTA project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* This script adds the necessary tables and code to an existing
* CASTOR Nameserver schema in order to support the metadata migration
* to CTA, the CASTOR successor.
*
* @author Castor Dev team, castor-dev@cern.ch
*****************************************************************************/
UNDEF ctaSchema
ACCEPT ctaSchema CHAR PROMPT 'Enter the name of the CTA schema: ';
-- Helper tables to store intermediate data for the export.
-- We cannot use temporary tables with distributed transactions.
CREATE TABLE CTAFilesHelper (fileid INTEGER NOT NULL PRIMARY KEY, path VARCHAR2(2048), disk_uid INTEGER, disk_gid INTEGER,
filemode INTEGER, atime INTEGER, mtime INTEGER, classname VARCHAR2(100),
filesize INTEGER, checksum VARCHAR2(10), copyno INTEGER, VID VARCHAR2(6), fseq INTEGER,
blockId INTEGER, s_mtime INTEGER);
CREATE TABLE CTADirsHelper (fileid INTEGER NOT NULL PRIMARY KEY, path VARCHAR2(2048), disk_uid INTEGER, disk_gid INTEGER,
filemode INTEGER, atime INTEGER, mtime INTEGER, classname VARCHAR2(100));
-- Need to grant access from the CTA catalogue schema
GRANT SELECT ON CTAFilesHelper TO &ctaSchema;
GRANT SELECT ON CTADirsHelper TO &ctaSchema;
/* Procedure to extract the directory names for the export to CTA */
CREATE OR REPLACE PROCEDURE filesAndDirsForCTAExport(inPoolName IN VARCHAR2) AS
fileids numList;
dirids numList;
nbFiles INTEGER;
BEGIN
-- First check if there's anything already ongoing and fail early:
SELECT COUNT(*) INTO nbFiles FROM CTAFilesHelper;
IF nbFiles > 0 THEN
raise_application_error(-20000, 'Another export of ' || nbFiles || ' files to CTA is ongoing, ' ||
'please terminate it with completeCTAExport() before starting a new one.');
END IF;
-- Run the minimal join query to extract all relevant fileids and log this number
SELECT F.fileid, F.parent_fileid
BULK COLLECT INTO fileids, dirids
FROM Cns_file_metadata F, Cns_seg_metadata S
WHERE F.fileid = S.s_fileid
AND vid IN (
SELECT vid FROM Vmgr_tape_side
WHERE poolName = inPoolName AND BITAND(status, 2) = 0 -- not already EXPORTED
);
-- XXX TODO log fileids.LENGTH
-- Populate the helper tables by selecting all required metadata
EXECUTE IMMEDIATE 'TRUNCATE TABLE CTADirsHelper';
INSERT /*+ APPEND */ INTO CTADirsHelper (
-- strip the /castor/cern.ch prefix from all paths
SELECT F.fileid, substr(nvl(D.path, getPathForFileid(F.fileid)), length('/castor/cern.ch')) as path,
F.owner_uid disk_uid, F.gid disk_gid,
F.filemode, F.atime, F.mtime, C.name classname
FROM Cns_file_metadata F, Cns_class_metadata C, Dirs_Full_Path D,
(SELECT * FROM TABLE(dirIds)) DirIdsTable
WHERE DirIdsTable.column_value = F.fileid
AND F.fileid(+) = D.fileid
);
COMMIT;
INSERT /*+ APPEND */ INTO CTAFilesHelper (
SELECT F.fileid, decode(D.path, NULL, getPathForFileid(F.fileid), D.path || '/' || F.name) as path,
F.owner_uid, F.gid, F.filemode, F.atime, F.mtime, C.name classname,
S.segsize, S.checksum, S.copyno, S.vid, S.fseq, utl_raw.cast_to_binary_integer(S.blockId),
S.lastModificationTime as s_mtime
FROM Cns_file_metadata F, Cns_seg_metadata S, Cns_class_metadata C, Dirs_Full_Path D,
(SELECT * FROM TABLE(fileIds)) FileIdsTable
WHERE F.fileid = FileIdsTable.column_value
AND F.fileid = S.s_fileid
AND F.parent_fileid(+) = D.fileid
AND F.fileclass = C.classid
);
COMMIT;
END;
/
/* Procedure to terminate the export to CTA and account it on the statistics */
CREATE OR REPLACE PROCEDURE completeCTAExport(inPoolName IN VARCHAR2) AS
CURSOR c IS SELECT fileid FROM CTAFilesHelper;
ids numList;
BEGIN
LOOP
OPEN c;
FETCH c BULK COLLECT INTO ids LIMIT 10000;
EXIT WHEN ids.count = 0;
CLOSE c;
FORALL i IN 1..ids.count
UPDATE Cns_file_metadata SET onCTA = 1 WHERE fileid = ids(i);
FORALL i IN 1..ids.count
UPDATE Cns_seg_metadata SET onCTA = 1 WHERE s_fileid = ids(i);
FORALL i IN 1..ids.count
DELETE FROM CTAFilesHelper WHERE fileid = ids(i);
COMMIT;
END LOOP;
EXECUTE IMMEDIATE 'TRUNCATE TABLE CTAFilesHelper';
END;
/
-- XXX TO BE CHECKED
EXECUTE IMMEDIATE 'GRANT EXECUTE ON prepareCTAExport TO CTA';
EXECUTE IMMEDIATE 'GRANT EXECUTE ON dirsForCTAExport TO CTA';
EXECUTE IMMEDIATE 'GRANT EXECUTE ON filesForCTAExport TO CTA';
EXECUTE IMMEDIATE 'GRANT EXECUTE ON completeCTAExport TO CTA';
#!/bin/sh
#/******************************************************************************
# * castortapepooltocta.sh
# *
# * This file is part of the Castor/CTA project.
# * See http://castor.web.cern.ch/castor
# *
# * Copyright (C) 2003 CERN
# * This program is free software; you can redistribute it and/or
# * modify it under the terms of the GNU General Public License
# * as published by the Free Software Foundation; either version 2
# * of the License, or (at your option) any later version.
# * This program is distributed in the hope that it will be useful,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# * GNU General Public License for more details.
# * You should have received a copy of the GNU General Public License
# * along with this program; if not, write to the Free Software
# * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# *
# * command line tool to prepare the export of a tapepool metadata
# * to CTA, the CASTOR successor
#
# * @author Castor Dev team, castor-dev@cern.ch
# *****************************************************************************/
# check arguments
if [ $# != 1 ]; then
echo usage: $0 tapepool
exit 1
fi
# check that no migrations are pending/ongoing for this tapepool
printmigrationstatus | grep $1 && echo 'Migrations still ongoing, aborting' && exit 1
# backup relevant metadata
mkdir -p ~/ctaexport
cd ~/ctaexport
[[ ! -x stager_listprivileges_output ]] && \
stager_listprivileges > stager_listprivileges_output && \
# pause the stager altogether (this destroys the B&W lists!)
stager_removeprivilege -U:
# on the stager, make the tapepool unusable (the tapepool metadata can stay)
[[ ! -x migrationroute_$1 }} && printmigrationroute | grep $1 > migrationroutes_$1
printmigrationroute | grep $1 | awk '{print $1}' | xargs -i deletemigrationroute {}
# on the VMGR, mark all tapes as Exported for the tape pool
vmgrlisttape -P $1 | awk '{print $1}' | xargs -i vmgrmodifytape -V {} --st EXPORTED
# execute the CTA DB extraction from the CTA DB
# (remote-linked with the CASTOR Nameserver)
# ...
# empty the CASTOR disk cache (not necessary)
#for h in `printdiskserver | grep cern.ch | awk '{print $1}'`; do
# for f in `seq -w 1 24`; do
# deletediskcopy $h:/srv/castor/$f/
# done
#done
# to resume the stager once everything is completed:
#stager_addprivilege -U:
#!/bin/sh
#/******************************************************************************
# * unexportctatocastor.sh
# *
# * This file is part of the Castor/CTA project.
# * See http://castor.web.cern.ch/castor
# *
# * Copyright (C) 2003 CERN
# * This program is free software; you can redistribute it and/or
# * modify it under the terms of the GNU General Public License
# * as published by the Free Software Foundation; either version 2
# * of the License, or (at your option) any later version.
# * This program is distributed in the hope that it will be useful,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# * GNU General Public License for more details.
# * You should have received a copy of the GNU General Public License
# * along with this program; if not, write to the Free Software
# * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# *
# * command line tool to undo the export of a tapepool metadata
# * to CTA by reenabling the tapes in CASTOR.
#
# * @author Castor Dev team, castor-dev@cern.ch
# *****************************************************************************/
# check arguments
if [ $# != 1 ]; then
echo usage: $0 tapepool
exit 1
fi
# assume the relevant metadata was stored here
cd ~/ctaexport || echo 'Metadata from a previous export not found, aborting' && exit 1
# on the stager, restore the migration routes
cat migrationroutes_$1 | grep -v FILECLASS | grep -v '---' | awk '{print "entermigrationroute " $1 " " $2 ":" $4}' | sh
# on the VMGR, mark all tapes back as available (but full == read-only) for the tape pool
vmgrlisttape -P $1 | awk '{print $1}' | xargs -i vmgrmodifytape -V {} --st TAPE_FULL
-- commit any previous pending session
COMMIT;
--------------------------------------------------
-- 1. Usage stats. This section should be ported
-- to PostgreSQL at some time in the future.
--------------------------------------------------
-- Table for namespace statistics. Same logic as in CASTOR.
CREATE TABLE UsageStats (
gid NUMBER(6) DEFAULT 0 CONSTRAINT NN_UsageStats_gid NOT NULL,
timestamp NUMBER DEFAULT 0 CONSTRAINT NN_UsageStats_ts NOT NULL,
maxFileId INTEGER, fileCount INTEGER, fileSize INTEGER,
segCount INTEGER, segSize INTEGER, segCompressedSize INTEGER,
seg2Count INTEGER, seg2Size INTEGER, seg2CompressedSize INTEGER
);
ALTER TABLE UsageStats ADD CONSTRAINT PK_UsageStats_gid_ts PRIMARY KEY (gid, timestamp);
-- This table will be used to safely store the legacy CASTOR usage statistics.
CREATE TABLE CastorUsageStats (
gid NUMBER(6) DEFAULT 0 CONSTRAINT NN_UsageStats_gid NOT NULL,
timestamp NUMBER DEFAULT 0 CONSTRAINT NN_UsageStats_ts NOT NULL,
maxFileId INTEGER, fileCount INTEGER, fileSize INTEGER,
segCount INTEGER, segSize INTEGER, segCompressedSize INTEGER,
seg2Count INTEGER, seg2Size INTEGER, seg2CompressedSize INTEGER
);
-- This table is used to store the mapping gid -> experiment name, like in CASTOR.
-- Still to be manually updated, in the lack of an automated mechanism.
CREATE TABLE EXPERIMENTS (
NAME VARCHAR2(20 BYTE),
GID NUMBER(6,0) CONSTRAINT GID_PK PRIMARY KEY (GID)
);
-- Helper procedure to insert/accumulate statistics in the UsageStats table
CREATE OR REPLACE PROCEDURE insertNSStats(inGid IN INTEGER, inTimestamp IN NUMBER,
inMaxFileId IN INTEGER, inFileCount IN INTEGER, inFileSize IN INTEGER,
inSegCount IN INTEGER, inSegSize IN INTEGER, inSegCompressedSize IN INTEGER,
inSeg2Count IN INTEGER, inSeg2Size IN INTEGER, inSeg2CompressedSize IN INTEGER) AS
CONSTRAINT_VIOLATED EXCEPTION;
PRAGMA EXCEPTION_INIT(CONSTRAINT_VIOLATED, -1);
BEGIN
INSERT INTO UsageStats (gid, timestamp, maxFileId, fileCount, fileSize, segCount, segSize,
segCompressedSize, seg2Count, seg2Size, seg2CompressedSize)
VALUES (inGid, inTimestamp, inMaxFileId, inFileCount, inFileSize, inSegCount, inSegSize,
inSegCompressedSize, inSeg2Count, inSeg2Size, inSeg2CompressedSize);
EXCEPTION WHEN CONSTRAINT_VIOLATED THEN
UPDATE UsageStats SET
maxFileId = CASE WHEN inMaxFileId > maxFileId THEN inMaxFileId ELSE maxFileId END,
fileCount = fileCount + inFileCount,
fileSize = fileSize + inFileSize,
segCount = segCount + inSegCount,
segSize = segSize + inSegSize,
segCompressedSize = segCompressedSize + inSegCompressedSize,
seg2Count = seg2Count + inSeg2Count,
seg2Size = seg2Size + inSeg2Size,
seg2CompressedSize = seg2CompressedSize + inSeg2CompressedSize
WHERE gid = inGid AND timestamp = inTimestamp;
END;
/
-- This procedure is run as a database job to generate statistics from the namespace
-- Taken as is from CASTOR, cf. https://gitlab.cern.ch/castor/CASTOR/tree/master/ns/oracleTrailer.sql
CREATE OR REPLACE PROCEDURE gatherCatalogueStats AS
varTimestamp NUMBER := trunc(getTime());
BEGIN
-- File-level statistics
FOR g IN (SELECT disk_file_gid, MAX(archive_file_id) maxId,
COUNT(*) fileCount, SUM(size_in_bytes) fileSize
FROM Archive_File
WHERE creation_time < varTimestamp
GROUP BY disk_file_gid) LOOP
insertNSStats(g.disk_file_gid, varTimestamp, g.maxId, g.fileCount, g.fileSize, 0, 0, 0, 0, 0, 0);
END LOOP;
COMMIT;
-- Tape-level statistics
FOR g IN (SELECT disk_file_gid, copy_nb, SUM(size_in_bytes) segComprSize,
SUM(size_in_bytes) segSize, COUNT(*) segCount
FROM Tape_File, Archive_File
WHERE Tape_File.archive_file_id = Archive_File.archive_file_id
AND Archive_File.creation_time < varTimestamp
GROUP BY disk_file_gid, copy_nb) LOOP
IF g.copy_nb = 1 THEN
insertNSStats(g.disk_file_gid, varTimestamp, 0, 0, 0, g.segCount, g.segSize, g.segComprSize, 0, 0, 0);
ELSE
insertNSStats(g.disk_file_gid, varTimestamp, 0, 0, 0, 0, 0, 0, g.segCount, g.segSize, g.segComprSize);
END IF;
END LOOP;
COMMIT;
-- Also compute totals
INSERT INTO UsageStats (gid, timestamp, maxFileId, fileCount, fileSize, segCount, segSize,
segCompressedSize, seg2Count, seg2Size, seg2CompressedSize)
(SELECT -1, varTimestamp, MAX(maxFileId), SUM(fileCount), SUM(fileSize),
SUM(segCount), SUM(segSize), SUM(segCompressedSize),
SUM(seg2Count), SUM(seg2Size), SUM(seg2CompressedSize)
FROM UsageStats
WHERE timestamp = varTimestamp);
COMMIT;
END;
/
/* Database job for the statistics */
BEGIN
-- Remove database jobs before recreating them
FOR j IN (SELECT job_name FROM user_scheduler_jobs
WHERE job_name = 'STATSJOB')
LOOP
DBMS_SCHEDULER.DROP_JOB(j.job_name, TRUE);
END LOOP;
-- Create a db job to be run every day executing the gatherNSStats procedure
DBMS_SCHEDULER.CREATE_JOB(
JOB_NAME => 'StatsJob',
JOB_TYPE => 'PLSQL_BLOCK',
JOB_ACTION => 'BEGIN gatherCatalogueStats(); END;',
JOB_CLASS => 'CASTOR_JOB_CLASS',
START_DATE => SYSDATE + 60/1440,
REPEAT_INTERVAL => 'FREQ=DAILY; INTERVAL=1',
ENABLED => TRUE,
COMMENTS => 'Gathering of catalogue usage statistics');
END;
/
---------------------------------------------
-- 2. CASTOR to CTA migration. This code is
-- only supported for Oracle.
---------------------------------------------
-- Create synonyms for all relevant tables
-- XXX TBD XXX
/* Function to convert seconds into a time string using the format:
* DD-MON-YYYY HH24:MI:SS. If seconds is not defined then the current time
* will be returned. Note that the time is converted from UTC to the
* currently defined time zone.
*/
CREATE OR REPLACE FUNCTION getTimeString
(seconds IN NUMBER DEFAULT NULL,
format IN VARCHAR2 DEFAULT 'DD-MON-YYYY HH24:MI:SS')
RETURN VARCHAR2 AS
BEGIN
RETURN (to_char(to_date('01-JAN-1970', 'DD-MON-YYYY') + (systimestamp - cast(sys_extract_utc(systimestamp) as date))
+ nvl(seconds, getTime()) / (60 * 60 * 24), format));
END;
/
-- Import metadata from the CASTOR namespace
CREATE OR REPLACE PROCEDURE importFromCASTOR(inTapePool VARCHAR2, inVO VARCHAR2, inEOSCTAInstance VARCHAR2,
Dirs OUT SYS_REFCURSOR, Files OUT SYS_REFCURSOR) AS
BEGIN
-- first import tapes
importTapePool(inTapePool, inVO);
-- XXX error handling is missing
castor.filesAndDirsForCTAExport(inTapePool);
-- import metadata into the CTA catalogue
populateCTAFromCASTOR(inEOSCTAInstance);
-- Get all metadata for the EOS-side namespace
OPEN Dirs FOR
SELECT * FROM castor.CTADirsHelper;
OPEN Files FOR
SELECT * FROM castor.CTAFilesHelper;
END;
/
CREATE OR REPLACE PROCEDURE populateCTAFromCASTOR(inEOSCTAInstance VARCHAR2) AS
pathInEos VARCHAR2;
ct INTEGER := 0;
BEGIN