nsresult FileBlockCache::Run() { MonitorAutoLock mon(mDataMonitor); NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread"); NS_ASSERTION(!mChangeIndexList.empty(), "Only dispatch when there's work to do"); NS_ASSERTION(mIsWriteScheduled, "Should report write running or scheduled."); while (!mChangeIndexList.empty()) { if (!mIsOpen) { // We've been closed, abort, discarding unwritten changes. mIsWriteScheduled = false; return NS_ERROR_FAILURE; } // Process each pending change. We pop the index out of the change // list, but leave the BlockChange in mBlockChanges until the change // is written to file. This is so that any read which happens while // we drop mDataMonitor to write will refer to the data's source in // memory, rather than the not-yet up to date data written to file. // This also ensures we will insert a new index into mChangeIndexList // when this happens. // Hold a reference to the change, in case another change // overwrites the mBlockChanges entry for this block while we drop // mDataMonitor to take mFileMonitor. int32_t blockIndex = mChangeIndexList.front(); mChangeIndexList.pop_front(); RefPtr<BlockChange> change = mBlockChanges[blockIndex]; MOZ_ASSERT(change, "Change index list should only contain entries for blocks " "with changes"); { MonitorAutoUnlock unlock(mDataMonitor); MonitorAutoLock lock(mFileMonitor); if (change->IsWrite()) { WriteBlockToFile(blockIndex, change->mData.get()); } else if (change->IsMove()) { MoveBlockInFile(change->mSourceBlockIndex, blockIndex); } } // If a new change has not been made to the block while we dropped // mDataMonitor, clear reference to the old change. Otherwise, the old // reference has been cleared already. if (mBlockChanges[blockIndex] == change) { mBlockChanges[blockIndex] = nullptr; } } mIsWriteScheduled = false; return NS_OK; }
nsresult FileBlockCache::MoveBlockInFile(int32_t aSourceBlockIndex, int32_t aDestBlockIndex) { mFileMonitor.AssertCurrentThreadOwns(); uint8_t buf[BLOCK_SIZE]; int32_t bytesRead = 0; if (NS_FAILED(ReadFromFile(BlockIndexToOffset(aSourceBlockIndex), buf, BLOCK_SIZE, bytesRead))) { return NS_ERROR_FAILURE; } return WriteBlockToFile(aDestBlockIndex, buf); }
nsresult FileBlockCache::MoveBlockInFile(PRInt32 aSourceBlockIndex, PRInt32 aDestBlockIndex) { mFileMonitor.AssertCurrentThreadOwns(); PRUint8 buf[BLOCK_SIZE]; PRInt32 bytesRead = 0; if (NS_FAILED(ReadFromFile(aSourceBlockIndex * BLOCK_SIZE, buf, BLOCK_SIZE, bytesRead))) { return NS_ERROR_FAILURE; } return WriteBlockToFile(aDestBlockIndex, buf); }