Index: src/ch/task.cpp =================================================================== diff -u -rcac4819aa32d29c9feab400cadc083d713459a82 -r79b981925588ba300cae07d965e12aa590aa7a91 --- src/ch/task.cpp (.../task.cpp) (revision cac4819aa32d29c9feab400cadc083d713459a82) +++ src/ch/task.cpp (.../task.cpp) (revision 79b981925588ba300cae07d965e12aa590aa7a91) @@ -352,7 +352,8 @@ TTaskProgressInfo::TTaskProgressInfo() : m_stCurrentIndex(0), - m_ullCurrentFileProcessedSize(0) + m_ullCurrentFileProcessedSize(0), + m_stSubOperationIndex(0) { } @@ -398,7 +399,94 @@ m_ullCurrentFileProcessedSize += ullSizeToAdd; } +void TTaskProgressInfo::SetSubOperationIndex(size_t stSubOperationIndex) +{ + boost::unique_lock lock(m_lock); + m_stSubOperationIndex = stSubOperationIndex; +} + +size_t TTaskProgressInfo::GetSubOperationIndex() const +{ + boost::shared_lock lock(m_lock); + return m_stSubOperationIndex; +} + +void TTaskProgressInfo::IncreaseSubOperationIndex() +{ + boost::unique_lock lock(m_lock); + ++m_stSubOperationIndex; +} + //////////////////////////////////////////////////////////////////////////// +// class TOperationDescription + +TOperationDescription::TOperationDescription() : + m_eOperation(eOperation_None) +{ +} + +TOperationDescription::~TOperationDescription() +{ +} + +void TOperationDescription::SetOperationType(EOperationType eOperation) +{ + switch(eOperation) + { + case eOperation_None: + THROW(_T("Cannot set operation type 'none'"), 0, 0, 0); + break; + + case eOperation_Copy: + { + boost::unique_lock lock(m_lock); + m_vSubOperations.clear(); + m_vSubOperations.push_back(eSubOperation_Scanning); + m_vSubOperations.push_back(eSubOperation_Copying); + break; + } + + case eOperation_Move: + { + boost::unique_lock lock(m_lock); + m_vSubOperations.clear(); + m_vSubOperations.push_back(eSubOperation_Scanning); + m_vSubOperations.push_back(eSubOperation_Copying); + m_vSubOperations.push_back(eSubOperation_Deleting); + break; + } + + BOOST_STATIC_ASSERT(eOperation_Move == eOperation_Max - 1); + + default: + THROW(_T("Unhandled case"), 0, 0, 0); + } + + m_eOperation = eOperation; +} + +EOperationType TOperationDescription::GetOperationType() const +{ + boost::shared_lock lock(m_lock); + return m_eOperation; +} + +size_t TOperationDescription::GetSubOperationsCount() const +{ + boost::shared_lock lock(m_lock); + return m_vSubOperations.size(); +} + +ESubOperationType TOperationDescription::GetSubOperationAt(size_t stIndex) const +{ + boost::shared_lock lock(m_lock); + if(stIndex >= m_vSubOperations.size()) + THROW(_T("Index out of bounds"), 0, 0, 0); + else + return m_vSubOperations[stIndex]; +} + +//////////////////////////////////////////////////////////////////////////// // CTask members CTask::CTask(chcore::IFeedbackHandler* piFeedbackHandler, size_t stSessionUniqueID) : m_log(), @@ -568,14 +656,12 @@ void CTask::SetOperationType(EOperationType eOperationType) { - boost::unique_lock lock(m_lock); - m_eOperation = eOperationType; + m_tOperation.SetOperationType(eOperationType); } EOperationType CTask::GetOperationType() const { - boost::shared_lock lock(m_lock); - return m_eOperation; + return m_tOperation.GetOperationType(); } // m_nBufferSize @@ -654,6 +740,7 @@ if(bData) { m_clipboard.Load(ar, 0, bData); + ar >> m_tOperation; m_files.Load(ar, 0, false); @@ -690,15 +777,6 @@ THROW(_T("Wrong data read from stream"), 0, 0, 0); } - ar >> iState; - if(iState >= eOperation_Copy && iState <= eOperation_Move) - m_eOperation = (EOperationType)iState; - else - { - BOOST_ASSERT(false); - THROW(_T("Wrong data read from stream"), 0, 0, 0); - } - ar >> m_bsSizes; ar >> m_nPriority; @@ -737,7 +815,10 @@ { m_clipboard.Store(ar, 0, bData); - if(GetStatusNL(ST_STEP_MASK) > ST_SEARCHING) + ar << m_tOperation; + + ESubOperationType eSubOperation = m_tOperation.GetSubOperationAt(m_tTaskProgressInfo.GetSubOperationIndex()); + if(eSubOperation != eSubOperation_Scanning) m_files.Store(ar, 0, false); else { @@ -753,7 +834,7 @@ { ar << m_tTaskProgressInfo; - UINT uiStatus = (m_nStatus & ST_WRITE_MASK); + UINT uiStatus = m_nStatus; ar << uiStatus; // store current state (convert from waiting to processing state before storing) @@ -763,17 +844,16 @@ ar << iState; - iState = m_eOperation; - ar << iState; - ar << m_bsSizes; ar << m_nPriority; time_t timeElapsed = m_localStats.GetTimeElapsed(); ar << timeElapsed; m_clipboard.Store(ar, 0, bData); - if(GetStatusNL(ST_STEP_MASK) > ST_SEARCHING) + + ESubOperationType eSubOperation = m_tOperation.GetSubOperationAt(m_tTaskProgressInfo.GetSubOperationIndex()); + if(eSubOperation != eSubOperation_Scanning) m_files.Store(ar, 0, true); else { @@ -968,17 +1048,19 @@ } // second part - if( (m_nStatus & ST_STEP_MASK) == ST_DELETING ) + EOperationType eOperationType = m_tOperation.GetOperationType(); + ESubOperationType eSubOperation = m_tOperation.GetSubOperationAt(m_tTaskProgressInfo.GetSubOperationIndex()); + if(eSubOperation == eSubOperation_Deleting) _tcscat(pData->m_szStatusText, GetResManager().LoadString(IDS_STATUS0_STRING+6)); - else if( (m_nStatus & ST_STEP_MASK) == ST_SEARCHING ) + else if(eSubOperation == eSubOperation_Scanning) _tcscat(pData->m_szStatusText, GetResManager().LoadString(IDS_STATUS0_STRING+0)); - else if(m_eOperation == eOperation_Copy) + else if(eOperationType == eOperation_Copy) { _tcscat(pData->m_szStatusText, GetResManager().LoadString(IDS_STATUS0_STRING+1)); if(!m_afFilters.IsEmpty()) _tcscat(pData->m_szStatusText, GetResManager().LoadString(IDS_FILTERING_STRING)); } - else if(m_eOperation == eOperation_Move) + else if(eOperationType == eOperation_Move) { _tcscat(pData->m_szStatusText, GetResManager().LoadString(IDS_STATUS0_STRING+2)); if(!m_afFilters.IsEmpty()) @@ -1190,9 +1272,6 @@ // log m_log.logi(_T("Searching for files...")); - // update status - SetStatus(ST_SEARCHING, ST_STEP_MASK); - // delete the content of m_files m_files.Clear(); @@ -1340,9 +1419,6 @@ // calc size of all files CalculateTotalSize(); - // change state to ST_COPYING - finished searching for files - SetStatus(ST_COPYING, ST_STEP_MASK); - // save task status Store(true); Store(false); @@ -2235,7 +2311,7 @@ return eSubResult_KillRequest; } - // update m_stCurrentIndex, getting current CFileInfo + // update m_stNextIndex, getting current CFileInfo CFileInfoPtr spFileInfo = m_files.GetAt(m_tTaskProgressInfo.GetCurrentIndex()); // set dest path with filename @@ -2357,20 +2433,9 @@ // delete buffer - it's not needed ccp.dbBuffer.Delete(); - // change status - if(GetOperationType() == eOperation_Move) - { - SetStatus(ST_DELETING, ST_STEP_MASK); - // set the index to 0 before deleting - m_tTaskProgressInfo.SetCurrentIndex(0); - } - else - { - SetTaskState(eTaskState_Finished); + // to look better (as 100%) - increase current index by 1 + m_tTaskProgressInfo.SetCurrentIndex(stSize); - // to look better - increase current index by 1 - m_tTaskProgressInfo.SetCurrentIndex(stSize); - } // log m_log.logi(_T("Finished processing in ProcessFiles")); @@ -2493,52 +2558,60 @@ // determine when to scan directories bool bReadTasksSize = GetConfig().get_bool(PP_CMREADSIZEBEFOREBLOCKING); - // check if we're allowed to continue searching for files - if(!bReadTasksSize) + // wait for permission to really start (but only if search for files is not allowed to start regardless of the lock) + size_t stSubOperationIndex = m_tTaskProgressInfo.GetSubOperationIndex(); + if(!bReadTasksSize || stSubOperationIndex != 0 || m_tOperation.GetSubOperationsCount() == 0 || m_tOperation.GetSubOperationAt(0) != eSubOperation_Scanning) eResult = CheckForWaitState(); // operation limiting - // start tracking time - if(eResult == eSubResult_Continue) + // start tracking time for this thread + m_localStats.EnableTimeTracking(); + + for(; stSubOperationIndex < m_tOperation.GetSubOperationsCount() && eResult == eSubResult_Continue; ++stSubOperationIndex) { - m_localStats.EnableTimeTracking(); + // set current sub-operation index to allow resuming + m_tTaskProgressInfo.SetSubOperationIndex(stSubOperationIndex); - // search for files if needed - if((GetStatus(ST_STEP_MASK) == ST_NULL_STATUS || GetStatus(ST_STEP_MASK) == ST_SEARCHING)) + ESubOperationType eSubOperation = m_tOperation.GetSubOperationAt(stSubOperationIndex); + switch(eSubOperation) { + case eSubOperation_Scanning: // get rid of info about processed sizes m_localStats.SetProcessedSize(0); m_localStats.SetTotalSize(0); // start searching eResult = RecurseDirectories(); - } - } - // check for free space - if(eResult == eSubResult_Continue) - eResult = CheckForFreeSpaceFB(); + // check for free space + if(eResult == eSubResult_Continue) + eResult = CheckForFreeSpaceFB(); - if(eResult == eSubResult_Continue && bReadTasksSize) - { - m_localStats.DisableTimeTracking(); + // if we didn't wait for permission to start earlier, then ask now (but only in case this is the first search) + if(eResult == eSubResult_Continue && bReadTasksSize && stSubOperationIndex == 0) + { + m_localStats.DisableTimeTracking(); - eResult = CheckForWaitState(); + eResult = CheckForWaitState(); - m_localStats.EnableTimeTracking(); - } + m_localStats.EnableTimeTracking(); + } - // Phase II - copying/moving - if(eResult == eSubResult_Continue && GetStatus(ST_STEP_MASK) == ST_COPYING) - { - // decrease processed in ctaskarray - the rest will be done in ProcessFiles - //m_rtGlobalStats.DecreaseGlobalProcessedSize(GetProcessedSize()); - eResult = ProcessFiles(); - } + break; - // deleting data - III phase - if(eResult == eSubResult_Continue && GetStatus(ST_STEP_MASK) == ST_DELETING) - eResult = DeleteFiles(); + case eSubOperation_Copying: + eResult = ProcessFiles(); + break; + case eSubOperation_Deleting: + eResult = DeleteFiles(); + break; + + default: + BOOST_ASSERT(false); + THROW(_T("Unhandled case"), 0, 0, 0); + } + } + // refresh time m_localStats.DisableTimeTracking(); @@ -2576,10 +2649,9 @@ } // perform cleanup dependent on currently executing subtask - switch(GetStatus(ST_STEP_MASK)) + switch(m_tOperation.GetSubOperationAt(m_tTaskProgressInfo.GetSubOperationIndex())) { - case ST_NULL_STATUS: - case ST_SEARCHING: + case eSubOperation_Scanning: m_files.Clear(); // get rid of m_files contents Store(true); // save state of a task break; Index: src/ch/task.h =================================================================== diff -u -rcac4819aa32d29c9feab400cadc083d713459a82 -r79b981925588ba300cae07d965e12aa590aa7a91 --- src/ch/task.h (.../task.h) (revision cac4819aa32d29c9feab400cadc083d713459a82) +++ src/ch/task.h (.../task.h) (revision 79b981925588ba300cae07d965e12aa590aa7a91) @@ -30,15 +30,7 @@ #define ST_NULL_STATUS 0x00000000 -#define ST_WRITE_MASK 0x000fffff - //------------------------------------ -#define ST_STEP_MASK 0x000000ff -#define ST_SEARCHING 0x00000001 -#define ST_COPYING 0x00000002 -#define ST_DELETING 0x00000003 - -//------------------------------------ #define ST_SPECIAL_MASK 0x0000f000 // simultaneous flags #define ST_IGNORE_DIRS 0x00001000 @@ -63,10 +55,25 @@ // enum represents type of the operation handled by the task enum EOperationType { + eOperation_None, eOperation_Copy, - eOperation_Move + eOperation_Move, + + // add new operation types before this enum value + eOperation_Max }; +enum ESubOperationType +{ + eSubOperation_None, + eSubOperation_Scanning, + eSubOperation_Copying, + eSubOperation_Deleting, + + // add new operation types before this one + eSubOperation_Max +}; + // special value representing no task #define NO_TASK_SESSION_UNIQUE_ID 0 @@ -323,6 +330,10 @@ unsigned long long GetCurrentFileProcessedSize() const; void IncreaseCurrentFileProcessedSize(unsigned long long ullSizeToAdd); + void SetSubOperationIndex(size_t stSubOperationIndex); + size_t GetSubOperationIndex() const; + void IncreaseSubOperationIndex(); + template void load(Archive& ar, unsigned int /*uiVersion*/) { @@ -332,10 +343,14 @@ unsigned long long ullCurrentFileProcessedSize = 0; ar >> ullCurrentFileProcessedSize; + size_t stSubOperationIndex = 0; + ar >> stSubOperationIndex; + boost::unique_lock lock(m_lock); m_stCurrentIndex = stCurrentIndex; m_ullCurrentFileProcessedSize = ullCurrentFileProcessedSize; + m_stSubOperationIndex = stSubOperationIndex; } template @@ -345,24 +360,67 @@ size_t stCurrentIndex = m_stCurrentIndex; unsigned long long ullCurrentFileProcessedSize = m_ullCurrentFileProcessedSize; + size_t stSubOperationIndex = m_stSubOperationIndex; m_lock.unlock_shared(); ar << stCurrentIndex; ar << ullCurrentFileProcessedSize; + ar << stSubOperationIndex; } BOOST_SERIALIZATION_SPLIT_MEMBER(); private: + volatile size_t m_stSubOperationIndex; // index of sub-operation from TOperationDescription volatile size_t m_stCurrentIndex; // index to the m_files array stating currently processed item volatile unsigned long long m_ullCurrentFileProcessedSize; // count of bytes processed for current file mutable boost::shared_mutex m_lock; }; /////////////////////////////////////////////////////////////////////////// +// TOperationDescription + +// class describes the sub-operations to be performed +class TOperationDescription +{ +public: + TOperationDescription(); + ~TOperationDescription(); + + void SetOperationType(EOperationType eOperation); + EOperationType GetOperationType() const; + + size_t GetSubOperationsCount() const; + ESubOperationType GetSubOperationAt(size_t stIndex) const; + + template + void load(Archive& ar, unsigned int /*uiVersion*/) + { + EOperationType eOperation = eOperation_None; + ar >> eOperation; + SetOperationType(eOperation); + } + + template + void save(Archive& ar, unsigned int /*uiVersion*/) const + { + ar << m_eOperation; + } + + BOOST_SERIALIZATION_SPLIT_MEMBER(); + +private: + EOperationType m_eOperation; + std::vector m_vSubOperations; + + mutable boost::shared_mutex m_lock; +}; + +/////////////////////////////////////////////////////////////////////////// // CTask + class CTask { protected: @@ -526,8 +584,6 @@ CClipboardArray m_clipboard; // original paths with which we started operation CDestPath m_dpDestPath; // destination path - EOperationType m_eOperation; // operation which is to be performed by this task object - // task settings int m_nPriority; // task priority (really processing thread priority) @@ -543,6 +599,8 @@ // changing fast volatile ETaskCurrentState m_eCurrentState; // current state of processing this task represents + TOperationDescription m_tOperation; // manages the operation and its suboperations + volatile UINT m_nStatus; // what phase of the operation is this task in TTaskProgressInfo m_tTaskProgressInfo; // task progress information