void CacheEntry::InvokeCallbacks() { mLock.AssertCurrentThreadOwns(); LOG(("CacheEntry::InvokeCallbacks BEGIN [this=%p]", this)); // Invoke first all r/w callbacks, then all r/o callbacks. if (InvokeCallbacks(false)) InvokeCallbacks(true); LOG(("CacheEntry::InvokeCallbacks END [this=%p]", this)); }
NS_IMETHODIMP CacheEntry::SetValid() { LOG(("CacheEntry::SetValid [this=%p, state=%s]", this, StateString(mState))); nsCOMPtr<nsIOutputStream> outputStream; { mozilla::MutexAutoLock lock(mLock); MOZ_ASSERT(mState > EMPTY); mState = READY; mHasData = true; InvokeCallbacks(); outputStream.swap(mOutputStream); } if (outputStream) { LOG((" abandoning phantom output stream")); outputStream->Close(); } return NS_OK; }
NS_IMETHODIMP CacheEntry::OpenOutputStream(int64_t offset, nsIOutputStream * *_retval) { LOG(("CacheEntry::OpenOutputStream [this=%p]", this)); nsresult rv; mozilla::MutexAutoLock lock(mLock); MOZ_ASSERT(mState > EMPTY); if (mOutputStream && !mIsDoomed) { LOG((" giving phantom output stream")); mOutputStream.forget(_retval); } else { rv = OpenOutputStreamInternal(offset, _retval); if (NS_FAILED(rv)) return rv; } // Entry considered ready when writer opens output stream. if (mState < READY) mState = READY; // Invoke any pending readers now. InvokeCallbacks(); return NS_OK; }
void CacheEntry::OnOutputClosed() { // Called when the file's output stream is closed. Invoke any callbacks // waiting for complete entry. mozilla::MutexAutoLock lock(mLock); InvokeCallbacks(); }
void CacheEntry::BackgroundOp(uint32_t aOperations, bool aForceAsync) { mLock.AssertCurrentThreadOwns(); if (!CacheStorageService::IsOnManagementThread() || aForceAsync) { if (mBackgroundOperations.Set(aOperations)) CacheStorageService::Self()->Dispatch(this); LOG(("CacheEntry::BackgroundOp this=%p dipatch of %x", this, aOperations)); return; } mozilla::MutexAutoUnlock unlock(mLock); MOZ_ASSERT(CacheStorageService::IsOnManagementThread()); if (aOperations & Ops::FRECENCYUPDATE) { #ifndef M_LN2 #define M_LN2 0.69314718055994530942 #endif // Half-life is 90 days. static double const half_life = 90.0 * (24 * 60 * 60); // Must convert from seconds to milliseconds since PR_Now() gives usecs. static double const decay = (M_LN2 / half_life) / static_cast<double>(PR_USEC_PER_SEC); double now_decay = static_cast<double>(PR_Now()) * decay; if (mFrecency == 0) { mFrecency = now_decay; } else { // TODO: when C++11 enabled, use std::log1p(n) which is equal to log(n + 1) but // more precise. mFrecency = log(exp(mFrecency - now_decay) + 1) + now_decay; } LOG(("CacheEntry FRECENCYUPDATE [this=%p, frecency=%1.10f]", this, mFrecency)); } if (aOperations & Ops::REGISTER) { LOG(("CacheEntry REGISTER [this=%p]", this)); CacheStorageService::Self()->RegisterEntry(this); } if (aOperations & Ops::DOOM) { LOG(("CacheEntry DOOM [this=%p]", this)); DoomAlreadyRemoved(); } if (aOperations & Ops::CALLBACKS) { LOG(("CacheEntry CALLBACKS (invoke) [this=%p]", this)); mozilla::MutexAutoLock lock(mLock); InvokeCallbacks(); } }
void CacheEntry::OnHandleClosed(CacheEntryHandle const* aHandle) { LOG(("CacheEntry::OnHandleClosed [this=%p, state=%s, handle=%p]", this, StateString(mState), aHandle)); nsCOMPtr<nsIOutputStream> outputStream; { mozilla::MutexAutoLock lock(mLock); if (mWriter != aHandle) { LOG((" not the writer")); return; } if (mOutputStream) { // No one took our internal output stream, so there are no data // and output stream has to be open symultaneously with input stream // on this entry again. mHasData = false; } outputStream.swap(mOutputStream); mWriter = nullptr; if (mState == WRITING) { LOG((" reverting to state EMPTY - write failed")); mState = EMPTY; } else if (mState == REVALIDATING) { LOG((" reverting to state READY - reval failed")); mState = READY; } if (mState == READY && !mHasData) { // We may get to this state when following steps happen: // 1. a new entry is given to a consumer // 2. the consumer calls MetaDataReady(), we transit to READY // 3. abandons the entry w/o opening the output stream, mHasData left false // // In this case any following consumer will get a ready entry (with metadata) // but in state like the entry data write was still happening (was in progress) // and will indefinitely wait for the entry data or even the entry itself when // RECHECK_AFTER_WRITE is returned from onCacheEntryCheck. LOG((" we are in READY state, pretend we have data regardless it" " has actully been never touched")); mHasData = true; } InvokeCallbacks(); } if (outputStream) { LOG((" abandoning phantom output stream")); outputStream->Close(); } }
NS_IMETHODIMP CacheEntry::MetaDataReady() { mozilla::MutexAutoLock lock(mLock); LOG(("CacheEntry::MetaDataReady [this=%p, state=%s]", this, StateString(mState))); MOZ_ASSERT(mState > EMPTY); if (mState == WRITING) mState = READY; InvokeCallbacks(); return NS_OK; }
NS_IMETHODIMP CacheEntry::OnFileReady(nsresult aResult, bool aIsNew) { LOG(("CacheEntry::OnFileReady [this=%p, rv=0x%08x, new=%d]", this, aResult, aIsNew)); MOZ_ASSERT(!mLoadStart.IsNull()); if (NS_SUCCEEDED(aResult)) { if (aIsNew) { mozilla::Telemetry::AccumulateTimeDelta( mozilla::Telemetry::NETWORK_CACHE_V2_MISS_TIME_MS, mLoadStart); } else { mozilla::Telemetry::AccumulateTimeDelta( mozilla::Telemetry::NETWORK_CACHE_V2_HIT_TIME_MS, mLoadStart); } } // OnFileReady, that is the only code that can transit from LOADING // to any follow-on state, can only be invoked ones on an entry, // thus no need to lock. Until this moment there is no consumer that // could manipulate the entry state. mozilla::MutexAutoLock lock(mLock); MOZ_ASSERT(mState == LOADING); mState = (aIsNew || NS_FAILED(aResult)) ? EMPTY : READY; mFileStatus = aResult; if (mState == READY) { mHasData = true; uint32_t frecency; mFile->GetFrecency(&frecency); // mFrecency is held in a double to increase computance precision. // It is ok to persist frecency only as a uint32 with some math involved. mFrecency = INT2FRECENCY(frecency); } InvokeCallbacks(); return NS_OK; }
void CacheEntry::OnWriterClosed(Handle const* aHandle) { LOG(("CacheEntry::OnWriterClosed [this=%p, state=%s, handle=%p]", this, StateString(mState), aHandle)); nsCOMPtr<nsIOutputStream> outputStream; { mozilla::MutexAutoLock lock(mLock); if (mWriter != aHandle) { LOG((" not the current writer")); return; } if (mOutputStream) { // No one took our internal output stream, so there are no data // and output stream has to be open symultaneously with input stream // on this entry again. mHasData = false; } outputStream.swap(mOutputStream); mWriter = nullptr; if (mState == WRITING) { LOG((" reverting to state EMPTY - write failed")); mState = EMPTY; } else if (mState == REVALIDATING) { LOG((" reverting to state READY - reval failed")); mState = READY; } InvokeCallbacks(); } if (outputStream) { LOG((" abandoning phantom output stream")); outputStream->Close(); } }
NS_IMETHODIMP CacheEntry::OnFileReady(nsresult aResult, bool aIsNew) { LOG(("CacheEntry::OnFileReady [this=%p, rv=0x%08x, new=%d]", this, aResult, aIsNew)); MOZ_ASSERT(!mLoadStart.IsNull()); if (NS_SUCCEEDED(aResult)) { if (aIsNew) { mozilla::Telemetry::AccumulateTimeDelta( mozilla::Telemetry::NETWORK_CACHE_V2_MISS_TIME_MS, mLoadStart); } else { mozilla::Telemetry::AccumulateTimeDelta( mozilla::Telemetry::NETWORK_CACHE_V2_HIT_TIME_MS, mLoadStart); } } // OnFileReady, that is the only code that can transit from LOADING // to any follow-on state, can only be invoked ones on an entry, // thus no need to lock. Until this moment there is no consumer that // could manipulate the entry state. mozilla::MutexAutoLock lock(mLock); MOZ_ASSERT(mState == LOADING); mState = (aIsNew || NS_FAILED(aResult)) ? EMPTY : READY; mFileStatus = aResult; if (mState == READY) mHasData = true; InvokeCallbacks(); return NS_OK; }
bool CacheEntry::Open(Callback & aCallback, bool aTruncate, bool aPriority, bool aBypassIfBusy) { mozilla::MutexAutoLock lock(mLock); // Check state under the lock if (aBypassIfBusy && (mState == WRITING || mState == REVALIDATING)) { return false; } RememberCallback(aCallback); // Load() opens the lock if (Load(aTruncate, aPriority)) { // Loading is in progress... return true; } InvokeCallbacks(); return true; }
void CClientSteamContext::UpdateLoggedOnState() { bool bPreviousLoggedOn = m_bLoggedOn; m_bLoggedOn = ( SteamUser() && SteamUtils() && SteamUser()->BLoggedOn() ); if ( !bPreviousLoggedOn && m_bLoggedOn ) { // update Steam info m_SteamIDLocalPlayer = SteamUser()->GetSteamID(); m_nUniverse = SteamUtils()->GetConnectedUniverse(); m_nAppID = SteamUtils()->GetAppID(); } if ( bPreviousLoggedOn != m_bLoggedOn ) { // Notify any listeners of the change in logged on state SteamLoggedOnChange_t loggedOnChange; loggedOnChange.bPreviousLoggedOn = bPreviousLoggedOn; loggedOnChange.bLoggedOn = m_bLoggedOn; InvokeCallbacks( loggedOnChange ); } }
void CacheEntry::InvokeCallbacksLock() { mozilla::MutexAutoLock lock(mLock); InvokeCallbacks(); }
void CacheEntry::BackgroundOp(uint32_t aOperations, bool aForceAsync) { mLock.AssertCurrentThreadOwns(); if (!CacheStorageService::IsOnManagementThread() || aForceAsync) { if (mBackgroundOperations.Set(aOperations)) CacheStorageService::Self()->Dispatch(this); LOG(("CacheEntry::BackgroundOp this=%p dipatch of %x", this, aOperations)); return; } { mozilla::MutexAutoUnlock unlock(mLock); MOZ_ASSERT(CacheStorageService::IsOnManagementThread()); if (aOperations & Ops::FRECENCYUPDATE) { ++mUseCount; #ifndef M_LN2 #define M_LN2 0.69314718055994530942 #endif // Half-life is dynamic, in seconds. static double half_life = CacheObserver::HalfLifeSeconds(); // Must convert from seconds to milliseconds since PR_Now() gives usecs. static double const decay = (M_LN2 / half_life) / static_cast<double>(PR_USEC_PER_SEC); double now_decay = static_cast<double>(PR_Now()) * decay; if (mFrecency == 0) { mFrecency = now_decay; } else { // TODO: when C++11 enabled, use std::log1p(n) which is equal to log(n + 1) but // more precise. mFrecency = log(exp(mFrecency - now_decay) + 1) + now_decay; } LOG(("CacheEntry FRECENCYUPDATE [this=%p, frecency=%1.10f]", this, mFrecency)); // Because CacheFile::Set*() are not thread-safe to use (uses WeakReference that // is not thread-safe) we must post to the main thread... nsRefPtr<nsRunnableMethod<CacheEntry> > event = NS_NewRunnableMethodWithArg<double>(this, &CacheEntry::StoreFrecency, mFrecency); NS_DispatchToMainThread(event); } if (aOperations & Ops::REGISTER) { LOG(("CacheEntry REGISTER [this=%p]", this)); CacheStorageService::Self()->RegisterEntry(this); } if (aOperations & Ops::UNREGISTER) { LOG(("CacheEntry UNREGISTER [this=%p]", this)); CacheStorageService::Self()->UnregisterEntry(this); } } // unlock if (aOperations & Ops::CALLBACKS) { LOG(("CacheEntry CALLBACKS (invoke) [this=%p]", this)); InvokeCallbacks(); } }