///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoCheckpointDump.cc
// ---------------------
// Cego checkpoint dump implementation module
//
// Design and Implementation by Bjoern Lemke               
//     
// (C)opyright 2000-2025 Bjoern Lemke
//
// IMPLEMENTATION MODULE
//
// Class: CegoCheckpointDump
// 
// Description: The checkpoint dump handler class
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

// LFC INCLUDES
#include <lfcbase/Exception.h>

// CEGO INCLUDES
#include "CegoCheckpointDump.h"

extern bool __fsyncOn;

CegoCheckpointDump::CegoCheckpointDump(const Chain& tableSet, const Chain& tsRoot, unsigned pageSize)
{
    _tableSet = tableSet;
    _tsRoot = tsRoot;
    _pageSize = pageSize;
    _pDumpFile = 0;
}

void CegoCheckpointDump::startWrite()
{
    if ( _pDumpFile )
    {
	throw Exception(EXLOC, "Checkpoint dumpfile already open");
    }
    Chain dumpFileName = _tsRoot + Chain("/") + Chain(CHECKPOINTDUMPFILE) + Chain("_") + _tableSet + Chain(DUMP_PROCESS_POSTFIX);
    _pDumpFile = new File(dumpFileName);
    if ( _pDumpFile->exists() )
    {
	throw Exception(EXLOC, "Checkpoint dumpfile already exists");
    }
    _pDumpFile->open(File::WRITE);
}

void CegoCheckpointDump::dumpPage(PageIdType pageId, unsigned fixStat, char* pageData)
{
    if ( _pDumpFile )
    {
	_pDumpFile->writeByte((char*)&pageId, sizeof(PageIdType));
	_pDumpFile->writeByte((char*)&fixStat, sizeof(unsigned));
	_pDumpFile->writeByte(pageData, _pageSize);
    }
    else
    {
	throw Exception(EXLOC, "No checkpoint dumpfile open for write");
    }			     
}

void CegoCheckpointDump::finish()
{
    if ( _pDumpFile )
    {
	if ( __fsyncOn )
	    _pDumpFile->flush();
	_pDumpFile->close();
    }
}

void CegoCheckpointDump::commitDump()
{
    Chain dumpFileName = _tsRoot + Chain("/") + Chain(CHECKPOINTDUMPFILE) + Chain("_") + _tableSet + Chain(DUMP_PROCESS_POSTFIX);
    _pDumpFile = new File(dumpFileName);
    if ( _pDumpFile->exists() == false )
    {
	throw Exception(EXLOC, "Checkpoint dumpfile does not exist");
    }
    
    Chain readyFileName = _tsRoot + Chain("/") + Chain(CHECKPOINTDUMPFILE) + Chain("_") + _tableSet + Chain(DUMP_READY_POSTFIX);
    _pDumpFile->rename(readyFileName);
    delete _pDumpFile;
    _pDumpFile = 0;
}

void CegoCheckpointDump::startRead()
{
    if ( _pDumpFile )
    {
	throw Exception(EXLOC, "Checkpoint dumpfile already open");
    }

    Chain readyFileName = _tsRoot + Chain("/") + Chain(CHECKPOINTDUMPFILE) + Chain("_") + _tableSet + Chain(DUMP_READY_POSTFIX);
    _pDumpFile = new File(readyFileName);
    if ( _pDumpFile->exists() == false )
    {
	throw Exception(EXLOC, "Checkpoint dumpfile not available for read");
    }
    _pDumpFile->open(File::READ);   
}

bool CegoCheckpointDump::readDump(PageIdType& pageId, unsigned& fixStat, char* pageData)
{
    if ( _pDumpFile == 0 )
    {      
	throw Exception(EXLOC, "No checkpoint dumpfile open for read");
    }			     

    unsigned long readCount = 0;
    readCount = _pDumpFile->readByte((char*)&pageId, sizeof(PageIdType));
    if ( readCount ==  0 )
	return false;

    readCount += _pDumpFile->readByte((char*)&fixStat, sizeof(unsigned));
    readCount += _pDumpFile->readByte(pageData, _pageSize);

    if ( readCount != sizeof(PageIdType) + sizeof(unsigned) + _pageSize )
	throw Exception(EXLOC, "Checkpoint dump incomplete");
    
    return true;    
}

void CegoCheckpointDump::remove()
{
    if ( _pDumpFile )
    {
	_pDumpFile->close();
	_pDumpFile->remove();	
	delete _pDumpFile;
    }
    else
    {
	throw Exception(EXLOC, "Checkpoint dumpfile not open for end");
    }
}

bool CegoCheckpointDump::readyDumpExists()
{
    Chain readyFileName = _tsRoot + Chain("/") + Chain(CHECKPOINTDUMPFILE) + Chain("_") + _tableSet + Chain(DUMP_READY_POSTFIX);
    File checkFile(readyFileName);
    return checkFile.exists();	
}

void CegoCheckpointDump::cleanUp()
{
    Chain processFileName = _tsRoot + Chain("/") + Chain(CHECKPOINTDUMPFILE) + Chain("_") + _tableSet + Chain(DUMP_PROCESS_POSTFIX);
    File checkProcessFile(processFileName);
    if ( checkProcessFile.exists() )
	checkProcessFile.remove();

    Chain readyFileName = _tsRoot + Chain("/") + Chain(CHECKPOINTDUMPFILE) + Chain("_") + _tableSet + Chain(DUMP_READY_POSTFIX);
    File checkReadyFile(readyFileName);
    if ( checkReadyFile.exists() )
	checkReadyFile.remove();
}
