// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "zstd-compressed-block-collection.h"

#include <lib/fzl/vmo-mapper.h>
#include <lib/trace/event.h>
#include <stddef.h>
#include <stdint.h>
#include <zircon/device/block.h>
#include <zircon/status.h>
#include <zircon/types.h>

#include <cstring>
#include <limits>
#include <memory>

#include <blobfs/node-finder.h>
#include <fs/trace.h>
#include <storage/buffer/owned_vmoid.h>

#include "allocator/allocator.h"
#include "iterator/allocated-extent-iterator.h"
#include "iterator/block-iterator.h"
#include "zstd-seekable-block-cache.h"
#include "zstd-seekable.h"

namespace blobfs {

ZSTDCompressedBlockCollectionImpl::ZSTDCompressedBlockCollectionImpl(
    fzl::VmoMapper* vmo_mapper, storage::OwnedVmoid* vmoid, uint32_t num_vmo_blocks,
    SpaceManager* space_manager, fs::LegacyTransactionHandler* txn_handler, NodeFinder* node_finder,
    uint32_t node_index, uint32_t num_merkle_blocks)
    : vmo_mapper_(vmo_mapper),
      vmoid_(vmoid),
      num_vmo_blocks_(num_vmo_blocks),
      space_manager_(space_manager),
      txn_handler_(txn_handler),
      node_finder_(node_finder),
      node_index_(node_index),
      num_merkle_blocks_(num_merkle_blocks) {
  InodePtr inode = node_finder->GetNode(node_index);
  ZX_DEBUG_ASSERT(inode != nullptr);
  ZX_DEBUG_ASSERT(inode->block_count >= num_merkle_blocks);
  const uint32_t num_data_blocks = inode->block_count - num_merkle_blocks;
  if (num_data_blocks > 0) {
    cache_ = std::make_unique<ZSTDSeekableDefaultBlockCache>(num_data_blocks);
  }
}

zx_status_t ZSTDCompressedBlockCollectionImpl::Read(uint32_t data_block_offset,
                                                    uint32_t num_blocks) {
  TRACE_DURATION("blobfs", "ZSTDCompressedBlockCollectionImpl::Read", "node index", node_index_,
                 "data block offset", data_block_offset, "number of blocks", num_blocks);

  fs::ReadTxn txn(txn_handler_);

  uint64_t blob_block_offset64 =
      static_cast<uint64_t>(num_merkle_blocks_) + static_cast<uint64_t>(data_block_offset);
  if (blob_block_offset64 > std::numeric_limits<uint32_t>::max()) {
    FS_TRACE_ERROR("[blobfs][zstd] Block offset overflow\n");
    return ZX_ERR_OUT_OF_RANGE;
  }
  uint32_t blob_block_offset = static_cast<uint32_t>(blob_block_offset64);

  // Consult cache on one-block reads. Early return on cache hit.
  bool first_block_cached = false;
  if (cache_ != nullptr) {
    TRACE_DURATION("blobfs", "ZSTDCompressedBlockCollectionImpl::Read::ReadCache");
    zx_status_t status =
        cache_->ReadBlock(static_cast<uint8_t*>(vmo_mapper_->start()), data_block_offset);
    if (status == ZX_OK) {
      if (num_blocks == 1) {
        return ZX_OK;
      }

      first_block_cached = true;
    }
  }

  // Iterate to blocks and enqueue reads into VMO which backs |vmoid_|.
  {
    TRACE_DURATION("blobfs", "ZSTDCompressedBlockCollectionImpl::Read::Iterate", "blocks",
                   data_block_offset + num_blocks);
    BlockIterator iter(std::make_unique<AllocatedExtentIterator>(node_finder_, node_index_));
    zx_status_t status = IterateToBlock(&iter, blob_block_offset);
    if (status != ZX_OK) {
      FS_TRACE_ERROR("[blobfs][zstd] Failed to iterate to block at offset %u: %s\n",
                     blob_block_offset, zx_status_get_string(status));
    }

    // Lookup offset to BlobFS on block device; device offsets in |StreamBlocks| are relative to
    // this offset, but |txn| needs absolute block device offsets.
    uint64_t dev_data_start = DataStartBlock(space_manager_->Info());

    status = StreamBlocks(
        &iter, num_blocks,
        [&](uint64_t current_blob_block_offset, uint64_t dev_block_offset, uint32_t n_blocks) {
          // Sanity check offsets. Note that this does not catch attempting to read past the end of
          // the blob. This code assumes that |StreamBlocks| will return non-|ZX_OK| in that case.
          if (current_blob_block_offset < blob_block_offset ||
              current_blob_block_offset - blob_block_offset > num_blocks ||
              current_blob_block_offset - blob_block_offset + n_blocks > num_vmo_blocks_) {
            FS_TRACE_ERROR("[blobfs][zstd] Attempt to enqueue read at out-of-bounds VMO offset\n");
            return ZX_ERR_OUT_OF_RANGE;
          }

          uint64_t actual_vmo_block_offset = current_blob_block_offset - blob_block_offset;
          uint64_t actual_dev_block_offset = dev_data_start + dev_block_offset;

          // Adjust offsets and number of blocks when skipping the first block (because it was
          // cached).
          if (first_block_cached && actual_vmo_block_offset == 0) {
            // Should have early exit if only reading one block.
            ZX_DEBUG_ASSERT(n_blocks > 1);
            // Skip first block that would have been read (because it was cached).
            txn.Enqueue(vmoid_->get(), actual_vmo_block_offset + 1, actual_dev_block_offset + 1,
                        n_blocks - 1);
          } else {
            txn.Enqueue(vmoid_->get(), actual_vmo_block_offset, actual_dev_block_offset, n_blocks);
          }
          return ZX_OK;
        });
    if (status != ZX_OK) {
      return status;
    }
  }

  // Read blocks into VMO which backs |vmoid_|.
  {
    TRACE_DURATION("blobfs", "ZSTDCompressedBlockCollectionImpl::Read::Transact", "blocks",
                   num_blocks);
    txn.Transact();
  }

  if (cache_ != nullptr) {
    TRACE_DURATION("blobfs", "ZSTDCompressedBlockCollectionImpl::Read::WriteCache");

    // TODO(markdittmer): This is a tight coupling between the collection and cache. It would be
    // better to delegate this logic to some kind of caching strategy object.

    // Corner case: More than one block starting at first block: Include first block in cache.
    if (data_block_offset == 0 && num_blocks > 1) {
      cache_->WriteBlock(static_cast<uint8_t*>(vmo_mapper_->start()), 0);
    }

    // Usual case: Cache last block read.
    cache_->WriteBlock(
        static_cast<uint8_t*>(vmo_mapper_->start()) + ((num_blocks - 1) * kBlobfsBlockSize),
        data_block_offset + num_blocks - 1);
  }

  return ZX_OK;
}

}  // namespace blobfs
