//!\brief Функция отправки файла на сервер FileTransfer void FileSenderImp::SendFile( std::wstring &fileId, FileInfo *filesArray, int filesArraySize, int lifeTime ) { if ( m_connName.localComponentName.empty() || m_connName.remoteComponentName.empty() ) KLFT_THROW_ERROR( ERR_BAD_FUNCTION_PARAMETERS ); if ( !KLTR_GetTransport()->IsConnectionActive( m_connName.localComponentName.c_str(), m_connName.remoteComponentName.c_str() ) ) KLFT_THROW_ERROR( ERR_CONNECTION_BROKEN ); if ( filesArray==NULL || filesArraySize==0 ) KLFT_THROW_ERROR( ERR_BAD_FUNCTION_PARAMETERS ); if ( filesArray!=NULL && filesArraySize!=0 ) { for( int i = 0; i < filesArraySize; i++ ) { if( !KLSTD_IfExists( filesArray[i].sourceFilePath.c_str() ) ) { KLFT_THROW_ERROR1( ERR_FILE_NOT_FOUND, filesArray[i].sourceFilePath.c_str() ); } } } if ( m_pSentFile!=NULL ) KLFT_THROW_ERROR( ERR_FILE_IS_ALREADY_UPLOADING ); KLERR_TRY { KLSTD::AutoCriticalSection autoUnlock( m_pCricSec ); fileId = KLSTD_CreateGUIDString(); m_fileId = fileId; m_filesArray.clear(); for( int i = 0; i < filesArraySize; i++ ) { m_filesArray.push_back( filesArray[i] ); } m_pWaitSem = NULL; KLSTD_CreateSemaphore( &m_pWaitSem, 0 ); KLTP_GetThreadsPool()->AddWorker( &m_wId, L"File sender worker", new FileSenderWorker( this ), KLTP::ThreadsPool::RunOnce ); } KLERR_CATCH( pError ) { KLERR_SAY_FAILURE( 2, pError ); m_pSentFile = NULL; KLERR_RETHROW(); } KLERR_ENDTRY }
//!\brief Получение текущего статуса отправляемого файла void FileSenderImp::GetFileStatus( const std::wstring &fileId, SendFileStatus &fileStatus ) { KLSTD::AutoCriticalSection autoUnlock( m_pCricSec ); if ( m_fileId!=fileId ) KLFT_THROW_ERROR( ERR_WRONG_FILE_ID ); fileStatus = m_fileStatus; if ( fileStatus.sentPercent < PERCENT_FOR_ARCHIVATE && m_pSentFile!=NULL ) { int iArchPercent = m_pSentFile->GetArchivatePercent(); fileStatus.sentPercent = (int)(((double)iArchPercent / 100.0) * (double)PERCENT_FOR_ARCHIVATE); } }
//!\brief Функция прерывает отправку файла void FileSenderImp::CancelSendFile( const std::wstring &fileId ) { KLTP::ThreadsPool::WorkerId wId; { KLSTD::AutoCriticalSection autoUnlock( m_pCricSec ); if ( m_pSentFile!=NULL && m_pSentFile->GetFileId()!=fileId ) KLFT_THROW_ERROR( ERR_WRONG_FILE_ID ); wId = m_wId; m_wId = (-1); m_stopSendFlag = true; m_pSentFile = NULL; KLERR_BEGIN { KLTRAP::TransportProxy trProxy; trProxy.Initialize( m_connName.localComponentName.c_str(), m_connName.remoteComponentName.c_str() ); KLTRAP::TransportConnectionLocker trLocker( &trProxy ); struct soap* pSoap = trLocker.Get(); struct klft_CancelServerFileUploadResponse res; soap_call_klft_CancelServerFileUpload( pSoap, NULL, NULL, (wchar_t *)fileId.c_str(), res ); trLocker.CheckResult(); if ( res.error.code ) { KLERR::Error *pError=NULL; KLPAR::ExceptionFromSoap( res.error, &pError ); throw pError; } }KLERR_ENDT(3); } KLTP_GetThreadsPool()->DeleteWorker( wId ); }
//!\brief Функция ожидания окончания операции отправки файла на сервер bool FileSenderImp::WaitFileSent( const std::wstring &fileId, int waitTimeout ) { KLSTD::CAutoPtr<KLSTD::Semaphore> pWaitSem; { KLSTD::AutoCriticalSection autoUnlock( m_pCricSec ); if ( m_fileId!=fileId ) KLFT_THROW_ERROR( ERR_WRONG_FILE_ID ); pWaitSem = m_pWaitSem; if ( pWaitSem==NULL ) KLFT_THROW_ERROR( ERR_WRONG_FILE_ID ); if ( m_fileStatus.errorCode!=0 ) KLFT_THROW_ERROR_CODE( m_fileStatus.errorCode ); } bool waitRes = pWaitSem->Wait( waitTimeout ); if ( m_fileStatus.errorCode!=0 ) KLFT_THROW_ERROR_CODE( m_fileStatus.errorCode ); return waitRes; }
bool QuotaObject::MaybeAllocateMoreSpace(int64_t aOffset, int32_t aCount) { int64_t end = aOffset + aCount; QuotaManager* quotaManager = QuotaManager::Get(); NS_ASSERTION(quotaManager, "Shouldn't be null!"); MutexAutoLock lock(quotaManager->mQuotaMutex); if (mSize >= end || !mOriginInfo) { return true; } GroupInfo* groupInfo = mOriginInfo->mGroupInfo; if (groupInfo->IsForPersistentStorage()) { uint64_t newUsage = mOriginInfo->mUsage - mSize + end; if (newUsage > mOriginInfo->mLimit) { // This will block the thread, but it will also drop the mutex while // waiting. The mutex will be reacquired again when the waiting is // finished. if (!quotaManager->LockedQuotaIsLifted()) { return false; } // Threads raced, the origin info removal has been done by some other // thread. if (!mOriginInfo) { // The other thread could allocate more space. if (end > mSize) { mSize = end; } return true; } nsCString group = mOriginInfo->mGroupInfo->mGroup; nsCString origin = mOriginInfo->mOrigin; mOriginInfo->LockedClearOriginInfos(); NS_ASSERTION(!mOriginInfo, "Should have cleared in LockedClearOriginInfos!"); quotaManager->LockedRemoveQuotaForOrigin(PERSISTENCE_TYPE_PERSISTENT, group, origin); // Some other thread could increase the size without blocking (increasing // the origin usage without hitting the limit), but no more than this one. NS_ASSERTION(mSize < end, "This shouldn't happen!"); mSize = end; return true; } mOriginInfo->mUsage = newUsage; groupInfo->mUsage = groupInfo->mUsage - mSize + end; mSize = end; return true; } NS_ASSERTION(groupInfo->mPersistenceType == PERSISTENCE_TYPE_TEMPORARY, "Huh?"); uint64_t delta = end - mSize; uint64_t newUsage = mOriginInfo->mUsage + delta; // Temporary storage has no limit for origin usage (there's a group and the // global limit though). uint64_t newGroupUsage = groupInfo->mUsage + delta; // Temporary storage has a hard limit for group usage (20 % of the global // limit). if (newGroupUsage > quotaManager->GetGroupLimit()) { return false; } uint64_t newTemporaryStorageUsage = quotaManager->mTemporaryStorageUsage + delta; if (newTemporaryStorageUsage > quotaManager->mTemporaryStorageLimit) { // This will block the thread without holding the lock while waitting. nsAutoTArray<OriginInfo*, 10> originInfos; uint64_t sizeToBeFreed = quotaManager->LockedCollectOriginsForEviction(delta, originInfos); if (!sizeToBeFreed) { return false; } NS_ASSERTION(sizeToBeFreed >= delta, "Huh?"); { MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex); for (uint32_t i = 0; i < originInfos.Length(); i++) { quotaManager->DeleteTemporaryFilesForOrigin(originInfos[i]->mOrigin); } } // Relocked. NS_ASSERTION(mOriginInfo, "How come?!"); nsTArray<nsCString> origins; for (uint32_t i = 0; i < originInfos.Length(); i++) { OriginInfo* originInfo = originInfos[i]; NS_ASSERTION(originInfo != mOriginInfo, "Deleted itself!"); nsCString group = originInfo->mGroupInfo->mGroup; nsCString origin = originInfo->mOrigin; quotaManager->LockedRemoveQuotaForOrigin(PERSISTENCE_TYPE_TEMPORARY, group, origin); #ifdef DEBUG originInfos[i] = nullptr; #endif origins.AppendElement(origin); } // We unlocked and relocked several times so we need to recompute all the // essential variables and recheck the group limit. delta = end - mSize; newUsage = mOriginInfo->mUsage + delta; newGroupUsage = groupInfo->mUsage + delta; if (newGroupUsage > quotaManager->GetGroupLimit()) { // Unfortunately some other thread increased the group usage in the // meantime and we are not below the group limit anymore. // However, the origin eviction must be finalized in this case too. MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex); quotaManager->FinalizeOriginEviction(origins); return false; } newTemporaryStorageUsage = quotaManager->mTemporaryStorageUsage + delta; NS_ASSERTION(newTemporaryStorageUsage <= quotaManager->mTemporaryStorageLimit, "How come?!"); // Ok, we successfully freed enough space and the operation can continue // without throwing the quota error. mOriginInfo->mUsage = newUsage; groupInfo->mUsage = newGroupUsage; quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage;; // Some other thread could increase the size in the meantime, but no more // than this one. NS_ASSERTION(mSize < end, "This shouldn't happen!"); mSize = end; // Finally, release IO thread only objects and allow next synchronized // ops for the evicted origins. MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex); quotaManager->FinalizeOriginEviction(origins); return true; } mOriginInfo->mUsage = newUsage; groupInfo->mUsage = newGroupUsage; quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage; mSize = end; return true; }
bool QuotaObject::MaybeUpdateSize(int64_t aSize, bool aTruncate) { QuotaManager* quotaManager = QuotaManager::Get(); MOZ_ASSERT(quotaManager); MutexAutoLock lock(quotaManager->mQuotaMutex); if (mSize == aSize) { return true; } if (!mOriginInfo) { mSize = aSize; return true; } GroupInfo* groupInfo = mOriginInfo->mGroupInfo; MOZ_ASSERT(groupInfo); if (mSize > aSize) { if (aTruncate) { const int64_t delta = mSize - aSize; AssertNoUnderflow(quotaManager->mTemporaryStorageUsage, delta); quotaManager->mTemporaryStorageUsage -= delta; AssertNoUnderflow(groupInfo->mUsage, delta); groupInfo->mUsage -= delta; AssertNoUnderflow(mOriginInfo->mUsage, delta); mOriginInfo->mUsage -= delta; mSize = aSize; } return true; } MOZ_ASSERT(mSize < aSize); nsRefPtr<GroupInfo> complementaryGroupInfo = groupInfo->mGroupInfoPair->LockedGetGroupInfo( ComplementaryPersistenceType(groupInfo->mPersistenceType)); uint64_t delta = aSize - mSize; AssertNoOverflow(mOriginInfo->mUsage, delta); uint64_t newUsage = mOriginInfo->mUsage + delta; // Temporary storage has no limit for origin usage (there's a group and the // global limit though). AssertNoOverflow(groupInfo->mUsage, delta); uint64_t newGroupUsage = groupInfo->mUsage + delta; uint64_t groupUsage = groupInfo->mUsage; if (complementaryGroupInfo) { AssertNoOverflow(groupUsage, complementaryGroupInfo->mUsage); groupUsage += complementaryGroupInfo->mUsage; } // Temporary storage has a hard limit for group usage (20 % of the global // limit). AssertNoOverflow(groupUsage, delta); if (groupUsage + delta > quotaManager->GetGroupLimit()) { return false; } AssertNoOverflow(quotaManager->mTemporaryStorageUsage, delta); uint64_t newTemporaryStorageUsage = quotaManager->mTemporaryStorageUsage + delta; if (newTemporaryStorageUsage > quotaManager->mTemporaryStorageLimit) { // This will block the thread without holding the lock while waitting. nsAutoTArray<OriginInfo*, 10> originInfos; uint64_t sizeToBeFreed = quotaManager->LockedCollectOriginsForEviction(delta, originInfos); if (!sizeToBeFreed) { return false; } NS_ASSERTION(sizeToBeFreed >= delta, "Huh?"); { MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex); for (uint32_t i = 0; i < originInfos.Length(); i++) { OriginInfo* originInfo = originInfos[i]; quotaManager->DeleteFilesForOrigin( originInfo->mGroupInfo->mPersistenceType, originInfo->mOrigin); } } // Relocked. NS_ASSERTION(mOriginInfo, "How come?!"); nsTArray<OriginParams> origins; for (uint32_t i = 0; i < originInfos.Length(); i++) { OriginInfo* originInfo = originInfos[i]; NS_ASSERTION(originInfo != mOriginInfo, "Deleted itself!"); PersistenceType persistenceType = originInfo->mGroupInfo->mPersistenceType; nsCString group = originInfo->mGroupInfo->mGroup; nsCString origin = originInfo->mOrigin; bool isApp = originInfo->mIsApp; quotaManager->LockedRemoveQuotaForOrigin(persistenceType, group, origin); #ifdef DEBUG originInfos[i] = nullptr; #endif origins.AppendElement(OriginParams(persistenceType, origin, isApp)); } // We unlocked and relocked several times so we need to recompute all the // essential variables and recheck the group limit. AssertNoUnderflow(aSize, mSize); delta = aSize - mSize; AssertNoOverflow(mOriginInfo->mUsage, delta); newUsage = mOriginInfo->mUsage + delta; AssertNoOverflow(groupInfo->mUsage, delta); newGroupUsage = groupInfo->mUsage + delta; groupUsage = groupInfo->mUsage; if (complementaryGroupInfo) { AssertNoOverflow(groupUsage, complementaryGroupInfo->mUsage); groupUsage += complementaryGroupInfo->mUsage; } AssertNoOverflow(groupUsage, delta); if (groupUsage + delta > quotaManager->GetGroupLimit()) { // Unfortunately some other thread increased the group usage in the // meantime and we are not below the group limit anymore. // However, the origin eviction must be finalized in this case too. MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex); quotaManager->FinalizeOriginEviction(origins); return false; } AssertNoOverflow(quotaManager->mTemporaryStorageUsage, delta); newTemporaryStorageUsage = quotaManager->mTemporaryStorageUsage + delta; NS_ASSERTION(newTemporaryStorageUsage <= quotaManager->mTemporaryStorageLimit, "How come?!"); // Ok, we successfully freed enough space and the operation can continue // without throwing the quota error. mOriginInfo->mUsage = newUsage; groupInfo->mUsage = newGroupUsage; quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage;; // Some other thread could increase the size in the meantime, but no more // than this one. MOZ_ASSERT(mSize < aSize); mSize = aSize; // Finally, release IO thread only objects and allow next synchronized // ops for the evicted origins. MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex); quotaManager->FinalizeOriginEviction(origins); return true; } mOriginInfo->mUsage = newUsage; groupInfo->mUsage = newGroupUsage; quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage; mSize = aSize; return true; }