blob: e37f2618d7432c72ef8e80550453548995a3b1da [file] [log] [blame]
// 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 <lib/fzl/vmo-mapper.h>
#include <lib/zx/vmo.h>
#include <stddef.h>
#include <stdint.h>
#include <zircon/device/block.h>
#include <zircon/types.h>
#include <memory>
#include <blobfs/node-finder.h>
#include <fbl/macros.h>
#include <fs/transaction/legacy_transaction_handler.h>
#include <storage/buffer/owned_vmoid.h>
#include <storage/buffer/vmoid_registry.h>
#include "allocator/allocator.h"
#include "compression/zstd-seekable-blob-cache.h"
#include "compression/zstd-seekable.h"
namespace blobfs {
constexpr size_t kZSTDSeekableBlobCacheSize = 128;
// The number of bytes for the singleton transfer buffer that reads from storage in the compressed
// case. The choice to use a singleton buffer is somewhat arbitrary, but it simplifies code that
// would otherwise have to manage a pool of buffers or create and destroy them for every blob.
// This is analagous to |kTransferBufferSize| for compressed blobs. The buffer must be large enough
// to comfortably service individual reads in compressed space from any supported decompression
// strategy. Unlike the uncompressed case, pages are not passed off to client-owned VMOs in this
// case, so pages will not be decommitted by construction. Hence, this value should be sufficiently
// large but no larger.
constexpr uint64_t kCompressedTransferBufferBytes = fbl::round_up(
std::max<uint64_t>(kZSTDSeekableHeaderSize, 4 * kZSTDSeekableMaxFrameSize), kBlobfsBlockSize);
// The number of blocks for the singleton transfer buffer that reads from storage in the compressed
// case. Due to the types used in contexts that need this value, it is necessary to be assured that
// it fits inside a |uint32_t|.
static_assert(kCompressedTransferBufferBytes / kBlobfsBlockSize <=
constexpr uint32_t kCompressedTransferBufferBlocks =
static_cast<uint32_t>(kCompressedTransferBufferBytes / kBlobfsBlockSize);
// ZSTDSeekableBlobCollection is a container for accessing compressed blobs. This container stores
// data shared between compressed blobs such as a single storage/VMO transfer buffer.
class ZSTDSeekableBlobCollection {
static zx_status_t Create(storage::VmoidRegistry* vmoid_registry, SpaceManager* space_manager,
fs::LegacyTransactionHandler* txn_handler, NodeFinder* node_finder,
std::unique_ptr<ZSTDSeekableBlobCollection>* out);
// Load exactly |num_bytes| bytes starting at _uncompressed_ file contents byte offset
// |data_byte_offset| from blob identified by inode index |node_index| into |buf|. The value of
// data in |buf| is expected to be valid if and only if the return value is |ZX_OK|.
zx_status_t Read(uint32_t node_index, uint8_t* buf, uint64_t buf_size, uint64_t* data_byte_offset,
uint64_t* num_bytes);
ZSTDSeekableBlobCollection(storage::VmoidRegistry* vmoid_registry, SpaceManager* space_manager,
fs::LegacyTransactionHandler* txn_handler, NodeFinder* node_finder,
size_t cache_size);
// Parameters passed through to |ZSTDCompressedBlockCollection| construction.
SpaceManager* space_manager_;
fs::LegacyTransactionHandler* txn_handler_;
NodeFinder* node_finder_;
// Storage transfer VMO, its ID from binding it to a block device, and its mapping in memory.
// It is safe to keep this VMO mapped and pass it to inidividual blobs for each read because
// all components involved in compressed blob reads:
// 1. Run in the same thread,
// and
// 2. Synchronously wait for their data to arrive in |transfer_vmo_|, then:
// a) Decompress and discard the data before requesting more,
// or
// b) Copy the data before requesting more.
zx::vmo transfer_vmo_;
storage::OwnedVmoid vmoid_;
fzl::VmoMapper mapped_vmo_;
ZSTDSeekableLRUBlobCache cache_;
ZSTD_DStream* d_stream_;
} // namespace blobfs