Example #1
0
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));
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
void CacheEntry::OnOutputClosed()
{
  // Called when the file's output stream is closed.  Invoke any callbacks
  // waiting for complete entry.

  mozilla::MutexAutoLock lock(mLock);
  InvokeCallbacks();
}
Example #5
0
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();
  }
}
Example #6
0
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();
  }
}
Example #7
0
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;
}
Example #8
0
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;
}
Example #9
0
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();
  }
}
Example #10
0
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;
}
Example #11
0
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 );
	}
}
Example #13
0
void CacheEntry::InvokeCallbacksLock()
{
  mozilla::MutexAutoLock lock(mLock);
  InvokeCallbacks();
}
Example #14
0
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();
  }
}