/********************************************************************** * * MFFile.cpp * Copyright (C) 2003 UNESCO * * A component of the Greenstone digital library software * from the New Zealand Digital Library Project at the * University of Waikato, New Zealand. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * *********************************************************************/ //////////////////////////////////////////////////////////// // MfFile.cpp : Master file object methods using blocked I/O // //////////////////////////////////////////////////////////// #include "stdafx.h" #include "IsisDb.h" #include "Checking.h" //---------------------------------------------------------------------------------- // MfFile::MfFile() : // // Constructor, makes a Masterfile object that isn't connected to a file //---------------------------------------------------------------------------------- MfFile::MfFile() : BlkFile(), hdr_created_(false), nextaddr_(MFCTLLEN) { lastWrittenBlock_ = -1; } //---------------------------------------------------------------------------------- // int MfFile::OpenMf(const TCHAR *fname, // FileSystem::AccessMode mode /* = FileSystem::FILE_READWRITE */) // // Opens a Masterfile object //---------------------------------------------------------------------------------- int MfFile::OpenMf(const TCHAR *fname, FileSystem::AccessMode mode /* = FileSystem::FILE_READWRITE */) { int rc; try { rc = CFileBase::Open(fname, mode); hdr_created_ = true; ReadMfHdr(); PrintMfHdr(); Checking::CheckMfHeader(fname, mfh_); } catch (CFileBaseException e) { throw CIsisDbException(ISIS_MF_OPEN_ERROR, __FILE__, __LINE__); } return rc; } //---------------------------------------------------------------------------------- // int MfFile::createMf(const TCHAR *fname, int type) // // Creates a Masterfile object //---------------------------------------------------------------------------------- int MfFile::CreateMf(const TCHAR *fname, int type) { return 0; } ////////////////////////////// MfFile::~MfFile() { } //---------------------------------------------------------------------------------- // void MfFile::ReadMfRecord(long mfb, int mfp, MfRecord &m) // // Reads the master file record beginning at address (mfb,mfp) into m //---------------------------------------------------------------------------------- bool MfFile::ReadMfRecord(long mfb, int mfp, MfRecord &m) { return m.Read(*this, mfb, mfp); } //------------------------------------------------------------------------------- // void WriteMfRecord(long mfb, int mfp, MfRecord &m) // // Helper protected method, which writes the Master file record m at address // (mfb, mfp) mfb (1:MAXMFB), mfp (0: MFBLKSIZE) //------------------------------------------------------------------------------- void MfFile::WriteMfRecord(long mfb, int mfp, MfRecord &m) { m.Write(*this, mfb, mfp); } //-------------------------------------------------------------------------------- // void CreateMfRecord(MfRecord &m, long &mfb, int &mfp) // // Create a new record. The MFN to be assigned is obtained from the field nxtmfn_ // in the Master file header. Then addMfRecord is called for adding the record // at the end of the master file, at the position indicated by the fields // nxtmfb_/nxtmfb_. The next MFN to be assigned is updated. // //-------------------------------------------------------------------------------- void MfFile::CreateMfRecord(MfRecord &m, long &mfb, int &mfp) { } void MfFile::AppendNewBlock() { } //-------------------------------------------------------------------------------- // void AddMfRecord(MfRecord &m, long &mfb, int &mfp) // // Add the record at the end of the master file, at the position indicated by // the fields nxtmfb_/nxtmfp_. (nxtmfp_ is in range [1:MFBLKSIZE]) // Return the address where the record was stored into mfb & mfp //-------------------------------------------------------------------------------- void MfFile::AddMfRecord(MfRecord &m, long &mfb, int &mfp) { } //-------------------------------------------------------------------------------- // void UpdateMfRecord(MfRecord &m, long &mfb, int &mfp) // // Update a Master file record.If possible, i.e. if the record length was not // increased, the record is written back at its original location otherwise it is // written at the end of the file. In both cases, MFBWB/MFBWP are not changed. // //-------------------------------------------------------------------------------- void MfFile::UpdateMfRecord(MfRecord &m, long &mfb, int &mfp) { } ///////////////////////////////////////////////////////////////////////////////////// // methods for dumping file and record headers void MfFile::PrintMfHdr(SMfHeader &h) // Prints header record { } ////////////////////////////// void MfFile::PrintMfRecord(MfRecord &m) // Print a master file record structure { m.Dump(); } ///////////////////////////////////////////////////////////////////////////////////// // Methods for accessing records directly //---------------------------------------------------------------------------------- // void MfFile::ReadMfRecord(long daddr, MfRecord &m) // // Reads a master file record into the master record object m. // Non blocked version //---------------------------------------------------------------------------------- void MfFile::ReadMfRecord(long daddr, MfRecord &m) { m.Clear(); ReadLeader(daddr, m); // Read record leader (Leader is added to record) m.ExtractSubLeader(); //TRACE("\nReadMfRecord -- mfn=%ld mfrl=%d", m.GetMfn(), m.GetMfrl()); //assert(m.CheckIntegrity()); int mfrl = m.GetMfrl(); if (mfrl < 0) mfrl = -mfrl; // mfrl can be negative!!!! char* p = new char[mfrl]; CFileBase::Fetch(p, mfrl, daddr); m.AddToRecord(p+GetLeaderSize(), mfrl-GetLeaderSize()); delete[] p; nextaddr_ += mfrl; int mfb = nextaddr_ / MFBLKSIZE + 1; int mfp = nextaddr_ % MFBLKSIZE; if (mfp > MFBLKSIZE - GetMinLeaderSize()) { mfb++; mfp = 0; } nextaddr_ = (mfb-1)*MFBLKSIZE + mfp; m.DecomposeRecord(); } //--------------------------------------------------------------------------------- // void MfFile::WriteMfRecord(long daddr, MfRecord &m) // // Stores Master record object m to disk address daddr // Non blocked version //--------------------------------------------------------------------------------- void MfFile::WriteMfRecord(long daddr, MfRecord &m) { } ///////////////////////////////////////////////////////////////////////////////////// // Master file locking methods //----------------------------------------------------------------------------------- // void MfFile::InitFileLockHdr(SMfLockHeader &hdr) // // Initialize a the lock header for a newly constructed file lock header. //----------------------------------------------------------------------------------- void MfFile::InitFileLockHdr(SMfLockHeader &hdr) { hdr.lockProtect_ = (uint32_t)0; hdr.readLock_ = (uint32_t)0; hdr.writeLock_ = (uint32_t)0; } //----------------------------------------------------------------------------------- // FileError MfFile::WriteFileLockHdr(const SMfLockHeader &hdr) // // Write the lock header to the file. // Returns a non-zero value to indicate an error condition or zero if successful. //----------------------------------------------------------------------------------- FileError MfFile::WriteFileLockHdr(const SMfLockHeader &hdr) { return CFileBase::Store(&hdr, sizeof(SMfLockHeader), sizeof(SMfHeader)); } //----------------------------------------------------------------------------------- // FileError MfFile::ReadFileLockHdr(SMfLockHeader &hdr) // // Read the lock header from the file. // Returns a non-zero value to indicate an error condition or zero if successful. //----------------------------------------------------------------------------------- FileError MfFile::ReadFileLockHdr(SMfLockHeader &hdr) { return CFileBase::Fetch(&hdr, sizeof(SMfLockHeader), sizeof(SMfHeader)); } //----------------------------------------------------------------------------------- // int MfFile::LockFile(CFileMgrLockType l_type) // // Lock the file and set the lock access mode to shared or exclusive. // Returns a non-zero value if the file cannot be locked or the lock variable cannot // be changed because it is exclusive or another thread is currently updating it. //----------------------------------------------------------------------------------- int MfFile::LockFile(MfLockType l_type) { // Read the file lock to ensure that this file has a lock header // and to keep the header in sync during multiple file access. SMfLockHeader lock_header; if (ReadFileLockHdr(lock_header) != FILE_NO_ERROR) return fileError_; // Cannot modifiy this lock until the thread holding it releases the // lock header. if (lock_header.lockProtect_ != 0) { fileError_ = ISIS_MFLOCK_ACCESS_ERROR; #ifdef __CPP_EXCEPTIONS__ throw CFileBaseException(fileError_); #else return fileError_; #endif } switch (l_type) { case MF_WRITE_LOCK : // Cannot obtain an exclusive lock until all the threads in the // read lock queue have finished if ((lock_header.readLock_ != 0) || (lock_header.writeLock_ != 0)) { fileError_ = ISIS_MFLOCK_ERROR; #ifdef __CPP_EXCEPTIONS__ throw CFileBaseException(fileError_); #else return fileError_; #endif } else { lock_header.writeLock_ = 1; } lock_header.lockProtect_ = 1; if (CFileBase::Store(&lock_header.lockProtect_, sizeof(uint32_t), sizeof(SMfHeader)) != FILE_NO_ERROR) return fileError_; // Skip over the read lock member SeekTo(sizeof(SMfHeader) + (sizeof(uint32_t) * 2)); if (CFileBase::Store(&lock_header.writeLock_, sizeof(uint32_t)) != FILE_NO_ERROR) return fileError_; lock_header.lockProtect_ = (uint32_t)0; if (CFileBase::Store(&lock_header.lockProtect_, sizeof(uint32_t), sizeof(SMfHeader)) != FILE_NO_ERROR) return fileError_; break; case MF_READ_LOCK : // This lock is exclusively owned and cannot be read locked // until the thread holding this lock release the exclusive lock. if (lock_header.writeLock_ == 1) { fileError_ = ISIS_MFLOCK_ERROR; #ifdef __CPP_EXCEPTIONS__ throw CFileBaseException(fileError_); #else return fileError_; #endif } if (lock_header.readLock_ < 0xFFFFFFFF) { lock_header.readLock_++; } else { fileError_ = ISIS_MFLOCK_ERROR; #ifdef __CPP_EXCEPTIONS__ throw CFileBaseException(fileError_); #else return fileError_; #endif } lock_header.lockProtect_ = 1; if (CFileBase::Store(&lock_header.lockProtect_, sizeof(uint32_t), sizeof(SMfHeader)) != FILE_NO_ERROR) return fileError_; if (CFileBase::Store(&lock_header.readLock_, sizeof(uint32_t)) != FILE_NO_ERROR) return fileError_; lock_header.lockProtect_ = (uint32_t)0; if (CFileBase::Store(&lock_header.lockProtect_, sizeof(uint32_t), sizeof(SMfHeader)) != FILE_NO_ERROR) return fileError_; break; default: // Invalid lock type specified fileError_ = ISIS_INVALID_LOCK_TYPE; #ifdef __CPP_EXCEPTIONS__ throw CFileBaseException(fileError_); #else return fileError_; #endif } return fileError_ = fileError_ = FILE_NO_ERROR; } //----------------------------------------------------------------------------------- // int MfFile::UnlockFile(CFileMgrLockType l_type) // // Unlock the file. Returns a non-zero value if the file cannot be unlocked or the // lock variable cannot be changed because it is exclusive or another thread is // currently updating it. //----------------------------------------------------------------------------------- int MfFile::UnlockFile(MfLockType l_type) { // Read the file lock to ensure that this file has a lock header // and to keep the header in sync during multiple file access. SMfLockHeader lock_header; if (ReadFileLockHdr(lock_header) != FILE_NO_ERROR) return fileError_; // Cannot modifiy this lock until the thread holding it releases the // lock header. if (lock_header.lockProtect_ != 0) { fileError_ = ISIS_MFLOCK_ACCESS_ERROR; #ifdef __CPP_EXCEPTIONS__ throw CFileBaseException(fileError_); #else return fileError_; #endif } switch (l_type) { case MF_WRITE_LOCK : if (lock_header.writeLock_ == 0) return FILE_NO_ERROR; else lock_header.writeLock_ = 0; lock_header.lockProtect_ = 1; if (CFileBase::Store(&lock_header.lockProtect_, sizeof(uint32_t), sizeof(SMfHeader)) != FILE_NO_ERROR) return fileError_; // Skip over the read lock member SeekTo(sizeof(SMfHeader) + (sizeof(uint32_t) * 2)); if (CFileBase::Store(&lock_header.writeLock_, sizeof(uint32_t)) != FILE_NO_ERROR) return fileError_; lock_header.lockProtect_ = (uint32_t)0; if (CFileBase::Store(&lock_header.lockProtect_, sizeof(uint32_t), sizeof(SMfHeader)) != FILE_NO_ERROR) return fileError_; break; case MF_READ_LOCK : if (lock_header.readLock_ == 0) // This record is not locked return fileError_ = FILE_NO_ERROR; else if (lock_header.readLock_ > 0) // Prevent read lock rollover lock_header.readLock_--; else lock_header.readLock_ = 0; lock_header.lockProtect_ = 1; if (CFileBase::Store(&lock_header.lockProtect_, sizeof(uint32_t), sizeof(SMfHeader)) != FILE_NO_ERROR) return fileError_; if (CFileBase::Store(&lock_header.readLock_, sizeof(uint32_t)) != FILE_NO_ERROR) return fileError_; lock_header.lockProtect_ = (uint32_t)0; if (CFileBase::Store(&lock_header.lockProtect_, sizeof(uint32_t), sizeof(SMfHeader)) != FILE_NO_ERROR) return fileError_; break; default: // Invalid lock type specified fileError_ = FMGR_INVALID_LOCK_TYPE; #ifdef __CPP_EXCEPTIONS__ throw CFileBaseException(fileError_); #else return fileError_; #endif } return fileError_ = fileError_ = FILE_NO_ERROR; } //----------------------------------------------------------------------------------- // FileError MfFile::ResetFileLock() // // Reset the file's lock header. This function will clear all the file lock fields // without testing the lock or the lock protect. Returns a non-zero value to indicate // an error condition or zero if successful. //----------------------------------------------------------------------------------- FileError MfFile::ResetFileLock() { SMfLockHeader lock_header; InitFileLockHdr(lock_header); return WriteFileLockHdr(lock_header); }