/********************************************************************** * * MFFile.h * 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.H: Class definition for blocked I/O on the master // file //////////////////////////////////////////////////////////// #ifndef _MFFILE_H_ #define _MFFILE_H_ #ifndef _MASTER_H_ #include "Master.h" #endif #ifndef _BLKFILE_H_ #include "BlkFile.h" #endif #include enum MfLockType { MF_READ_LOCK, MF_WRITE_LOCK }; struct SMfLockHeader { long lockProtect_; // Serialize access to the file lock members long readLock_; // Shared (or read_only) file lock long writeLock_; // Exclusive (or write-only) file lock SMfLockHeader() : lockProtect_(0), readLock_(0), writeLock_(0) {} }; enum { USERMST=0, MSGMST=1 }; // binary hex // ------ --- // 0000 0 // 0001 1 // 0010 2 // 0011 3 class MfAddress { private: long m_mfb; short m_mfp; char m_status; public: MfAddress() { m_status = 0x00; } MfAddress(long mfb, short mfp) { ASSERT(mfb>0); ASSERT(mfp>=0); m_mfb = mfb; m_mfp = mfp; m_status = 0x03; } long getMfb() { ASSERT(m_status & 0x01); return m_mfb; } short getMfp() { ASSERT(m_status & 0x02); return m_mfp; } void setMfb(long mfb) { ASSERT(mfb>0); m_mfb = mfb; m_status |= 0x01; } void setMfp(short mfp) { ASSERT(mfp>=0); m_mfp = mfp; m_status |= 0x02; } bool isValid() { return (m_status == 0x03); } }; ///////////////////////////////////////////////////////////////////////// // Master File header record aggregate structure // struct SMfHeader { ISIS_LONG ctlmfn_; // Always 0 ISIS_LONG nxtmfn_; // MFN to be assigned to next record created ISIS_LONG nxtmfb_; // Last block number allocated (1st is 1) ISIS_INT nxtmfp_; // Offset to next available position in last block (1:MFBLKSIZE) ISIS_INT mftype_; // Type of master file (USERMST or MSGMST) ISIS_LONG reccnt_; ISIS_LONG mfcxx1_; ISIS_LONG mfcxx2_; ISIS_LONG mfcxx3_; public: SMfHeader(const char *dbname=""); ~SMfHeader() { } }; //-------------------------------------------------------------------------- // SMfHeader::SMfHeader(const char *dbname /* ="" */) // // Default constructor, initializes the Master file header to default values //-------------------------------------------------------------------------- inline SMfHeader::SMfHeader(const char *dbname /* ="" */) { ctlmfn_ = 0; nxtmfn_ = 1L; nxtmfb_ = 1L; nxtmfp_ = MFCTLLEN+1; mftype_ = USERMST; reccnt_ = mfcxx1_=mfcxx2_=mfcxx3_=0; } ////////////////////// // Master file class // class MfFile : public BlkFile { friend class IsisDb; friend class MfRecord; protected: SMfHeader mfh_; // Header structure long nextaddr_; // Address of next record char buf_[MFBLKSIZE]; // Buffer to hold 1 Master File block bool hdr_created_; // True if 1st block exists int fileError_; long lastWrittenBlock_; protected: void WriteMfRecord(long mfb, int mfp, MfRecord &r); void AppendNewBlock(); public: void setNextMfn(long mfn) // Set MFN to be assigned to next record created { mfh_.nxtmfn_ = mfn; } protected: void setNextMfb(long nxtmfb_) // Set last block number allocated (1st is 1) { mfh_.nxtmfb_ = nxtmfb_; } void setNextMfp(int nxtmfp_) // Set offset to next available position in last block { mfh_.nxtmfp_ = nxtmfp_; } int setm_mftype(int mftype_) // Set type of master file (USERMST or MSGMST) { mfh_.mftype_ = mftype_; } virtual void ReadBlk(void* d, long b) { BlkFile::ReadBlk(d, b); } virtual void WriteBlk(void* d, long b) { BlkFile::WriteBlk(d, b); } void ReadMfHdr(SMfHeader &h); void ReadMfHdr(); void WriteMfHdr(SMfHeader &h); void WriteMfHdr(); void SetLastWrittenBlock(long b) { lastWrittenBlock_ = b; } public: MfFile(); virtual ~MfFile(); int OpenMf(const TCHAR* name, FileSystem::AccessMode mode = FileSystem::FILE_READWRITE); int CreateMf(const TCHAR* name, int MSTtype = USERMST); void CloseMf() { if (ReadyForWriting()) WriteMfHdr(); Close(); } // Accessors for the Master File Header long GetNextMfn() // Get MFN to be assigned to next record created { return mfh_.nxtmfn_; } long GetNextMfb() // Get last block number allocated (1st is 1) { return mfh_.nxtmfb_; } int GetNextMfp() // Get offset to next available position in last block { return mfh_.nxtmfp_; } int GetMftype() // Get type of master file (USERMST or MSGMST) { return mfh_.mftype_; } SMfHeader& GetSMfHeader() { return mfh_; } void CreateMfRecord(MfRecord &m, long &mfb, int &mfp); void AddMfRecord(MfRecord &m, long &mfb, int &mfp); void UpdateMfRecord(MfRecord &m, long &mfb, int &mfp); bool ReadMfRecord(long mfb, int mfp, MfRecord &r); void ReadMfRecord(long addr, MfRecord &r); void WriteMfRecord(long addr, MfRecord &r); void RewindMf(); bool ReadMfNext(MfRecord &r); void WriteMfNext(MfRecord &r); void ReadLeader(long daddr, MfRecord& m) { m.ReadLeader(*this, daddr); } void LockMfHdr(); void UnlockMfHdr(); void LockMfr(long mfn); void UnlockMfr(long mfn); public: // File lock functions void InitFileLockHdr(SMfLockHeader &hdr); FileError ResetFileLock(); FileError WriteFileLockHdr(const SMfLockHeader &hdr); FileError ReadFileLockHdr(SMfLockHeader &hdr); int LockFile(MfLockType l_type = MF_WRITE_LOCK); int UnlockFile(MfLockType l_type = MF_WRITE_LOCK); void PrintMfRecord(MfRecord &r); void PrintMfHdr(SMfHeader &h); void PrintMfHdr(); }; class CMfIterator { const MfFile& m_mf; long cur; public: CMfIterator(const MfFile& mf) : m_mf(mf) { } bool More() const; void Advance(); MfRecord Current() { MfRecord mfr(NULL); return mfr; } }; ////////////////////////////// inline void MfFile::LockMfHdr() // Locks the master file header record { double_t dwPos = 0; double_t dwCount = sizeof(SMfHeader); //CFile::LockRange(dwPos, dwCount); } ////////////////////////////// inline void MfFile::UnlockMfHdr() // Unlocks the master file header record { double_t dwPos = 0; double_t dwCount = sizeof(SMfHeader); //CFile::UnlockRange(dwPos, dwCount); } ////////////////////////////// inline void MfFile::ReadMfHdr() // Reads the master file header record { ReadBlk(buf_, 1L); TRACE(_T("\nsizeof(SMfHeader)=%d"), sizeof(SMfHeader)); ::MoveMemory(&mfh_, buf_, sizeof(SMfHeader)); } ////////////////////////////// inline void MfFile::WriteMfHdr() // Updates the master file header record { if (hdr_created_) ReadBlk(buf_, 1L); TRACE(_T("\nsizeof(SMfHeader)=%d"), sizeof(SMfHeader)); ::MoveMemory(buf_, &mfh_, sizeof(SMfHeader)); WriteBlk(buf_, 1L); } ////////////////////////////// inline void MfFile::ReadMfHdr(SMfHeader &h) // Reads the master file header record { ReadBlk(buf_, 1L); ::MoveMemory(&h, buf_, sizeof(SMfHeader)); } ////////////////////////////// inline void MfFile::WriteMfHdr(SMfHeader &h) // Updates the master file header record { if (hdr_created_) ReadBlk(buf_, 1L); ::MoveMemory(buf_, &h, sizeof(SMfHeader)); WriteBlk(buf_, 1L); } inline void MfFile::PrintMfHdr() { PrintMfHdr(mfh_); } ////////////////////////////// inline bool MfFile::ReadMfNext(MfRecord &r) // Reads the next physically record { if (nextaddr_ >= CFileBase::FileSize(file_name)) return false; ReadMfRecord(nextaddr_, r); return true; } ////////////////////////////// inline void MfFile::WriteMfNext(MfRecord &r) // Writes physically at next position { WriteMfRecord(nextaddr_, r); } #endif