std::unique_ptr readRecord()

in cachelib/navy/serialization/RecordIO.cpp [150:218]


  std::unique_ptr<folly::IOBuf> readRecord() override {
    bool readHeader = true;
    std::unique_ptr<folly::IOBuf> buf = nullptr;
    uint8_t* bufferData = buffer_.data();
    uint64_t size = 0;
    uint8_t* data = nullptr;
    auto dataOffset = 0;

    do {
      // This is true when we have to read a header and there are not
      // enough bytes in the buffer OR we have to read the next block
      // in the multi-block read
      if (bufIndex_ + headerSize() > kBlockSize) {
        // read new block from the device if the number of bytes left from
        // previous read are less than header size.
        if (offset_ + kBlockSize > metadataSize_) {
          throw std::logic_error("exceeding metadata limit");
        }
        // read from device to the middle of the buffer 'kReadOffset'
        if (!dev_.read(offset_, kBlockSize, bufferData)) {
          throw std::invalid_argument(
              folly::sformat("read failed: offset = {}", offset_));
        }
        offset_ += kBlockSize;
        bufIndex_ = 0;
      }

      // Parse the header if we are expecting header
      if (readHeader) {
        readHeader = false;
        auto valid = validateRecordHeader(
            folly::Range<unsigned char*>(&bufferData[bufIndex_],
                                         kBlockSize - bufIndex_),
            kMetadataHeaderFileId);
        if (!valid) {
          throw std::logic_error("Invalid record header");
        }

        recordio_detail::Header* h =
            reinterpret_cast<recordio_detail::Header*>(&bufferData[bufIndex_]);
        size = headerSize() + h->dataLength;
        // copy the header also to IOBuf so that we can do validation
        buf = folly::IOBuf::create(size);
        if (buf == nullptr) {
          return nullptr;
        }
        buf->append(size);
        data = buf->writableData();
        dataOffset = 0;
      }
      auto cpSize =
          std::min(static_cast<uint64_t>(kBlockSize - bufIndex_), size);
      memcpy(data + dataOffset, &bufferData[bufIndex_], cpSize);
      bufIndex_ += cpSize;
      dataOffset += cpSize;
      size -= cpSize;
    } while (size > 0);
    // Validate the what we just read from the device
    auto record =
        validateRecordData(folly::Range<unsigned char*>(data, buf->length()));
    if (record.fileId == 0) {
      throw std::invalid_argument(folly::sformat(
          "Invalid record : offset = {}, length = {}", offset_, buf->length()));
    }
    // skip the header part and return
    buf->trimStart(headerSize());

    return buf;
  }