Index: src/libchcore/TFailedBufferQueue.h =================================================================== diff -u -rbef894e38e5c1486824787cf8c47a87a0828b228 -rb6a48931b8155a01d871d050f52d915abb2df8ca --- src/libchcore/TFailedBufferQueue.h (.../TFailedBufferQueue.h) (revision bef894e38e5c1486824787cf8c47a87a0828b228) +++ src/libchcore/TFailedBufferQueue.h (.../TFailedBufferQueue.h) (revision b6a48931b8155a01d871d050f52d915abb2df8ca) @@ -100,8 +100,6 @@ TEvent m_eventHasBuffers; unsigned long long m_ullErrorPosition = NoPosition; }; - - using TFailedBufferQueuePtr = std::shared_ptr; } #endif Index: src/libchcore/TFilesystemFileFeedbackWrapper.cpp =================================================================== diff -u -r8a2ff3b2b71b45fb525e030167e62f316cb32869 -rb6a48931b8155a01d871d050f52d915abb2df8ca --- src/libchcore/TFilesystemFileFeedbackWrapper.cpp (.../TFilesystemFileFeedbackWrapper.cpp) (revision 8a2ff3b2b71b45fb525e030167e62f316cb32869) +++ src/libchcore/TFilesystemFileFeedbackWrapper.cpp (.../TFilesystemFileFeedbackWrapper.cpp) (revision b6a48931b8155a01d871d050f52d915abb2df8ca) @@ -25,22 +25,28 @@ namespace chcore { - TFilesystemFileFeedbackWrapper::TFilesystemFileFeedbackWrapper(const IFeedbackHandlerPtr& spFeedbackHandler, const logger::TLogFileDataPtr& spLogFileData, + TFilesystemFileFeedbackWrapper::TFilesystemFileFeedbackWrapper(const IFilesystemFilePtr& spFile, + const IFeedbackHandlerPtr& spFeedbackHandler, const logger::TLogFileDataPtr& spLogFileData, TWorkerThreadController& rThreadController, const IFilesystemPtr& spFilesystem) : + m_spFile(spFile), m_spFeedbackHandler(spFeedbackHandler), m_spLog(std::make_unique(spLogFileData, L"Filesystem-File")), m_rThreadController(rThreadController), m_spFilesystem(spFilesystem) { - if(!spFeedbackHandler || !spFilesystem) - throw TCoreException(eErr_InvalidArgument, L"Missing filesystem or feedback handler", LOCATION); + if (!spFeedbackHandler) + throw TCoreException(eErr_InvalidArgument, L"spFeedbackHandler is NULL", LOCATION); + if (!spFile) + throw TCoreException(eErr_InvalidArgument, L"spFile is NULL", LOCATION); + if (!spFilesystem) + throw TCoreException(eErr_InvalidArgument, L"spFilesystem is NULL", LOCATION); } - TSubTaskBase::ESubOperationResult TFilesystemFileFeedbackWrapper::OpenSourceFileFB(const IFilesystemFilePtr& fileSrc) + TSubTaskBase::ESubOperationResult TFilesystemFileFeedbackWrapper::OpenSourceFileFB() { bool bRetry = false; - fileSrc->Close(); + m_spFile->Close(); do { @@ -49,7 +55,7 @@ try { - fileSrc->OpenExistingForReading(); + m_spFile->OpenExistingForReading(); return TSubTaskBase::eSubResult_Continue; } @@ -58,7 +64,7 @@ dwLastError = e.GetNativeError(); } - TFeedbackResult frResult = m_spFeedbackHandler->FileError(fileSrc->GetFilePath().ToWString(), TString(), EFileError::eCreateError, dwLastError); + TFeedbackResult frResult = m_spFeedbackHandler->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eCreateError, dwLastError); switch (frResult.GetResult()) { case EFeedbackResult::eResult_Skip: @@ -69,7 +75,7 @@ // log TString strFormat = _T("Cancel request [error %errno] while opening source file %path (OpenSourceFileFB)"); strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); - strFormat.Replace(_T("%path"), fileSrc->GetFilePath().ToString()); + strFormat.Replace(_T("%path"), m_spFile->GetFilePath().ToString()); LOG_ERROR(m_spLog) << strFormat.c_str(); return TSubTaskBase::eSubResult_CancelRequest; @@ -83,7 +89,7 @@ // log TString strFormat = _T("Retrying [error %errno] to open source file %path (OpenSourceFileFB)"); strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); - strFormat.Replace(_T("%path"), fileSrc->GetFilePath().ToString()); + strFormat.Replace(_T("%path"), m_spFile->GetFilePath().ToString()); LOG_ERROR(m_spLog) << strFormat.c_str(); bRetry = true; @@ -103,12 +109,12 @@ return TSubTaskBase::eSubResult_Continue; } - TSubTaskBase::ESubOperationResult TFilesystemFileFeedbackWrapper::OpenExistingDestinationFileFB(const IFilesystemFilePtr& fileDst, bool bProtectReadOnlyFiles) + TSubTaskBase::ESubOperationResult TFilesystemFileFeedbackWrapper::OpenExistingDestinationFileFB(bool bProtectReadOnlyFiles) { bool bRetry = false; bool bAttributesChanged = false; - fileDst->Close(); + m_spFile->Close(); do { @@ -117,7 +123,7 @@ DWORD dwLastError = ERROR_SUCCESS; try { - fileDst->OpenExistingForWriting(); + m_spFile->OpenExistingForWriting(); return TSubTaskBase::eSubResult_Continue; } catch (const TFileException& e) @@ -132,11 +138,11 @@ try { TFileInfoPtr spDstFileInfo(std::make_shared()); - m_spFilesystem->GetFileInfo(fileDst->GetFilePath(), spDstFileInfo); + m_spFilesystem->GetFileInfo(m_spFile->GetFilePath(), spDstFileInfo); if(spDstFileInfo->IsReadOnly()) { - m_spFilesystem->SetAttributes(fileDst->GetFilePath(), spDstFileInfo->GetAttributes() & ~FILE_ATTRIBUTE_READONLY); + m_spFilesystem->SetAttributes(m_spFile->GetFilePath(), spDstFileInfo->GetAttributes() & ~FILE_ATTRIBUTE_READONLY); bRetry = true; bAttributesChanged = true; continue; @@ -148,15 +154,15 @@ } } - TFeedbackResult frResult = m_spFeedbackHandler->FileError(fileDst->GetFilePath().ToWString(), TString(), EFileError::eCreateError, dwLastError); + TFeedbackResult frResult = m_spFeedbackHandler->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eCreateError, dwLastError); switch (frResult.GetResult()) { case EFeedbackResult::eResult_Retry: { // log TString strFormat = _T("Retrying [error %errno] to open destination file %path (CustomCopyFileFB)"); strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); - strFormat.Replace(_T("%path"), fileDst->GetFilePath().ToString()); + strFormat.Replace(_T("%path"), m_spFile->GetFilePath().ToString()); LOG_ERROR(m_spLog) << strFormat.c_str(); bRetry = true; @@ -167,7 +173,7 @@ // log TString strFormat = _T("Cancel request [error %errno] while opening destination file %path (CustomCopyFileFB)"); strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); - strFormat.Replace(_T("%path"), fileDst->GetFilePath().ToString()); + strFormat.Replace(_T("%path"), m_spFile->GetFilePath().ToString()); LOG_ERROR(m_spLog) << strFormat.c_str(); return TSubTaskBase::eSubResult_CancelRequest; @@ -192,8 +198,7 @@ return TSubTaskBase::eSubResult_Continue; } - TSubTaskBase::ESubOperationResult TFilesystemFileFeedbackWrapper::OpenDestinationFileFB(const IFilesystemFilePtr& fileDst, - const TFileInfoPtr& spSrcFileInfo, + TSubTaskBase::ESubOperationResult TFilesystemFileFeedbackWrapper::OpenDestinationFileFB(const TFileInfoPtr& spSrcFileInfo, unsigned long long& ullSeekTo, bool& bFreshlyCreated, bool& bSkip, @@ -205,15 +210,15 @@ ullSeekTo = 0; bFreshlyCreated = true; - fileDst->Close(); + m_spFile->Close(); do { bRetry = false; DWORD dwLastError = ERROR_SUCCESS; try { - fileDst->CreateNewForWriting(); + m_spFile->CreateNewForWriting(); return TSubTaskBase::eSubResult_Continue; } catch (const TFileException& e) @@ -226,18 +231,18 @@ bFreshlyCreated = false; // pass it to the specialized method - TSubTaskBase::ESubOperationResult eResult = OpenExistingDestinationFileFB(fileDst, bProtectReadOnlyFiles); + TSubTaskBase::ESubOperationResult eResult = OpenExistingDestinationFileFB(bProtectReadOnlyFiles); if (eResult != TSubTaskBase::eSubResult_Continue) return eResult; - else if (!fileDst->IsOpen()) + else if (!m_spFile->IsOpen()) { bSkip = true; return TSubTaskBase::eSubResult_Continue; } // read info about the existing destination file, TFileInfoPtr spDstFileInfo(std::make_shared()); - fileDst->GetFileInfo(*spDstFileInfo); + m_spFile->GetFileInfo(*spDstFileInfo); // src and dst files are the same TFeedbackResult frResult = m_spFeedbackHandler->FileAlreadyExists(*spSrcFileInfo, *spDstFileInfo); @@ -259,7 +264,7 @@ { // log TString strFormat = _T("Cancel request while checking result of dialog before opening source file %path (CustomCopyFileFB)"); - strFormat.Replace(_T("%path"), fileDst->GetFilePath().ToString()); + strFormat.Replace(_T("%path"), m_spFile->GetFilePath().ToString()); LOG_INFO(m_spLog) << strFormat.c_str(); return TSubTaskBase::eSubResult_CancelRequest; @@ -273,15 +278,15 @@ } } - TFeedbackResult frResult = m_spFeedbackHandler->FileError(fileDst->GetFilePath().ToWString(), TString(), EFileError::eCreateError, dwLastError); + TFeedbackResult frResult = m_spFeedbackHandler->FileError(m_spFile->GetFilePath().ToWString(), TString(), EFileError::eCreateError, dwLastError); switch (frResult.GetResult()) { case EFeedbackResult::eResult_Retry: { // log TString strFormat = _T("Retrying [error %errno] to open destination file %path (CustomCopyFileFB)"); strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); - strFormat.Replace(_T("%path"), fileDst->GetFilePath().ToString()); + strFormat.Replace(_T("%path"), m_spFile->GetFilePath().ToString()); LOG_ERROR(m_spLog) << strFormat.c_str(); bRetry = true; @@ -293,7 +298,7 @@ // log TString strFormat = _T("Cancel request [error %errno] while opening destination file %path (CustomCopyFileFB)"); strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); - strFormat.Replace(_T("%path"), fileDst->GetFilePath().ToString()); + strFormat.Replace(_T("%path"), m_spFile->GetFilePath().ToString()); LOG_ERROR(m_spLog) << strFormat.c_str(); return TSubTaskBase::eSubResult_CancelRequest; @@ -319,7 +324,7 @@ return TSubTaskBase::eSubResult_Continue; } - TSubTaskBase::ESubOperationResult TFilesystemFileFeedbackWrapper::TruncateFileFB(const IFilesystemFilePtr& spFile, file_size_t fsNewSize, const TSmartPath& pathFile, bool& bSkip) + TSubTaskBase::ESubOperationResult TFilesystemFileFeedbackWrapper::TruncateFileFB(file_size_t fsNewSize, const TSmartPath& pathFile, bool& bSkip) { bSkip = false; @@ -330,7 +335,7 @@ try { - spFile->Truncate(fsNewSize); + m_spFile->Truncate(fsNewSize); return TSubTaskBase::eSubResult_Continue; } catch (const TFileException& e) @@ -373,7 +378,7 @@ return TSubTaskBase::eSubResult_Continue; } - TSubTaskBase::ESubOperationResult TFilesystemFileFeedbackWrapper::ReadFileFB(const IFilesystemFilePtr& spFile, TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip) + TSubTaskBase::ESubOperationResult TFilesystemFileFeedbackWrapper::ReadFileFB(TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip) { bSkip = false; bool bRetry = false; @@ -385,7 +390,7 @@ try { - spFile->ReadFile(rBuffer); + m_spFile->ReadFile(rBuffer); return TSubTaskBase::eSubResult_Continue; } catch (const TFileException& e) @@ -429,7 +434,7 @@ return TSubTaskBase::eSubResult_Continue; } - TSubTaskBase::ESubOperationResult TFilesystemFileFeedbackWrapper::WriteFileFB(const IFilesystemFilePtr& spFile, TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip) + TSubTaskBase::ESubOperationResult TFilesystemFileFeedbackWrapper::WriteFileFB(TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip) { bSkip = false; @@ -442,7 +447,7 @@ try { - spFile->WriteFile(rBuffer); + m_spFile->WriteFile(rBuffer); return TSubTaskBase::eSubResult_Continue; } catch (const TFileException& e) @@ -486,7 +491,7 @@ return TSubTaskBase::eSubResult_Continue; } - TSubTaskBase::ESubOperationResult TFilesystemFileFeedbackWrapper::FinalizeFileFB(const IFilesystemFilePtr& spFile, TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip) + TSubTaskBase::ESubOperationResult TFilesystemFileFeedbackWrapper::FinalizeFileFB(TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip) { bSkip = false; @@ -499,7 +504,7 @@ try { - spFile->FinalizeFile(rBuffer); + m_spFile->FinalizeFile(rBuffer); return TSubTaskBase::eSubResult_Continue; } catch (const TFileException& e) Index: src/libchcore/TFilesystemFileFeedbackWrapper.h =================================================================== diff -u -r12b36349f6214befeace08efa9acc7e03be0d847 -rb6a48931b8155a01d871d050f52d915abb2df8ca --- src/libchcore/TFilesystemFileFeedbackWrapper.h (.../TFilesystemFileFeedbackWrapper.h) (revision 12b36349f6214befeace08efa9acc7e03be0d847) +++ src/libchcore/TFilesystemFileFeedbackWrapper.h (.../TFilesystemFileFeedbackWrapper.h) (revision b6a48931b8155a01d871d050f52d915abb2df8ca) @@ -32,29 +32,35 @@ class TFilesystemFileFeedbackWrapper { public: - TFilesystemFileFeedbackWrapper(const IFeedbackHandlerPtr& spFeedbackHandler, const logger::TLogFileDataPtr& spLogFileData, TWorkerThreadController& rThreadController, const IFilesystemPtr& spFilesystem); + TFilesystemFileFeedbackWrapper(const IFilesystemFilePtr& spFile, const IFeedbackHandlerPtr& spFeedbackHandler, + const logger::TLogFileDataPtr& spLogFileData, TWorkerThreadController& rThreadController, + const IFilesystemPtr& spFilesystem); TFilesystemFileFeedbackWrapper& operator=(const TFilesystemFileFeedbackWrapper&) = delete; - TSubTaskBase::ESubOperationResult OpenSourceFileFB(const IFilesystemFilePtr& fileSrc); - TSubTaskBase::ESubOperationResult OpenExistingDestinationFileFB(const IFilesystemFilePtr& fileDst, bool bProtectReadOnlyFiles); - TSubTaskBase::ESubOperationResult OpenDestinationFileFB(const IFilesystemFilePtr& fileDst, const TFileInfoPtr& spSrcFileInfo, + TSubTaskBase::ESubOperationResult OpenSourceFileFB(); + TSubTaskBase::ESubOperationResult OpenExistingDestinationFileFB(bool bProtectReadOnlyFiles); + TSubTaskBase::ESubOperationResult OpenDestinationFileFB(const TFileInfoPtr& spSrcFileInfo, unsigned long long& ullSeekTo, bool& bFreshlyCreated, bool& bSkip, bool bProtectReadOnlyFiles); - TSubTaskBase::ESubOperationResult TruncateFileFB(const IFilesystemFilePtr& spFile, file_size_t fsNewSize, + TSubTaskBase::ESubOperationResult TruncateFileFB(file_size_t fsNewSize, const TSmartPath& pathFile, bool& bSkip); - TSubTaskBase::ESubOperationResult ReadFileFB(const IFilesystemFilePtr& spFile, - TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip); - TSubTaskBase::ESubOperationResult WriteFileFB(const IFilesystemFilePtr& spFile, - TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip); + TSubTaskBase::ESubOperationResult ReadFileFB(TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip); + TSubTaskBase::ESubOperationResult WriteFileFB(TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip); - TSubTaskBase::ESubOperationResult FinalizeFileFB(const IFilesystemFilePtr& spFile, - TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip); + TSubTaskBase::ESubOperationResult FinalizeFileFB(TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip); + TSmartPath GetFilePath() const { return m_spFile->GetFilePath(); } + file_size_t GetFileSize() const { return m_spFile->GetFileSize(); } + file_size_t GetSeekPositionForResume(file_size_t fsLastAvailablePosition) { return m_spFile->GetSeekPositionForResume(fsLastAvailablePosition); } + + bool IsOpen() const { return m_spFile->IsOpen(); } + private: bool WasKillRequested(const TFeedbackResult& rFeedbackResult) const; private: + IFilesystemFilePtr m_spFile; IFeedbackHandlerPtr m_spFeedbackHandler; IFilesystemPtr m_spFilesystem; logger::TLoggerPtr m_spLog; Index: src/libchcore/TOrderedBufferQueue.cpp =================================================================== diff -u -r71bc7ffbd5b707e2cbb78eb30677d82577d62ee1 -rb6a48931b8155a01d871d050f52d915abb2df8ca --- src/libchcore/TOrderedBufferQueue.cpp (.../TOrderedBufferQueue.cpp) (revision 71bc7ffbd5b707e2cbb78eb30677d82577d62ee1) +++ src/libchcore/TOrderedBufferQueue.cpp (.../TOrderedBufferQueue.cpp) (revision b6a48931b8155a01d871d050f52d915abb2df8ca) @@ -120,7 +120,7 @@ void TOrderedBufferQueue::UpdateHasBuffers() { - if(!m_setBuffers.empty() && (m_ullExpectedBufferPosition == NoPosition || Peek()->GetFilePosition() == m_ullExpectedBufferPosition)) + if(!m_setBuffers.empty() && (m_ullExpectedBufferPosition == NoPosition || (*m_setBuffers.begin())->GetFilePosition() == m_ullExpectedBufferPosition)) m_eventHasBuffers.SetEvent(); else m_eventHasBuffers.ResetEvent(); Index: src/libchcore/TOverlappedWriter.cpp =================================================================== diff -u -r6e4ac7776b68464371cd8522a2a8d79fbcab3b28 -rb6a48931b8155a01d871d050f52d915abb2df8ca --- src/libchcore/TOverlappedWriter.cpp (.../TOverlappedWriter.cpp) (revision 6e4ac7776b68464371cd8522a2a8d79fbcab3b28) +++ src/libchcore/TOverlappedWriter.cpp (.../TOverlappedWriter.cpp) (revision b6a48931b8155a01d871d050f52d915abb2df8ca) @@ -28,7 +28,7 @@ unsigned long long ullFilePos) : m_spLog(logger::MakeLogger(spLogFileData, L"DataBuffer")), m_tBuffersToWrite(spBuffersToWrite), - m_tFailedWriteBuffers(ullFilePos), + m_tFailedWriteBuffers(), m_tFinishedBuffers(ullFilePos), m_bDataWritingFinished(false) { @@ -61,7 +61,7 @@ // overwrite error code (to avoid treating the buffer as failed read) pBuffer->SetErrorCode(ERROR_SUCCESS); - m_tFailedWriteBuffers.Push(pBuffer); + m_tFailedWriteBuffers.PushWithFallback(pBuffer, m_tBuffersToWrite); } TOverlappedDataBuffer* TOverlappedWriter::GetFailedWriteBuffer() Index: src/libchcore/TOverlappedWriter.h =================================================================== diff -u -r6e4ac7776b68464371cd8522a2a8d79fbcab3b28 -rb6a48931b8155a01d871d050f52d915abb2df8ca --- src/libchcore/TOverlappedWriter.h (.../TOverlappedWriter.h) (revision 6e4ac7776b68464371cd8522a2a8d79fbcab3b28) +++ src/libchcore/TOverlappedWriter.h (.../TOverlappedWriter.h) (revision b6a48931b8155a01d871d050f52d915abb2df8ca) @@ -67,7 +67,7 @@ TWriteBufferQueueWrapper m_tBuffersToWrite; - TOrderedBufferQueue m_tFailedWriteBuffers; + TFailedBufferQueue m_tFailedWriteBuffers; TOrderedBufferQueue m_tFinishedBuffers; bool m_bDataWritingFinished = false; // output file was already written to the end Index: src/libchcore/TReadBufferQueueWrapper.cpp =================================================================== diff -u -r71bc7ffbd5b707e2cbb78eb30677d82577d62ee1 -rb6a48931b8155a01d871d050f52d915abb2df8ca --- src/libchcore/TReadBufferQueueWrapper.cpp (.../TReadBufferQueueWrapper.cpp) (revision 71bc7ffbd5b707e2cbb78eb30677d82577d62ee1) +++ src/libchcore/TReadBufferQueueWrapper.cpp (.../TReadBufferQueueWrapper.cpp) (revision b6a48931b8155a01d871d050f52d915abb2df8ca) @@ -97,16 +97,7 @@ bool TReadBufferQueueWrapper::IsBufferReady() const { if(IsDataSourceFinished()) - { - if(m_tClaimedQueue.IsEmpty()) - return false; - - const TOverlappedDataBuffer* const pFirstBuffer = m_tClaimedQueue.Peek(); - if(pFirstBuffer->GetFilePosition() <= m_ullDataSourceFinishedPos) - return true; - - return false; - } + return !m_tClaimedQueue.IsEmpty(); else return !m_tClaimedQueue.IsEmpty() || !m_spUnorderedQueue->IsEmpty(); } Index: src/libchcore/TReadBufferQueueWrapper.h =================================================================== diff -u -r71bc7ffbd5b707e2cbb78eb30677d82577d62ee1 -rb6a48931b8155a01d871d050f52d915abb2df8ca --- src/libchcore/TReadBufferQueueWrapper.h (.../TReadBufferQueueWrapper.h) (revision 71bc7ffbd5b707e2cbb78eb30677d82577d62ee1) +++ src/libchcore/TReadBufferQueueWrapper.h (.../TReadBufferQueueWrapper.h) (revision b6a48931b8155a01d871d050f52d915abb2df8ca) @@ -61,8 +61,6 @@ unsigned long long m_ullDataSourceFinishedPos = NoPosition; }; - - using TUnorderedBufferQueueWrapperPtr = std::shared_ptr; } #endif Index: src/libchcore/TSubTaskCopyMove.cpp =================================================================== diff -u -r6e4ac7776b68464371cd8522a2a8d79fbcab3b28 -rb6a48931b8155a01d871d050f52d915abb2df8ca --- src/libchcore/TSubTaskCopyMove.cpp (.../TSubTaskCopyMove.cpp) (revision 6e4ac7776b68464371cd8522a2a8d79fbcab3b28) +++ src/libchcore/TSubTaskCopyMove.cpp (.../TSubTaskCopyMove.cpp) (revision b6a48931b8155a01d871d050f52d915abb2df8ca) @@ -340,8 +340,6 @@ const TConfig& rConfig = GetContext().GetConfig(); IFilesystemPtr spFilesystem = GetContext().GetLocalFilesystem(); - TFilesystemFileFeedbackWrapper tFileFBWrapper(spFeedbackHandler, GetContext().GetLogFileData(), rThreadController, spFilesystem); - // calculate if we want to disable buffering for file transfer // NOTE: we are using here the file size read when scanning directories for files; it might be // outdated at this point, but at present we don't want to re-read file size since it @@ -352,8 +350,11 @@ IFilesystemFilePtr fileSrc = spFilesystem->CreateFileObject(pData->spSrcFile->GetFullFilePath(), bNoBuffer); IFilesystemFilePtr fileDst = spFilesystem->CreateFileObject(pData->pathDstFile, bNoBuffer); + TFilesystemFileFeedbackWrapper srcFileWrapper(fileSrc, spFeedbackHandler, GetContext().GetLogFileData(), rThreadController, spFilesystem); + TFilesystemFileFeedbackWrapper dstFileWrapper(fileDst, spFeedbackHandler, GetContext().GetLogFileData(), rThreadController, spFilesystem); + bool bSkip = false; - TSubTaskBase::ESubOperationResult eResult = OpenSrcAndDstFilesFB(tFileFBWrapper, pData, fileSrc, fileDst, bSkip); + TSubTaskBase::ESubOperationResult eResult = OpenSrcAndDstFilesFB(srcFileWrapper, dstFileWrapper, pData, bSkip); if(eResult != TSubTaskBase::eSubResult_Continue) return eResult; else if(bSkip) @@ -426,7 +427,7 @@ if (!pBuffer) throw TCoreException(eErr_InternalProblem, L"Read was possible, but no buffer is available", LOCATION); - eResult = tFileFBWrapper.ReadFileFB(fileSrc, *pBuffer, pData->spSrcFile->GetFullFilePath(), bSkip); + eResult = srcFileWrapper.ReadFileFB(*pBuffer, pData->spSrcFile->GetFullFilePath(), bSkip); if(eResult != TSubTaskBase::eSubResult_Continue) { tReaderWriter.AddEmptyBuffer(pBuffer, false); @@ -476,7 +477,7 @@ if (!pBuffer) throw TCoreException(eErr_InternalProblem, L"Write was possible, but no buffer is available", LOCATION); - eResult = tFileFBWrapper.WriteFileFB(fileDst, *pBuffer, pData->pathDstFile, bSkip); + eResult = dstFileWrapper.WriteFileFB(*pBuffer, pData->pathDstFile, bSkip); if(eResult != TSubTaskBase::eSubResult_Continue) { tReaderWriter.AddEmptyBuffer(pBuffer, false); @@ -530,7 +531,7 @@ if(pBuffer->IsLastPart()) { - eResult = tFileFBWrapper.FinalizeFileFB(fileDst, *pBuffer, pData->pathDstFile, bSkip); + eResult = dstFileWrapper.FinalizeFileFB(*pBuffer, pData->pathDstFile, bSkip); if (eResult != TSubTaskBase::eSubResult_Continue) { tReaderWriter.AddEmptyBuffer(pBuffer, false); @@ -621,8 +622,8 @@ m_tSubTaskStats.AdjustProcessedSize(m_tSubTaskStats.GetCurrentItemProcessedSize(), spSrcFileInfo->GetLength64()); } - TSubTaskCopyMove::ESubOperationResult TSubTaskCopyMove::OpenSrcAndDstFilesFB(TFilesystemFileFeedbackWrapper& rFileFBWrapper, CUSTOM_COPY_PARAMS* pData, - const IFilesystemFilePtr& spFileSrc, const IFilesystemFilePtr& spFileDst, bool& bSkip) + TSubTaskCopyMove::ESubOperationResult TSubTaskCopyMove::OpenSrcAndDstFilesFB(TFilesystemFileFeedbackWrapper& rSrcFile, TFilesystemFileFeedbackWrapper& rDstFile, + CUSTOM_COPY_PARAMS* pData, bool& bSkip) { const TConfig& rConfig = GetContext().GetConfig(); IFilesystemPtr spFilesystem = GetContext().GetLocalFilesystem(); @@ -632,10 +633,10 @@ unsigned long long ullProcessedSize = m_tSubTaskStats.GetCurrentItemProcessedSize(); // first open the source file and handle any failures - TSubTaskCopyMove::ESubOperationResult eResult = rFileFBWrapper.OpenSourceFileFB(spFileSrc); + TSubTaskCopyMove::ESubOperationResult eResult = rSrcFile.OpenSourceFileFB(); if(eResult != TSubTaskBase::eSubResult_Continue) return eResult; - else if(!spFileSrc->IsOpen()) + else if(!rSrcFile.IsOpen()) { // invalid handle = operation skipped by user AdjustProcessedSizeForSkip(pData->spSrcFile); @@ -650,7 +651,7 @@ // but it would require frequent total size updates and thus - serializations). // NOTE2: the by-chunk corrections of stats are still applied when copying to ensure even further size // matching; this update however still allows for better serialization management. - file_size_t fsNewSize = spFileSrc->GetFileSize(); + file_size_t fsNewSize = rSrcFile.GetFileSize(); file_size_t fsOldSize = pData->spSrcFile->GetLength64(); if(fsNewSize != fsOldSize) { @@ -671,7 +672,7 @@ // verify that the file qualifies for silent resume try { - spFilesystem->GetFileInfo(spFileDst->GetFilePath(), spDstFileInfo); + spFilesystem->GetFileInfo(rDstFile.GetFilePath(), spDstFileInfo); } catch(const TFileException&) { @@ -684,10 +685,10 @@ // we are resuming previous operation if(bContinue) { - eResult = rFileFBWrapper.OpenExistingDestinationFileFB(spFileDst, GetTaskPropValue(rConfig)); + eResult = rDstFile.OpenExistingDestinationFileFB(GetTaskPropValue(rConfig)); if (eResult != TSubTaskBase::eSubResult_Continue) return eResult; - else if (!spFileDst->IsOpen()) + else if (!rDstFile.IsOpen()) { AdjustProcessedSizeForSkip(pData->spSrcFile); @@ -704,7 +705,7 @@ { // open destination file for case, when we start operation on this file (i.e. it is not resume of the // old operation) - eResult = rFileFBWrapper.OpenDestinationFileFB(spFileDst, pData->spSrcFile, ullSeekTo, bDstFileFreshlyCreated, bSkip, GetTaskPropValue(rConfig)); + eResult = rDstFile.OpenDestinationFileFB(pData->spSrcFile, ullSeekTo, bDstFileFreshlyCreated, bSkip, GetTaskPropValue(rConfig)); if(eResult != TSubTaskBase::eSubResult_Continue) return eResult; else if(bSkip) @@ -732,7 +733,7 @@ ullSeekTo = std::min(ullSeekTo, fsNewSize); // seek to the position where copying will start - file_size_t fsMoveTo = spFileDst->GetSeekPositionForResume(ullSeekTo); + file_size_t fsMoveTo = rDstFile.GetSeekPositionForResume(ullSeekTo); // sanity check if (bDstFileFreshlyCreated && ullSeekTo != 0) @@ -747,7 +748,7 @@ if(!bDstFileFreshlyCreated) { // if destination file was opened (as opposed to newly created) - eResult = rFileFBWrapper.TruncateFileFB(spFileDst, fsMoveTo, pData->pathDstFile, bSkip); + eResult = rDstFile.TruncateFileFB(fsMoveTo, pData->pathDstFile, bSkip); if(eResult != TSubTaskBase::eSubResult_Continue) return eResult; else if(bSkip) Index: src/libchcore/TSubTaskCopyMove.h =================================================================== diff -u -r1506d51ff1c0a5d156dab398051efc0c87473e81 -rb6a48931b8155a01d871d050f52d915abb2df8ca --- src/libchcore/TSubTaskCopyMove.h (.../TSubTaskCopyMove.h) (revision 1506d51ff1c0a5d156dab398051efc0c87473e81) +++ src/libchcore/TSubTaskCopyMove.h (.../TSubTaskCopyMove.h) (revision b6a48931b8155a01d871d050f52d915abb2df8ca) @@ -65,8 +65,8 @@ ESubOperationResult CustomCopyFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, CUSTOM_COPY_PARAMS* pData); - ESubOperationResult OpenSrcAndDstFilesFB(TFilesystemFileFeedbackWrapper& rFileFBWrapper, CUSTOM_COPY_PARAMS* pData, - const IFilesystemFilePtr& spFileSrc, const IFilesystemFilePtr& spFileDst, bool& bSkip); + ESubOperationResult OpenSrcAndDstFilesFB(TFilesystemFileFeedbackWrapper& rSrcFile, TFilesystemFileFeedbackWrapper& rDstFile, + CUSTOM_COPY_PARAMS* pData, bool& bSkip); ESubOperationResult HandleReadError(const IFeedbackHandlerPtr& spFeedbackHandler, TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip); Index: src/libchcore/TWriteBufferQueueWrapper.cpp =================================================================== diff -u -r6e4ac7776b68464371cd8522a2a8d79fbcab3b28 -rb6a48931b8155a01d871d050f52d915abb2df8ca --- src/libchcore/TWriteBufferQueueWrapper.cpp (.../TWriteBufferQueueWrapper.cpp) (revision 6e4ac7776b68464371cd8522a2a8d79fbcab3b28) +++ src/libchcore/TWriteBufferQueueWrapper.cpp (.../TWriteBufferQueueWrapper.cpp) (revision b6a48931b8155a01d871d050f52d915abb2df8ca) @@ -27,6 +27,9 @@ m_spDataQueue(spQueue), m_eventHasBuffers(true, false) { + if (!spQueue) + throw TCoreException(eErr_InvalidArgument, L"spQueue is NULL", LOCATION); + UpdateHasBuffers(); } @@ -41,10 +44,7 @@ TOverlappedDataBuffer* TWriteBufferQueueWrapper::Pop() { - TOverlappedDataBuffer* pBuffer = m_tClaimedQueue.Pop(); - if(!pBuffer) - pBuffer = m_spDataQueue->Pop(); - + TOverlappedDataBuffer* pBuffer = InternalPop(); if(pBuffer) { pBuffer->InitForWrite(); @@ -54,6 +54,22 @@ return pBuffer; } + TOverlappedDataBuffer* TWriteBufferQueueWrapper::InternalPop() + { + const TOverlappedDataBuffer* pClaimedQueueBuffer = m_tClaimedQueue.Peek(); + if (!pClaimedQueueBuffer) + return m_spDataQueue->Pop(); + + const TOverlappedDataBuffer* pDataQueueBuffer = m_spDataQueue->Peek(); + if (!pDataQueueBuffer) + return m_tClaimedQueue.Pop(); + + if (pClaimedQueueBuffer->GetFilePosition() < pDataQueueBuffer->GetFilePosition()) + return m_tClaimedQueue.Pop(); + else + return m_spDataQueue->Pop(); + } + bool TWriteBufferQueueWrapper::IsBufferReady() const { return !m_tClaimedQueue.IsEmpty() || !m_spDataQueue->IsEmpty(); Index: src/libchcore/TWriteBufferQueueWrapper.h =================================================================== diff -u -rbef894e38e5c1486824787cf8c47a87a0828b228 -rb6a48931b8155a01d871d050f52d915abb2df8ca --- src/libchcore/TWriteBufferQueueWrapper.h (.../TWriteBufferQueueWrapper.h) (revision bef894e38e5c1486824787cf8c47a87a0828b228) +++ src/libchcore/TWriteBufferQueueWrapper.h (.../TWriteBufferQueueWrapper.h) (revision b6a48931b8155a01d871d050f52d915abb2df8ca) @@ -35,6 +35,7 @@ public: TWriteBufferQueueWrapper(const TOrderedBufferQueuePtr& spQueue); + void Push(TOverlappedDataBuffer* pBuffer, bool /*bKeepPosition*/) { Push(pBuffer); } void Push(TOverlappedDataBuffer* pBuffer); TOverlappedDataBuffer* Pop(); @@ -49,15 +50,14 @@ private: bool IsBufferReady() const; void UpdateHasBuffers(); + TOverlappedDataBuffer* InternalPop(); private: TOrderedBufferQueuePtr m_spDataQueue; // external queue of buffers to use TOrderedBufferQueue m_tClaimedQueue; // internal queue of claimed buffers TEvent m_eventHasBuffers; }; - - using TWriteBufferQueueWrapperPtr = std::shared_ptr; } #endif Index: src/libchcore/Tests/TOrderedBufferQueueTests.cpp =================================================================== diff -u -rbef894e38e5c1486824787cf8c47a87a0828b228 -rb6a48931b8155a01d871d050f52d915abb2df8ca --- src/libchcore/Tests/TOrderedBufferQueueTests.cpp (.../TOrderedBufferQueueTests.cpp) (revision bef894e38e5c1486824787cf8c47a87a0828b228) +++ src/libchcore/Tests/TOrderedBufferQueueTests.cpp (.../TOrderedBufferQueueTests.cpp) (revision b6a48931b8155a01d871d050f52d915abb2df8ca) @@ -3,6 +3,7 @@ #include "gmock/gmock.h" #include "../TOrderedBufferQueue.h" #include "../GTestMacros.h" +#include "../TCoreException.h" using namespace chcore; @@ -200,3 +201,81 @@ EXPECT_EQ(1, spReleaseList->GetCount()); } + +///////////////////////////////////////////////////////////////////////// +// custom, specialized functionality + +TEST(TOrderedBufferQueueTests, GetUnneededLastParts_NoLastParts) +{ + TOrderedBufferQueue queue(0); + TOverlappedDataBuffer buffer1(1024, nullptr); + buffer1.SetFilePosition(1000); + buffer1.SetRequestedDataSize(1000); + TOverlappedDataBuffer buffer2(1024, nullptr); + buffer2.SetFilePosition(0); + buffer2.SetRequestedDataSize(1000); + + queue.Push(&buffer1); + queue.Push(&buffer2); + + auto vParts = queue.GetUnneededLastParts(); + + EXPECT_EQ(0, vParts.size()); +} + +TEST(TOrderedBufferQueueTests, GetUnneededLastParts_SingleLastPart) +{ + TOrderedBufferQueue queue(0); + TOverlappedDataBuffer buffer1(1024, nullptr); + buffer1.SetFilePosition(1000); + buffer1.SetRequestedDataSize(1000); + buffer1.SetLastPart(true); + TOverlappedDataBuffer buffer2(1024, nullptr); + buffer2.SetFilePosition(0); + buffer2.SetRequestedDataSize(1000); + + queue.Push(&buffer1); + queue.Push(&buffer2); + + auto vParts = queue.GetUnneededLastParts(); + + EXPECT_EQ(0, vParts.size()); +} + +TEST(TOrderedBufferQueueTests, GetUnneededLastParts_UnfinishedBufferAfterFinished) +{ + TOrderedBufferQueue queue(0); + TOverlappedDataBuffer buffer1(1024, nullptr); + buffer1.SetFilePosition(1000); + buffer1.SetRequestedDataSize(1000); + TOverlappedDataBuffer buffer2(1024, nullptr); + buffer2.SetFilePosition(0); + buffer2.SetRequestedDataSize(1000); + buffer2.SetLastPart(true); + + queue.Push(&buffer1); + queue.Push(&buffer2); + + EXPECT_THROW(queue.GetUnneededLastParts(), TCoreException); +} + +TEST(TOrderedBufferQueueTests, GetUnneededLastParts_TwoLastParts) +{ + TOrderedBufferQueue queue(0); + TOverlappedDataBuffer buffer1(1024, nullptr); + buffer1.SetFilePosition(1000); + buffer1.SetRequestedDataSize(1000); + buffer1.SetLastPart(true); + TOverlappedDataBuffer buffer2(1024, nullptr); + buffer2.SetFilePosition(0); + buffer2.SetRequestedDataSize(1000); + buffer2.SetLastPart(true); + + queue.Push(&buffer1); + queue.Push(&buffer2); + + auto vParts = queue.GetUnneededLastParts(); + + EXPECT_EQ(1, vParts.size()); + EXPECT_EQ(&buffer1, vParts[0]); +} Index: src/libchcore/Tests/TWriteBufferQueueWrapperTests.cpp =================================================================== diff -u -r3ccbdb8d3eac3427e6d3354854476e57fdc7ceb9 -rb6a48931b8155a01d871d050f52d915abb2df8ca --- src/libchcore/Tests/TWriteBufferQueueWrapperTests.cpp (.../TWriteBufferQueueWrapperTests.cpp) (revision 3ccbdb8d3eac3427e6d3354854476e57fdc7ceb9) +++ src/libchcore/Tests/TWriteBufferQueueWrapperTests.cpp (.../TWriteBufferQueueWrapperTests.cpp) (revision b6a48931b8155a01d871d050f52d915abb2df8ca) @@ -3,11 +3,167 @@ #include "gmock/gmock.h" #include "../TWriteBufferQueueWrapper.h" #include +#include "../TCoreException.h" +#include "../GTestMacros.h" using namespace chcore; -TEST(TWriteBufferQueueWrapperTests, DefaultTest) +TEST(TWriteBufferQueueWrapperTests, ConstructorWithNullParam) { + EXPECT_THROW(TWriteBufferQueueWrapper(nullptr), TCoreException); +} + +TEST(TWriteBufferQueueWrapperTests, Constructor) +{ TOrderedBufferQueuePtr spQueue(std::make_shared()); - TWriteBufferQueueWrapper queueWrapper(spQueue); + + TWriteBufferQueueWrapper queue(spQueue); + EXPECT_EQ(0, queue.GetCount()); + EXPECT_EQ(true, queue.IsEmpty()); + EXPECT_TIMEOUT(queue.GetHasBuffersEvent()); } + +TEST(TWriteBufferQueueWrapperTests, Pop_EmptyQueue) +{ + TOrderedBufferQueuePtr spQueue(std::make_shared()); + TWriteBufferQueueWrapper queue(spQueue); + + EXPECT_EQ(nullptr, queue.Pop()); +} + +TEST(TWriteBufferQueueWrapperTests, Pop_FromBufferList) +{ + TOrderedBufferQueuePtr spQueue(std::make_shared()); + TOverlappedDataBuffer buffer1(1024, nullptr); + buffer1.SetFilePosition(0); + buffer1.SetRequestedDataSize(1000); + TOverlappedDataBuffer buffer2(1024, nullptr); + buffer2.SetFilePosition(1000); + buffer2.SetRequestedDataSize(1000); + TOverlappedDataBuffer buffer3(1024, nullptr); + buffer3.SetFilePosition(2000); + buffer3.SetRequestedDataSize(1000); + TOverlappedDataBuffer buffer4(1024, nullptr); + buffer4.SetFilePosition(3000); + buffer4.SetRequestedDataSize(1000); + + spQueue->Push(&buffer1); + spQueue->Push(&buffer2); + spQueue->Push(&buffer3); + spQueue->Push(&buffer4); + + TWriteBufferQueueWrapper queue(spQueue); + + EXPECT_EQ(&buffer1, queue.Pop()); + EXPECT_EQ(0, buffer1.GetFilePosition()); + EXPECT_EQ(1000, buffer1.GetRequestedDataSize()); + + EXPECT_EQ(&buffer2, queue.Pop()); + EXPECT_EQ(1000, buffer2.GetFilePosition()); + EXPECT_EQ(1000, buffer2.GetRequestedDataSize()); + + EXPECT_EQ(&buffer3, queue.Pop()); + EXPECT_EQ(2000, buffer3.GetFilePosition()); + EXPECT_EQ(1000, buffer3.GetRequestedDataSize()); + + EXPECT_EQ(&buffer4, queue.Pop()); + EXPECT_EQ(3000, buffer4.GetFilePosition()); + EXPECT_EQ(1000, buffer4.GetRequestedDataSize()); + + EXPECT_EQ(nullptr, queue.Pop()); +} + +TEST(TWriteBufferQueueWrapperTests, PushPop_ClaimedBuffers) +{ + TOrderedBufferQueuePtr spQueue(std::make_shared()); + TWriteBufferQueueWrapper queue(spQueue); + + TOverlappedDataBuffer buffer1(1024, nullptr); + buffer1.SetFilePosition(0); + buffer1.SetRequestedDataSize(1000); + TOverlappedDataBuffer buffer2(1024, nullptr); + buffer2.SetFilePosition(1000); + buffer2.SetRequestedDataSize(1000); + TOverlappedDataBuffer buffer3(1024, nullptr); + buffer3.SetFilePosition(2000); + buffer3.SetRequestedDataSize(1000); + TOverlappedDataBuffer buffer4(1024, nullptr); + buffer4.SetFilePosition(3000); + buffer4.SetRequestedDataSize(1000); + + queue.Push(&buffer4); + queue.Push(&buffer3); + queue.Push(&buffer2); + queue.Push(&buffer1); + + EXPECT_SIGNALED(queue.GetHasBuffersEvent()); + EXPECT_EQ(&buffer1, queue.Pop()); + EXPECT_EQ(0, buffer1.GetFilePosition()); + EXPECT_EQ(1000, buffer1.GetRequestedDataSize()); + + EXPECT_SIGNALED(queue.GetHasBuffersEvent()); + EXPECT_EQ(&buffer2, queue.Pop()); + EXPECT_EQ(1000, buffer2.GetFilePosition()); + EXPECT_EQ(1000, buffer2.GetRequestedDataSize()); + + EXPECT_SIGNALED(queue.GetHasBuffersEvent()); + EXPECT_EQ(&buffer3, queue.Pop()); + EXPECT_EQ(2000, buffer3.GetFilePosition()); + EXPECT_EQ(1000, buffer3.GetRequestedDataSize()); + + EXPECT_SIGNALED(queue.GetHasBuffersEvent()); + EXPECT_EQ(&buffer4, queue.Pop()); + EXPECT_EQ(3000, buffer4.GetFilePosition()); + EXPECT_EQ(1000, buffer4.GetRequestedDataSize()); + + EXPECT_TIMEOUT(queue.GetHasBuffersEvent()); + EXPECT_EQ(nullptr, queue.Pop()); +} + +TEST(TWriteBufferQueueWrapperTests, PushPop_MixedBuffers) +{ + TOrderedBufferQueuePtr spQueue(std::make_shared()); + TOverlappedDataBuffer buffer1(1024, nullptr); + buffer1.SetFilePosition(0); + buffer1.SetRequestedDataSize(1000); + TOverlappedDataBuffer buffer2(1024, nullptr); + buffer2.SetFilePosition(1000); + buffer2.SetRequestedDataSize(1000); + + spQueue->Push(&buffer1); + spQueue->Push(&buffer2); + + TWriteBufferQueueWrapper queue(spQueue); + + TOverlappedDataBuffer buffer3(1024, nullptr); + buffer3.SetFilePosition(2000); + buffer3.SetRequestedDataSize(1000); + TOverlappedDataBuffer buffer4(1024, nullptr); + buffer4.SetFilePosition(3000); + buffer4.SetRequestedDataSize(1000); + queue.Push(&buffer3); + queue.Push(&buffer4); + + EXPECT_SIGNALED(queue.GetHasBuffersEvent()); + EXPECT_EQ(&buffer1, queue.Pop()); + EXPECT_EQ(0, buffer1.GetFilePosition()); + EXPECT_EQ(1000, buffer1.GetRequestedDataSize()); + + EXPECT_SIGNALED(queue.GetHasBuffersEvent()); + EXPECT_EQ(&buffer2, queue.Pop()); + EXPECT_EQ(1000, buffer2.GetFilePosition()); + EXPECT_EQ(1000, buffer2.GetRequestedDataSize()); + + EXPECT_SIGNALED(queue.GetHasBuffersEvent()); + EXPECT_EQ(&buffer3, queue.Pop()); + EXPECT_EQ(2000, buffer3.GetFilePosition()); + EXPECT_EQ(1000, buffer3.GetRequestedDataSize()); + + EXPECT_SIGNALED(queue.GetHasBuffersEvent()); + EXPECT_EQ(&buffer4, queue.Pop()); + EXPECT_EQ(3000, buffer4.GetFilePosition()); + EXPECT_EQ(1000, buffer4.GetRequestedDataSize()); + + EXPECT_TIMEOUT(queue.GetHasBuffersEvent()); + EXPECT_EQ(nullptr, queue.Pop()); +}