Public Member Functions | Protected Member Functions | Private Member Functions | Private Attributes

bea_RecallThread Class Reference
[IVD Back-End Agent]

#include <bea_recall.h>

Inheritance diagram for bea_RecallThread:
Inheritance graph
[legend]
Collaboration diagram for bea_RecallThread:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 bea_RecallThread (i_BackEndAgent_i &a_bea, bea_Drive *const a_drive_p, bool a_firstCall)

Protected Member Functions

virtual ~bea_RecallThread ()

Private Member Functions

virtual void Run (void *arg)
void Recall ()
void MultiRecall ()

Private Attributes

 log_CLASSID_m
i_BackEndAgent_im_bea
bea_Drivem_drive_p
bea_Volumem_vol_p
UInt64_t m_dataAmount
i_CompletionStatus_e m_status
bool m_multi
bool m_firstCall

Detailed Description

Definition at line 47 of file bea_recall.h.


Constructor & Destructor Documentation

bea_RecallThread::bea_RecallThread ( i_BackEndAgent_i a_bea,
bea_Drive *const   a_drive_p,
bool  a_firstCall 
)

Definition at line 59 of file bea_recall.cpp.

References cmn_ThreadCounter::Inc(), log_FUNC_m, m_bea, and i_BackEndAgent_i::m_threadCounter.

Here is the call graph for this function:

bea_RecallThread::~bea_RecallThread (  )  [protected, virtual]

Definition at line 78 of file bea_recall.cpp.

References bea_Drive::Close(), dbg_LOW, cmn_ThreadCounter::Dec(), i_BackEndAgent_i::GetBEANumber(), i_BackEndAgent_i::GetJob(), ipc_EXEC_m, i_BackEndAgent_i::IsAborted(), log_DBG_m, log_FUNC_m, m_bea, m_drive_p, m_status, i_BackEndAgent_i::m_threadCounter, and NULL.

                                    {

    log_FUNC_m(~bea_RecallThread);

    // Decrease the counter imediatelly, because the job might imediatelly call
    // UseResources().
    m_bea.m_threadCounter.Dec();

    // Close the device before contactacting job
    if (m_drive_p != NULL) {
        m_drive_p->Close();
    }

    // Complete job
    try {
        if (m_bea.IsAborted()) {
            log_DBG_m(dbg_LOW, "Recall aborted. Won't contact job.");
        }
        else {
            ipc_EXEC_m(
                if( !CORBA::is_nil(m_bea.GetJob()) ) {
                    log_DBG_m(dbg_LOW, "Completion status: " << m_status);
                    i_Job_var job = m_bea.GetJob();
                    job->MediumOperationComplete(m_bea.GetBEANumber(), m_status);
                };
            );
        }
    }
    catch(...) {
        // Ignore all exceptions at this point.
    }
}

Here is the call graph for this function:


Member Function Documentation

void bea_RecallThread::MultiRecall (  )  [private]
void bea_RecallThread::Recall (  )  [private]

Definition at line 195 of file bea_recall.cpp.

References bea_OPREAD, bea_Medium::ChangeVolume(), df_Filter::CheckLeftovers(), cmn_GetEnvVariable(), cmn_Num2Str(), cmn_Str2Num(), dbg_DETAIL, dbg_LOW, dbg_NORM, file_creation_threshold_c(), bea_Volume::GetBlockSize(), i_BackEndAgent_i::GetBufferID(), bea_Medium::GetCurrentVolume(), bea_Medium::GetCurVolNumber(), i_BackEndAgent_i::GetDiskBufferFS(), i_BackEndAgent_i::GetDrive(), ivd_BaseException::GetError(), i_BackEndAgent_i::GetJob(), i_BackEndAgent_i::GetJobID(), bea_Drive::GetMedium(), bea_Medium::GetMediumMem(), i_BackEndAgent_i::GetMedVolBlockSize(), i_BackEndAgent_i::GetMedVolNumber(), bea_Volume::GetPosition(), bea_Medium::GetRMType(), i_BackEndAgent_i::GetSeekThreshold(), bea_Volume::GetVolumeNumber(), ie_DATA_CORRUPTION, ipc_EXEC_m, i_BackEndAgent_i::IsAborted(), bea_Medium::IsMediumMemValid(), ivd_Error, log_DBG_m, log_FUNC_m, i_BackEndAgent_i::LogStats(), m_bea, m_dataAmount, m_drive_p, m_firstCall, m_status, m_vol_p, df_Filter::NextBlockToCopy(), df_Filter::NextInputBlock(), df_Filter::NONE, NULL, df_Filter::ProcEndOfInput(), df_Filter::ProcessingFile(), bea_Volume::Read(), df_Filter::Reset(), bea_Volume::SeekBlock(), bea_Volume::SetBlockSize(), df_Filter::SetConsistencyMode(), df_RecReader::Unpack(), bea_MediumMemory::UpdateAccess(), and i_BackEndAgent_i::WaitForResources().

Referenced by Run().

                              {
    log_FUNC_m(Recall);

    m_bea.WaitForResources();

    if (m_bea.IsAborted()) {
        log_DBG_m(dbg_LOW, "Job aborted (1). Exit.");
        return;
    }

    log_DBG_m(dbg_LOW, "Starting recall. Job ID: " << m_bea.GetJobID());

    cmn_Time startTime;

    bea_Medium* med_p = m_drive_p->GetMedium();

    if (med_p->GetCurVolNumber() != m_bea.GetMedVolNumber()) {
        med_p->ChangeVolume( m_bea.GetMedVolNumber() );
    }
    m_vol_p = med_p->GetCurrentVolume();
    // Set the block size as sent by the recall job,
    // because volume identification is not read from volume header for recalls.
    m_vol_p->SetBlockSize(m_bea.GetMedVolBlockSize());

    if (med_p->GetCurVolNumber() != m_bea.GetMedVolNumber()) {
        med_p->ChangeVolume( m_bea.GetMedVolNumber() );
    }

    ivd_MediaType_e type = static_cast<ivd_MediaType_e>(med_p->GetRMType());
    bea_Drive* drv_p(m_bea.GetDrive());
    UInt64_t seekThreshold(
        m_bea.GetSeekThreshold(
            drv_p->GetVendorID(), drv_p->GetProductID(), type ) );

    if (seekThreshold == 0) {
        seekThreshold = drv_p->GetDefaultSeekThreshold();
    }

    log_DBG_m(dbg_LOW, "Seek threshold: " << seekThreshold);
    string fileCreationThreshold = cmn_GetEnvVariable(file_creation_threshold_c);

    bool firstSet(true);

    while (true){

        // Get files from Job
        i_FileLocationDataList_t_var iFileList;
        ipc_EXEC_m(
            iFileList = m_bea.GetJob()->GetNextRecallSet();
        );
        for (UInt32_t i(0); i < iFileList->length(); i++){
            log_DBG_m(dbg_DETAIL, "blk:" << iFileList[i].blockOffset <<
                " fileID:" << iFileList[i].fileID <<
                " migID:"  << ivd_MigrationID(iFileList[i].migrationID) <<
                " spltsz:" << iFileList[i].splitSize );
        }

        if (iFileList->length() == 0) {
            log_DBG_m(dbg_LOW, "Recall finished");
            break;
        }
        //else

        ivd_FileLocVect_t files;
        ivd_FileSize_t estDbSize(0);

        // check if file is big enough to enable seek to filesize
        log_DBG_m(dbg_DETAIL, "fileCreationThreshold = " << fileCreationThreshold);

        for (UInt32_t i(0); i < iFileList->length(); i++){
            files.push_back(ivd_FileLocationData_t(iFileList[i]));
            // estimation is too small on purpose (only data stream calculated),
            // the actual file will grow a few KB/MB more.
            estDbSize += iFileList[i].splitSize;
        }

        if (m_firstCall && !fileCreationThreshold.empty()) {
            UInt32_t fileCreationThresholdVal = cmn_Str2Num(fileCreationThreshold) * cfg_MEGABYTE;

            if ((fileCreationThresholdVal != 0) && (estDbSize > fileCreationThresholdVal)) {
                log_DBG_m(dbg_DETAIL, "Enable trunc to filesize, fileCreationThresholdVal= " << fileCreationThresholdVal <<
                                                            ", estDbSize=" << estDbSize);
            }
            else {
                estDbSize = 0;
                log_DBG_m(dbg_DETAIL, "Normal writing to diskbuff, fileCreationThresholdVal = " <<
                                      fileCreationThresholdVal <<
                                      ", estDbSize=" <<
                                      estDbSize);
            }
        }
        else {
            estDbSize = 0;
            log_DBG_m(dbg_DETAIL, "Normal writing to diskbuff, estDbSize=" << estDbSize);
        }


        log_DBG_m(dbg_LOW, "Recall will recall " << files.size() << " files");

        {
            UInt32_t nextBlockToCopy(0);
            bool     skipping(false);

            //Do append only if this is first Recall and first set of files
            bool append = !m_firstCall || !firstSet;
            log_DBG_m(dbg_LOW, "append: " << boolalpha << append);

            df_Filter dffilter( m_vol_p->GetBlockSize(),
                                m_bea.GetDiskBufferFS(),
                                cmn_Num2Str(m_bea.GetBufferID()),
                                files,
                                append,
                                estDbSize);
            firstSet = false;

            UInt32_t blkPos(files[0].blockOffset);

            // Sanity check: Positions have to be below
            if (blkPos < m_vol_p->GetStartOfDataPosition()) {
                log_MARKLINE_m;
                throw ivd_Error(ie_DATA_CORRUPTION,
                    "Invalid input parameters: Trying to seek to a medium position in the header.",
                    true);
            }

            // Don't perform unnecessary seeks, which may throw the contents of
            // the drive buffer away.
            if (m_vol_p->GetPosition() != blkPos) {
                m_vol_p->SeekBlock(blkPos);
            }

            // Job was aborted while seeking to the first position to read
            // files from.
            if (m_bea.IsAborted()) {
                log_DBG_m(dbg_NORM, "Recall aborted while seeking to first position.");
                dffilter.SetConsistencyMode(df_Filter::NONE);
                break;
            }

            UInt8_t* buffer = dffilter.NextInputBlock();
            while ( buffer != NULL ) {

                try {
                    m_vol_p->Read(buffer);
                    m_dataAmount += m_vol_p->GetBlockSize();
                }
                catch (ivd_Error &ie) {
                    if (ie.GetError() == ie_MEDIUM_FILEMARK) {
                        //reading finished
                        log_DBG_m(dbg_LOW, "reading finished (Filemark).");
                        break;
                    }
                    else if (ie.GetError() == ie_MEDIUM_EOD) {
                        log_DBG_m(dbg_LOW, "reading finished (eod).");
                        break;
                    }
                    else if (ie.GetError() == ie_MEDIUM_EOM) {
                        log_DBG_m(dbg_LOW, "Early end of volume. Ignore.");
                    }
                    else {
                        // An error has happened when reading data from
                        // medium: df_Filter shouldn't check for
                        // for consistency of recalled data in this case.
                        dffilter.SetConsistencyMode(df_Filter::NONE);
                        throw;
                    }
                }

                // Don't parse the data format in the
                // "holes between" the valid files.
                if (nextBlockToCopy <= blkPos) {
                    skipping = false;
                    dffilter.Unpack(buffer, blkPos);
                }

                if (!skipping && !dffilter.ProcessingFile()) {
                    nextBlockToCopy = dffilter.NextBlockToCopy();
                    if (nextBlockToCopy == 0){ //no more files
                        log_DBG_m(dbg_NORM, "No more files for processing.");
                        break;
                    }
                    log_DBG_m(dbg_NORM,
                        "Filter is not processing file. " <<
                        "Skip to block " << nextBlockToCopy <<
                        " (current: " << blkPos << ")");
                    dffilter.Reset();
                    skipping = true;
                }

                buffer = dffilter.NextInputBlock();

                if (skipping) {
                    UInt64_t sizeGap(nextBlockToCopy - blkPos);
                    sizeGap *= m_vol_p->GetBlockSize();
                    log_DBG_m(dbg_DETAIL, "gap: " << sizeGap);

                    if (sizeGap > seekThreshold) {
                        m_vol_p->SeekBlock(nextBlockToCopy);
                        blkPos = m_vol_p->GetPosition();
                        skipping = false;
                    }
                    else {
                        // Skipping by reading.
                        blkPos++;
                    }
                }
                else {
                    // Reading.
                    blkPos++;
                }

                if (m_bea.IsAborted()) {
                    log_DBG_m(dbg_NORM, "Recall aborted.");
                    dffilter.SetConsistencyMode(df_Filter::NONE);
                    break;
                }
            } // while

            dffilter.ProcEndOfInput();
            dffilter.CheckLeftovers();
            if (m_bea.IsAborted()) {
                log_DBG_m(dbg_NORM, "Recall aborted.");
                dffilter.SetConsistencyMode(df_Filter::NONE);
                break;
            }
        }
    }//end while //recall finished

    cmn_Time endTime;
    cmn_Time diffTime = endTime - startTime;

    m_bea.LogStats(diffTime, m_dataAmount, bea_OPREAD);

    try {
        if (m_drive_p->GetMedium()->IsMediumMemValid()) {
            bea_MediumMemory* mm = m_drive_p->GetMedium()->GetMediumMem();
            mm->UpdateAccess(m_vol_p->GetVolumeNumber());
        }
    }
    catch(ivd_Exception &ie) {
        log_DBG_m(dbg_LOW, "Error updating MIC. Ignored: " << ie );
    }

    m_status = i_SUCCEDED;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void bea_RecallThread::Run ( void *  arg  )  [private, virtual]

Reimplemented from cmn_Thread.

Definition at line 113 of file bea_recall.cpp.

References bea_OPREAD, dbg_LOW, evt_ERROR, i_BackEndAgent_i::GetBarcode(), i_BackEndAgent_i::GetJobID(), i_BackEndAgent_i::GetMedVolBlockSize(), i_BackEndAgent_i::GetMedVolID(), i_BackEndAgent_i::GetMedVolNumber(), i_BackEndAgent_i::GetPoolID(), i_BackEndAgent_i::HandleError(), i_SUCCEDED, i_UNKNOWN, i_BackEndAgent_i::IsAborted(), log_DBG_m, log_ERR_m, log_FUNC_m, log_WriteEvent(), m_bea, m_status, i_BackEndAgent_i::ReadIDs(), Recall(), i_BackEndAgent_i::ReleaseResources(), and i_BackEndAgent_i::VerifyIDs().

                                    {
    log_FUNC_m(Run);

    try {
        try {
            Recall();
            m_status = i_SUCCEDED;
        }
        catch(const ivd_DFError &dfe) {
            // Recall doesn't read volume header.
            // Incorrect medium is detected when trying to read the file.
            //
            // Check vol ID then for better error reporting.
            log_DBG_m(dbg_LOW, "Data format error detected. Checking volume ID.");

            m_bea.ReadIDs(m_bea.GetMedVolNumber(), true);

            m_bea.VerifyIDs(
                m_bea.GetBarcode(),
                m_bea.GetMedVolNumber(),
                m_bea.GetMedVolBlockSize(),
                cmn_UUID_t(m_bea.GetMedVolID()),
                cmn_UUID_t(m_bea.GetPoolID()) );

            // ID check passed: Volume and pool IDs match.
            // This is data format error or FSC/media mismatch
            ostringstream sstr;
            sstr
                << "Data format error on volume "
                << m_bea.GetMedVolNumber()<< ". "
                << "Please verify the situation using FSC vs media check.";

            log_WriteEvent(evt_ERROR, sstr.str(), "RECALL",
                m_bea.GetJobID(), m_bea.GetBarcode() );

            log_ERR_m("Data format error on recall: " << dfe);

            m_status = i_DATA_ERROR;
        }
    }
    catch(const ivd_Error &ie) {
        i_CompletionStatus_e status = m_bea.HandleError(ie, bea_OPREAD);

        if (m_status == i_UNKNOWN || m_status == i_SUCCEDED) {
            m_status = status;
        }
    }
    catch(const std::exception& ie) {
        if (m_bea.IsAborted()) {
            log_DBG_m(dbg_LOW,
                "Recall aborted. Received exception: " << ie.what() );
        }
        else {
            ostringstream sstr;
            sstr << "Recall failed: " << ie.what();
            log_WriteEvent(evt_ERROR, sstr.str(), "",
                m_bea.GetJobID(), m_bea.GetBarcode() );
        }

        if (m_status == i_SUCCEDED) {
            m_status = i_UNKNOWN;
        }
    }
    catch(...) {
        log_WriteEvent(evt_ERROR, "Recall failed. Unknown error.", "",
            m_bea.GetJobID(), m_bea.GetBarcode() );

        if (m_status == i_SUCCEDED) {
            m_status = i_UNKNOWN;
        }
    }

    try {
        m_bea.ReleaseResources();
    }
    catch (...) {
        // Ignore everything
    }
}

Here is the call graph for this function:


Member Data Documentation

Reimplemented from cmn_Thread.

Definition at line 59 of file bea_recall.h.

Definition at line 66 of file bea_recall.h.

Referenced by bea_RecallThread(), Recall(), Run(), and ~bea_RecallThread().

Definition at line 69 of file bea_recall.h.

Referenced by Recall().

Definition at line 67 of file bea_recall.h.

Referenced by Recall(), and ~bea_RecallThread().

Definition at line 72 of file bea_recall.h.

Referenced by Recall().

bool bea_RecallThread::m_multi [private]

Definition at line 71 of file bea_recall.h.

Definition at line 70 of file bea_recall.h.

Referenced by Recall(), Run(), and ~bea_RecallThread().

Definition at line 68 of file bea_recall.h.

Referenced by Recall().


The documentation for this class was generated from the following files: