Commit 8edc31f4 authored by Daniele Kruse's avatar Daniele Kruse
Browse files

Added positioning by fseq plus a few cosmetic changes (more uniform to the rest CASTOR)

parent 13698e5a
......@@ -391,12 +391,15 @@ void drives::DriveGeneric::rewind(void) throw (Exception) {
* @param count
*/
void drives::DriveGeneric::spaceFileMarksBackwards(size_t count) throw (Exception) {
size_t tobeskipped = count;
struct mtop m_mtCmd;
m_mtCmd.mt_op = MTBSF;
m_mtCmd.mt_count = (int)count;
castor::exception::Errnum::throwOnMinusOne(
m_sysWrapper.ioctl(m_tapeFD, MTIOCTOP, &m_mtCmd),
"Failed ST ioctl (MTBSF) in DriveGeneric::spaceFileMarksBackwards");
while (tobeskipped > 0) {
size_t c = (tobeskipped > 0x7FFFFF) ? 0x7FFFFF : tobeskipped;
m_mtCmd.mt_count = (int)c;
castor::exception::Errnum::throwOnMinusOne(m_sysWrapper.ioctl(m_tapeFD, MTIOCTOP, &m_mtCmd), "Failed ST ioctl (MTBSF) in DriveGeneric::spaceFileMarksBackwards");
tobeskipped -= c;
}
}
/**
......@@ -404,12 +407,15 @@ void drives::DriveGeneric::spaceFileMarksBackwards(size_t count) throw (Exceptio
* @param count
*/
void drives::DriveGeneric::spaceFileMarksForward(size_t count) throw (Exception) {
size_t tobeskipped = count;
struct mtop m_mtCmd;
m_mtCmd.mt_op = MTFSF;
m_mtCmd.mt_count = (int)count;
castor::exception::Errnum::throwOnMinusOne(
m_sysWrapper.ioctl(m_tapeFD, MTIOCTOP, &m_mtCmd),
"Failed ST ioctl (MTFSF) in DriveGeneric::spaceFileMarksForward");
while (tobeskipped > 0) {
size_t c = (tobeskipped > 0x7FFFFF) ? 0x7FFFFF : tobeskipped;
m_mtCmd.mt_count = (int)c;
castor::exception::Errnum::throwOnMinusOne(m_sysWrapper.ioctl(m_tapeFD, MTIOCTOP, &m_mtCmd), "Failed ST ioctl (MTFSF) in DriveGeneric::spaceFileMarksForward");
tobeskipped -= c;
}
}
/**
......@@ -458,15 +464,17 @@ void drives::DriveGeneric::unloadTape(void) throw (Exception) {
/**
* Synch call to the tape drive. This function will not return before the
* data in the drive's buffer is actually comitted to the medium.
* data in the drive's buffer is actually committed to the medium.
*/
void drives::DriveGeneric::sync(void) throw (Exception) {
void drives::DriveGeneric::flush(void) throw (Exception) {
struct mtop m_mtCmd;
m_mtCmd.mt_op = MTNOP; //The side effect of the no-op is to actually flush the driver's buffer to tape (see "man st").
m_mtCmd.mt_count = 1;
m_mtCmd.mt_op = MTWEOF; //Not using MTNOP because it doesn't do what it claims (see st source code) so here we put "write sync file marks" with count set to 0.
// The following text is a quote from the SCSI Stream commands manual (SSC-3):
// NOTE 25 Upon completion of any buffered write operation, the application client may issue a WRITE FILEMARKS(16) command with the IMMED bit set to zero and the FILEMARK COUNT field set to zero to perform a synchronize operation (see 4.2.10).
m_mtCmd.mt_count = 0;
castor::exception::Errnum::throwOnMinusOne(
m_sysWrapper.ioctl(m_tapeFD, MTIOCTOP, &m_mtCmd),
"Failed ST ioctl (MTNOP) in DriveGeneric::sync");
"Failed ST ioctl (MTWEOF) in DriveGeneric::flush");
}
/**
......
......@@ -313,7 +313,7 @@ namespace drives {
* Synch call to the tape drive. This function will not return before the
* data in the drive's buffer is actually comitted to the medium.
*/
virtual void sync(void) throw (Exception);
virtual void flush(void) throw (Exception);
/**
* Write count file marks. The function does not return before the file marks
......
......@@ -314,7 +314,7 @@ int main ()
print_and_assert_position(drive, 11);
std::cout << "Synch-ing..." << std::endl;
drive.sync(); // flush buffer with no-op
drive.flush(); // flush buffer with no-op
print_and_assert_position(drive, 11);
std::cout << "Rewinding..." << std::endl;
......
This diff is collapsed.
......@@ -33,11 +33,25 @@ namespace castor {
* Class managing the reading and writing of files to and from tape.
*/
namespace AULFile {
enum PositioningMode
{
ByBlockId,
ByFSeq
};
enum PartOfFile
{
Header,
Payload,
Trailer
};
/**
* Class containing all the information related to a file being migrated to
* tape.
*/
class Information { //no information about path and filename here as it cannot be used nor checked on tape
class FileInfo { //no information about path and filename here as it cannot be used nor checked on tape
public:
uint32_t checksum;
uint64_t nsFileId;
......@@ -81,22 +95,28 @@ namespace castor {
ZeroFileWritten(): Exception("Trying to write a file with size 0") {}
};
class UnsupportedPositioningMode: public Exception {
public:
UnsupportedPositioningMode(): Exception("Trying to use an unsupported positioning mode") {}
};
class HeaderChecker {
public:
/**
* Checks the field of a header comparing it with the numerical value provided
* Checks the hdr1
* @param hdr1: the hdr1 header of the current file
* @param fileInfo: the Information structure of the current file
* @param volId: the volume id of the tape in the drive
*/
static void checkHDR1(const HDR1 &hdr1, const Information &fileInfo, const std::string &volId) throw (Exception);
static void checkHDR1(const HDR1 &hdr1, const FileInfo &fileInfo, const std::string &volId) throw (Exception);
/**
* Checks the uhl1
* @param uhl1: the uhl1 header of the current file
* @param fileInfo: the Information structure of the current file
*/
static void checkUHL1(const UHL1 &uhl1, const Information &fileInfo) throw (Exception);
static void checkUHL1(const UHL1 &uhl1, const FileInfo &fileInfo) throw (Exception);
/**
* Checks the utl1
......@@ -106,12 +126,9 @@ namespace castor {
static void checkUTL1(const UTL1 &utl1, const uint32_t fseq) throw (Exception);
/**
* checks the volume label to make sure the label is valid and that we
* have the correct tape (checks VSN). Leaves the tape at the end of the
* first header block (i.e. right before the first data block) in case
* of success, or rewinds the tape in case of volume label problems.
* Might also leave the tape in unknown state in case any of the st
* operations fail.
* Checks the vol1
* @param vol1: the vol1 header of the current file
* @param volId: the volume id of the tape in the drive
*/
static void checkVOL1(const VOL1 &vol1, const std::string &volId) throw (Exception);
......@@ -125,7 +142,7 @@ namespace castor {
* @param is_field_oct: set to true if the value in the header is in octal and to false otherwise
* @return true if the header field matches the numerical value, false otherwise
*/
static bool checkHeaderNumericalField(const std::string &headerField, const uint64_t &value, bool is_field_hex=false, bool is_field_oct=false) throw (Exception);
static bool checkHeaderNumericalField(const std::string &headerField, const uint64_t value, const bool is_field_hex=false, const bool is_field_oct=false) throw (Exception);
};
/**
......@@ -134,41 +151,68 @@ namespace castor {
* and check for everything to be coherent. The tape should be mounted in
* the drive before the AULReadSession is started (i.e. constructed).
* Likewise, tape unmount is the business of the user.
*/
*/
class ReadSession {
public:
/**
* Constructor of the ReadSession. It will rewind the tape, and check the
* VSN value. Throws an exception in case of mismatch.
* volId value. Throws an exception in case of mismatch.
* @param drive: drive object to which we bind the session
* @param volId: volume name of the tape we would like to read from
* @param vid: volume name of the tape we would like to read from
*/
ReadSession(drives::DriveGeneric & drive, std::string volId) throw (Exception);
ReadSession(drives::DriveGeneric & drive, const std::string &vid) throw (Exception);
/**
* DriveGeneric object referencing the drive used during this read session
*/
drives::DriveGeneric & dg;
drives::DriveGeneric & m_drive;
/**
* Volume Serial Number
*/
std::string VSN;
const std::string m_vid;
/**
* Session lock to be sure that a read session is owned by maximum one ReadFile object
*/
bool lock;
void setCorrupted() throw() {
m_corrupted = true;
}
bool isCorrupted() throw() {
return m_corrupted;
}
void setCorrupted() {
corrupted = true;
void lock() throw (Exception) {
if(m_locked) {
throw SessionAlreadyInUse();
}
if(m_corrupted) {
throw SessionCorrupted();
}
m_locked = true;
}
bool isCorrupted() {
return corrupted;
void release() throw() {
if(!m_locked) {
m_corrupted = true;
}
m_locked = false;
}
void setCurrentFseq(uint32_t fseq) {
m_fseq = fseq;
}
uint32_t getCurrentFseq() {
return m_fseq;
}
void setCurrentFilePart(PartOfFile currentFilePart) {
m_currentFilePart = currentFilePart;
}
PartOfFile getCurrentFilePart() {
return m_currentFilePart;
}
private:
......@@ -176,7 +220,22 @@ namespace castor {
/**
* set to true in case the destructor of ReadFile finds a missing lock on its session
*/
bool corrupted;
bool m_corrupted;
/**
* Session lock to be sure that a read session is owned by maximum one ReadFile object
*/
bool m_locked;
/**
* Current fSeq, used only for positioning by fseq
*/
uint32_t m_fseq;
/**
* Part of the file we are reading
*/
PartOfFile m_currentFilePart;
};
class ReadFile{
......@@ -188,13 +247,14 @@ namespace castor {
* and position the tape right at the beginning of the file
* @param rs: session to be bound to
* @param fileInfo: information about the file we would like to read
* @param positioningMode: method used when positioning (see the PositioningMode enum)
*/
ReadFile(ReadSession *rs, const Information &fileInfo) throw (Exception);
ReadFile(ReadSession *rs, const FileInfo &fileInfo, const PositioningMode positioningMode) throw (Exception);
/**
* Destructor of the ReadFile. It will release the lock on the read session.
*/
~ReadFile() throw (Exception);
~ReadFile() throw ();
/**
* After positioning at the beginning of a file for readings, this function
......@@ -204,18 +264,13 @@ namespace castor {
size_t getBlockSize() throw (Exception);
/**
* Read data from the file. The buffer should equal to or bigger than the
* block size. Will try to actually fill up the provided buffer (this
* function can trigger several read on the tape side).
* This function will throw exceptions when problems arise (especially
* at end of file in case of size or checksum mismatch.
* After end of file, a new call to read without a call to position
* will throw NotReadingAFile.
* @param buff pointer to the data buffer
* @param len size of the buffer
* Reads data from the file. The buffer should be equal to or bigger than the
* block size.
* @param data: pointer to the data buffer
* @param size: size of the buffer
* @return The amount of data actually copied. Zero at end of file.
*/
size_t read(void * buff, size_t len) throw (Exception);
size_t read(void *data, const size_t size) throw (Exception);
private:
......@@ -224,10 +279,9 @@ namespace castor {
* it is the duty of this function to determine how to best move to the next
* file. The positioning will then be verified (header will be read).
* As usual, exception is thrown if anything goes wrong.
* @param fileInfo: all relevant information passed by the stager about
* the file.
* @param fileInfo: all relevant information passed by the stager about the file.
*/
void position(const Information &fileInfo) throw (Exception);
void position(const FileInfo &fileInfo) throw (Exception);
/**
* Set the block size member using the info contained within the uhl1
......@@ -239,12 +293,17 @@ namespace castor {
/**
* Block size in Bytes of the current file
*/
size_t current_block_size;
size_t m_currentBlockSize;
/**
* Session to which we are attached to
*/
ReadSession *session;
ReadSession *m_session;
/**
* Mode with which the positioning for reading a file is done
*/
PositioningMode m_positioningMode;
};
/**
......@@ -267,55 +326,57 @@ namespace castor {
* @param last_fseq: fseq of the last active (undeleted) file on tape
* @param compression: set this to true in case the drive has compression enabled (x000GC)
*/
WriteSession(drives::DriveGeneric & drive, std::string volId, uint32_t last_fseq, bool compression) throw (Exception);
WriteSession(drives::DriveGeneric & drive, const std::string &vid, const uint32_t last_fseq, const bool compression) throw (Exception);
/**
* DriveGeneric object referencing the drive used during this write session
*/
drives::DriveGeneric & dg;
drives::DriveGeneric & m_drive;
/**
* Volume Serial Number
*/
std::string VSN;
/**
* Session lock to be sure that a write session is owned by maximum one WriteFile object
*/
bool lock;
std::string m_vid;
/**
* set to true if the drive has compression enabled
*/
bool compressionEnabled;
bool m_compressionEnabled;
std::string getSiteName() throw() {
return siteName;
return m_siteName;
}
std::string getHostName() throw() {
return hostName;
return m_hostName;
}
void setCorrupted() {
corrupted = true;
void setCorrupted() throw() {
m_corrupted = true;
}
bool isCorrupted() {
return corrupted;
bool isCorrupted() throw() {
return m_corrupted;
}
private:
void lock() throw (Exception) {
if(m_locked) {
throw SessionAlreadyInUse();
}
if(m_corrupted) {
throw SessionCorrupted();
}
m_locked = true;
}
/**
* checks the volume label to make sure the label is valid and that we
* have the correct tape (checks VSN). Leaves the tape at the end of the
* first header block (i.e. right before the first data block) in case
* of success, or rewinds the tape in case of volume label problems.
* Might also leave the tape in unknown state in case any of the st
* operations fail.
*/
void checkVOL1() throw (Exception);
void release() throw() {
if(!m_locked) {
m_corrupted = true;
}
m_locked = false;
}
private:
/**
* looks for the site name in /etc/resolv.conf in the search line and saves the upper-cased value in siteName
......@@ -330,17 +391,22 @@ namespace castor {
/**
* The following two variables are needed when writing the headers and trailers, sitename is grabbed from /etc/resolv.conf
*/
std::string siteName;
std::string m_siteName;
/**
* hostname is instead gotten from gethostname()
*/
std::string hostName;
std::string m_hostName;
/**
* set to true in case the write operations do (or try to do) something illegal
*/
bool corrupted;
bool m_corrupted;
/**
* Session lock to be sure that a read session is owned by maximum one WriteFile object
*/
bool m_locked;
};
class WriteFile {
......@@ -353,7 +419,7 @@ namespace castor {
* @param fileInfo: information about the file we want to read
* @param blockSize: size of blocks we want to use in writing
*/
WriteFile(WriteSession *ws, Information fileinfo, size_t blockSize) throw (Exception);
WriteFile(WriteSession *ws, const FileInfo fileinfo, const size_t blockSize) throw (Exception);
/**
* Returns the block id of the current position
......@@ -366,7 +432,7 @@ namespace castor {
* @param data: buffer to copy the data from
* @param size: size of the buffer
*/
void write(const void *data, size_t size) throw (Exception);
void write(const void *data, const size_t size) throw (Exception);
/**
* Closes the file by writing the corresponding trailer on tape
......@@ -376,40 +442,40 @@ namespace castor {
/**
* Destructor of the WriteFile object. Releases the WriteSession
*/
~WriteFile() throw (Exception);
~WriteFile() throw ();
private:
/**
* Block size in Bytes of the current file
*/
size_t current_block_size;
size_t m_currentBlockSize;
/**
* Session to which we are attached to
*/
WriteSession *session;
WriteSession *m_session;
/**
* Information that we have about the current file to be written and that
* will be used to write appropriate headers and trailers
*/
Information fileinfo;
FileInfo m_fileinfo;
/**
* set to true whenever the constructor is called and to false when close() is called
*/
bool open;
bool m_open;
/**
* set to false initially, set to true after at least one successful nonzero writeBlock operation
*/
bool nonzero_file_written;
bool m_nonzeroFileWritten;
/**
* number of blocks written for the current file
*/
int number_of_blocks;
int m_numberOfBlocks;
};
};
}
......
......@@ -87,7 +87,7 @@ int main(int argc, char* argv[])
std::cin.ignore();
if(choice==1) {
castor::tape::AULFile::Information info;
castor::tape::AULFile::FileInfo info;
std::cout << "Please enter the blockId: ";
std::string blockId;
std::cin >> blockId;
......@@ -109,7 +109,7 @@ int main(int argc, char* argv[])
std::cout << "Please enter the size of the file: ";
std::cin >> info.size;
std::cin.ignore();
castor::tape::AULFile::ReadFile file(&my_sess,info);
castor::tape::AULFile::ReadFile file(&my_sess, info, castor::tape::AULFile::ByBlockId);
std::cout << "Tape positioned at the beginning of the file\n";
size_t bs = file.getBlockSize();
std::cout << "Block size: " << bs << std::endl;
......
......@@ -34,10 +34,11 @@
#include <fstream>
#include <sstream>
#include <iomanip>
#include <memory>
//- 1 1 V92002 1 00000000 748 100 adler32 108deddb 5001074305 /castor/cern.ch/de
void fill_info(castor::tape::AULFile::Information *fileInfo, const std::string volId, const uint32_t fseq) {
void fill_info(castor::tape::AULFile::FileInfo *fileInfo, const std::string volId, const uint32_t fseq) {
std::string disabled, copy_no, seg_no, volId_str, fseq_str, blockId_str, size_str, compr_fact, checksum_name, checksum_str, nsFileId_str, path;
std::ifstream resolv;
std::string filename("nslisttape_" + volId + ".txt");
......@@ -126,23 +127,22 @@ int main(int argc, char* argv[])
if(read_sess!=NULL and write_sess!=NULL) {
for(unsigned int i=0; i<no_of_files; i++) {
try {
castor::tape::AULFile::Information info;
castor::tape::AULFile::FileInfo info;
fill_info(&info, src_tape, i);
castor::tape::AULFile::ReadFile input_file(read_sess, info);
castor::tape::AULFile::ReadFile input_file(read_sess, info, castor::tape::AULFile::ByBlockId);
size_t blockSize = input_file.getBlockSize();
castor::tape::AULFile::WriteFile output_file(write_sess, info, blockSize);
char *buf = new char[blockSize];
std::auto_ptr<char> buf(new char[blockSize]);
size_t bytes_read = 0;
try {
while(true) {
bytes_read = input_file.read(buf, blockSize);
output_file.write(buf, bytes_read);
bytes_read = input_file.read(buf.get(), blockSize);
output_file.write(buf.get(), bytes_read);
}
}
catch (castor::tape::AULFile::EndOfFile &e) {
}
output_file.close();
delete[] buf;
}
catch (std::exception & e) {
fail = 1;
......@@ -150,7 +150,9 @@ int main(int argc, char* argv[])
<< e.what() << std::endl
<< "----------------------------------------------" << std::endl;
}
}
}
delete read_sess;
delete write_sess;
}
return fail;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment