예제 #1
0
size_t DiskCachingFileLoaderCache::SaveIntoCache(FileLoader *backend, s64 pos, size_t bytes, void *data, FileLoader::Flags flags) {
	lock_guard guard(lock_);

	if (!f_) {
		// Just to keep things working.
		return backend->ReadAt(pos, bytes, data, flags);
	}

	s64 cacheStartPos = pos / blockSize_;
	s64 cacheEndPos = (pos + bytes - 1) / blockSize_;
	size_t readSize = 0;
	size_t offset = (size_t)(pos - (cacheStartPos * (u64)blockSize_));
	u8 *p = (u8 *)data;

	size_t blocksToRead = 0;
	for (s64 i = cacheStartPos; i <= cacheEndPos; ++i) {
		auto &info = index_[i];
		if (info.block != INVALID_BLOCK) {
			break;
		}
		++blocksToRead;
		if (blocksToRead >= MAX_BLOCKS_PER_READ) {
			break;
		}
	}

	if (!MakeCacheSpaceFor(blocksToRead) || blocksToRead == 0) {
		return 0;
	}

	if (blocksToRead == 1) {
		auto &info = index_[cacheStartPos];

		u8 *buf = new u8[blockSize_];
		size_t readBytes = backend->ReadAt(cacheStartPos * (u64)blockSize_, blockSize_, buf, flags);

		// Check if it was written while we were busy.  Might happen if we thread.
		if (info.block == INVALID_BLOCK && readBytes != 0) {
			info.block = AllocateBlock((u32)cacheStartPos);
			WriteBlockData(info, buf);
			WriteIndexData((u32)cacheStartPos, info);
		}

		size_t toRead = std::min(bytes - readSize, (size_t)blockSize_ - offset);
		memcpy(p + readSize, buf + offset, toRead);
		readSize += toRead;

		delete [] buf;
	} else {
		u8 *wholeRead = new u8[blocksToRead * blockSize_];
		size_t readBytes = backend->ReadAt(cacheStartPos * (u64)blockSize_, blocksToRead * blockSize_, wholeRead, flags);

		for (size_t i = 0; i < blocksToRead; ++i) {
			auto &info = index_[cacheStartPos + i];
			// Check if it was written while we were busy.  Might happen if we thread.
			if (info.block == INVALID_BLOCK && readBytes != 0) {
				info.block = AllocateBlock((u32)cacheStartPos + (u32)i);
				WriteBlockData(info, wholeRead + (i * blockSize_));
				// TODO: Doing each index together would probably be better.
				WriteIndexData((u32)cacheStartPos + (u32)i, info);
			}

			size_t toRead = std::min(bytes - readSize, (size_t)blockSize_ - offset);
			memcpy(p + readSize, wholeRead + (i * blockSize_) + offset, toRead);
			readSize += toRead;
		}
		delete[] wholeRead;
	}

	cacheSize_ += blocksToRead;
	++generation_;

	if (generation_ == std::numeric_limits<u16>::max()) {
		RebalanceGenerations();
	}

	return readSize;
}
예제 #2
0
HRESULT CCoder::CodeReal(ISequentialInStream *anInStream, ISequentialOutStream *anOutStream, const UINT64 *anInSize)
{
  if (!m_Created)
  {
    RETURN_IF_NOT_S_OK(Create());
    m_Created = true;
  }

  UINT64 aNowPos = 0;
  m_FinderPos = 0;

  RETURN_IF_NOT_S_OK(m_MatchFinder.Init(anInStream));
  m_OutStream.Init(anOutStream);
  m_ReverseOutStream.Init(&m_OutStream);

  InitStructures();

  while(true)
  {
    int aCurrentPassIndex = 0;
    bool aNoMoreBytes;
    while (true)
    {
      while(true)
      {
        aNoMoreBytes = (m_AdditionalOffset == 0 && m_MatchFinder.GetNumAvailableBytes() == 0);
  
        if (((m_CurrentBlockUncompressedSize >= kBlockUncompressedSizeThreshold || 
                 m_ValueIndex >= kValueBlockSize) && 
              (m_OptimumEndIndex == m_OptimumCurrentIndex)) 
            || aNoMoreBytes)
          break;
        UINT32 aPos;
        UINT32 aLen = GetOptimal(aPos);
        if (aLen >= kMatchMinLen)
        {
          UINT32 aNewLen = aLen - kMatchMinLen;
          m_Values[m_ValueIndex].Flag = kFlagLenPos;
          m_Values[m_ValueIndex].Len = BYTE(aNewLen);
          UINT32 aLenSlot = g_LenSlots[aNewLen];
          m_MainCoder.AddSymbol(kMatchNumber + aLenSlot);
          m_Values[m_ValueIndex].Pos = UINT16(aPos);
          UINT32 aPosSlot = GetPosSlot(aPos);
          m_DistCoder.AddSymbol(aPosSlot);
        }
        else if (aLen == 1)  
        {
          BYTE aByte = m_MatchFinder.GetIndexByte(0 - m_AdditionalOffset);
          aLen = 1;
          m_MainCoder.AddSymbol(aByte);
          m_Values[m_ValueIndex].Flag = kFlagImm;
          m_Values[m_ValueIndex].Imm = aByte;
        }
        else
          throw E_INTERNAL_ERROR;
        m_ValueIndex++;
        m_AdditionalOffset -= aLen;
        aNowPos += aLen;
        m_CurrentBlockUncompressedSize += aLen;
        
      }
      aCurrentPassIndex++;
      bool aWriteMode = (aCurrentPassIndex == m_NumPasses);
      WriteBlockData(aWriteMode, aNoMoreBytes);
      if (aWriteMode)
        break;
      aNowPos = m_BlockStartPostion;
      m_AdditionalOffset = UINT32(m_FinderPos - m_BlockStartPostion);
      m_CurrentBlockUncompressedSize = 0;
    }
    m_BlockStartPostion += m_CurrentBlockUncompressedSize;
    m_CurrentBlockUncompressedSize = 0;
    if (aNoMoreBytes)
      break;
  }
  return  m_OutStream.Flush();
}