nsresult MemoryBlockCache::MoveBlock(int32_t aSourceBlockIndex, int32_t aDestBlockIndex) { MutexAutoLock lock(mMutex); size_t sourceOffset = BlockIndexToOffset(aSourceBlockIndex); size_t destOffset = BlockIndexToOffset(aDestBlockIndex); if (sourceOffset + BLOCK_SIZE > mBuffer.Length()) { LOG("MoveBlock() MEMORYBLOCKCACHE_ERRORS='MoveBlockSourceOverrun'"); Telemetry::Accumulate(Telemetry::HistogramID::MEMORYBLOCKCACHE_ERRORS, MoveBlockSourceOverrun); return NS_ERROR_FAILURE; } if (destOffset + BLOCK_SIZE > mBuffer.Length() && !mHasGrown) { LOG("MoveBlock() MEMORYBLOCKCACHE_ERRORS='MoveBlockDestOverflow'"); Telemetry::Accumulate(Telemetry::HistogramID::MEMORYBLOCKCACHE_ERRORS, MoveBlockDestOverflow); } if (!EnsureBufferCanContain(destOffset + BLOCK_SIZE)) { LOG("MoveBlock() MEMORYBLOCKCACHE_ERRORS='MoveBlockCannotGrow'"); Telemetry::Accumulate(Telemetry::HistogramID::MEMORYBLOCKCACHE_ERRORS, MoveBlockCannotGrow); return NS_ERROR_FAILURE; } memcpy(mBuffer.Elements() + destOffset, mBuffer.Elements() + sourceOffset, BLOCK_SIZE); return NS_OK; }
nsresult MemoryBlockCache::WriteBlock(uint32_t aBlockIndex, Span<const uint8_t> aData1, Span<const uint8_t> aData2) { MutexAutoLock lock(mMutex); size_t offset = BlockIndexToOffset(aBlockIndex); if (offset + aData1.Length() + aData2.Length() > mBuffer.Length() && !mHasGrown) { LOG("WriteBlock() MEMORYBLOCKCACHE_ERRORS='WriteBlockOverflow'"); Telemetry::Accumulate(Telemetry::HistogramID::MEMORYBLOCKCACHE_ERRORS, WriteBlockOverflow); } if (!EnsureBufferCanContain(offset + aData1.Length() + aData2.Length())) { LOG("WriteBlock() MEMORYBLOCKCACHE_ERRORS='WriteBlockCannotGrow'"); Telemetry::Accumulate(Telemetry::HistogramID::MEMORYBLOCKCACHE_ERRORS, WriteBlockCannotGrow); return NS_ERROR_FAILURE; } memcpy(mBuffer.Elements() + offset, aData1.Elements(), aData1.Length()); if (aData2.Length() > 0) { memcpy(mBuffer.Elements() + offset + aData1.Length(), aData2.Elements(), aData2.Length()); } return NS_OK; }
nsresult FileBlockCache::Read(int64_t aOffset, uint8_t* aData, int32_t aLength, int32_t* aBytes) { MonitorAutoLock mon(mDataMonitor); if (!mFD || (aOffset / BLOCK_SIZE) > INT32_MAX) return NS_ERROR_FAILURE; int32_t bytesToRead = aLength; int64_t offset = aOffset; uint8_t* dst = aData; while (bytesToRead > 0) { int32_t blockIndex = static_cast<int32_t>(offset / BLOCK_SIZE); int32_t start = offset % BLOCK_SIZE; int32_t amount = std::min(BLOCK_SIZE - start, bytesToRead); // If the block is not yet written to file, we can just read from // the memory buffer, otherwise we need to read from file. int32_t bytesRead = 0; nsRefPtr<BlockChange> change = mBlockChanges[blockIndex]; if (change && change->IsWrite()) { // Block isn't yet written to file. Read from memory buffer. const uint8_t* blockData = change->mData.get(); memcpy(dst, blockData + start, amount); bytesRead = amount; } else { if (change && change->IsMove()) { // The target block is the destination of a not-yet-completed move // action, so read from the move's source block from file. Note we // *don't* follow a chain of moves here, as a move's source index // is resolved when MoveBlock() is called, and the move's source's // block could be have itself been subject to a move (or write) // which happened *after* this move was recorded. blockIndex = mBlockChanges[blockIndex]->mSourceBlockIndex; } // Block has been written to file, either as the source block of a move, // or as a stable (all changes made) block. Read the data directly // from file. nsresult res; { MonitorAutoUnlock unlock(mDataMonitor); MonitorAutoLock lock(mFileMonitor); res = ReadFromFile(BlockIndexToOffset(blockIndex) + start, dst, amount, bytesRead); } NS_ENSURE_SUCCESS(res,res); } dst += bytesRead; offset += bytesRead; bytesToRead -= bytesRead; } *aBytes = aLength - bytesToRead; 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::WriteBlockToFile(int32_t aBlockIndex, const uint8_t* aBlockData) { mFileMonitor.AssertCurrentThreadOwns(); nsresult rv = Seek(BlockIndexToOffset(aBlockIndex)); if (NS_FAILED(rv)) return rv; int32_t amount = PR_Write(mFD, aBlockData, BLOCK_SIZE); if (amount < BLOCK_SIZE) { NS_WARNING("Failed to write media cache block!"); return NS_ERROR_FAILURE; } mFDCurrentPos += BLOCK_SIZE; return NS_OK; }