Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add llfs::IoRingStreamBuffer. #139

Merged
merged 6 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 27 additions & 16 deletions conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,44 @@
#+++++++++++-+-+--+----- --- -- - - - -

from conan import ConanFile
from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps
from conan.tools.files import copy

import os, sys, platform


#==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
# Import batt helper utilities module.
#
sys.path.append(os.path.join(os.path.dirname(__file__), 'script'))
import batt
import script.batt as batt
from script.batt import VISIBLE, OVERRIDE
#
#+++++++++++-+-+--+----- --- -- - - - -


class LlfsConan(ConanFile):
name = "llfs"

#----- --- -- - - - -
# version is set automatically from Git tags - DO NOT SET IT HERE
#----- --- -- - - - -

license = "Apache Public License 2.0"

author = "The MathWorks, Inc."

url = "https://github.com/mathworks/llfs"

description = "Low-Level File System Utilities (C++)"

settings = "os", "compiler", "build_type", "arch"
options = {"shared": [True, False]}
default_options = {"shared": False}

options = {
"shared": [True, False],
}

default_options = {
"shared": False,
}

build_policy = "missing"

exports = [
Expand All @@ -56,9 +69,7 @@ def configure(self):


def requirements(self):
from batt import VISIBLE, OVERRIDE

self.requires("batteries/0.49.6", **VISIBLE)
self.requires("batteries/0.50.2", **VISIBLE)
self.requires("boost/1.83.0", **VISIBLE)
self.requires("cli11/2.3.2", **VISIBLE)
self.requires("glog/0.6.0", **VISIBLE)
Expand All @@ -75,12 +86,12 @@ def requirements(self):

#+++++++++++-+-+--+----- --- -- - - - -

from batt import set_version_from_git_tags as set_version
from batt import cmake_in_src_layout as layout
from batt import default_cmake_generate as generate
from batt import default_cmake_build as build
from batt import default_cmake_lib_package as package
from batt import default_lib_package_info as package_info
from batt import default_lib_package_id as package_id
from script.batt import set_version_from_git_tags as set_version
from script.batt import cmake_in_src_layout as layout
from script.batt import default_cmake_generate as generate
from script.batt import default_cmake_build as build
from script.batt import default_cmake_lib_package as package
from script.batt import default_lib_package_info as package_info
from script.batt import default_lib_package_id as package_id

#+++++++++++-+-+--+----- --- -- - - - -
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ endmacro()
LLFS_DefineLibrary(llfs ./llfs
batteries::batteries
liburing::liburing
OpenSSL::Crypto
)

#=#=#==#==#===============+=+=+=+=++=++++++++++++++-++-+--+-+----+---------------
Expand Down Expand Up @@ -219,6 +220,7 @@ target_link_libraries(llfs_fuse
Boost::context
Boost::stacktrace_backtrace
libbacktrace::libbacktrace
OpenSSL::Crypto
CLI11::CLI11
dl
stdc++fs)
44 changes: 42 additions & 2 deletions src/llfs/buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include <batteries/buffer.hpp>

#include <memory>
#include <vector>

namespace llfs {
Expand All @@ -25,14 +26,18 @@ using batt::mutable_buffer_from_struct;
using batt::MutableBuffer;
using batt::resize_buffer;

// Returns the distance, in bytes, from `begin` to `end`. If `end` is less than `begin`, the result
// is negative.
//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
/** \brief Returns the distance, in bytes, from `begin` to `end`. If `end` is less than `begin`,
* the result is negative.
*/
inline isize byte_distance(const void* begin, const void* end)
{
return static_cast<const u8*>(end) - static_cast<const u8*>(begin);
}

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
/** \brief Returns an empty sequence of ConstBuffer objects.
*/
inline const std::vector<ConstBuffer>& no_buffers()
Expand All @@ -42,6 +47,41 @@ inline const std::vector<ConstBuffer>& no_buffers()
return no_buffers_;
}

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
/** \brief Returns the least-upper bound (exclusive) address of the passed buffer.
*/
inline const void* get_buffer_end(const batt::ConstBuffer& buffer) noexcept
{
return static_cast<const char*>(buffer.data()) + buffer.size();
}

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
/** \brief Returns the pointer that is offset from `ptr` by `delta` bytes.
*/
inline const void* advance_pointer(const void* ptr, isize delta)
{
return static_cast<const char*>(ptr) + delta;
}

} // namespace llfs

//#=##=##=#==#=#==#===#+==#+==========+==+=+=+=+=+=++=+++=+++++=-++++=-+++++++++++

namespace std {

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
/** \brief Resizes the given buffer storage object and returns a MutableBuffer of the same size.
*/
inline llfs::MutableBuffer resize_buffer_storage(std::unique_ptr<llfs::u8[]>& p_storage,
llfs::usize size)
{
p_storage.reset(new llfs::u8[size]);
return llfs::MutableBuffer{p_storage.get(), size};
}

} //namespace std

#endif // LLFS_BUFFER_HPP
30 changes: 30 additions & 0 deletions src/llfs/buffer.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//#=##=##=#==#=#==#===#+==#+==========+==+=+=+=+=+=++=+++=+++++=-++++=-+++++++++++
//
// Part of the LLFS Project, under Apache License v2.0.
// See https://www.apache.org/licenses/LICENSE-2.0 for license information.
// SPDX short identifier: Apache-2.0
//
//+++++++++++-+-+--+----- --- -- - - - -

#include <llfs/buffer.hpp>
//
#include <llfs/buffer.hpp>

#include <gmock/gmock.h>
#include <gtest/gtest.h>

namespace {

using namespace llfs::int_types;

TEST(BufferTest, ResizeBufferStorage)
{
std::unique_ptr<u8[]> storage;
llfs::MutableBuffer buffer = resize_buffer_storage(storage, 1977);

EXPECT_NE(buffer.data(), nullptr);
EXPECT_EQ((void*)buffer.data(), (void*)storage.get());
EXPECT_EQ(buffer.size(), 1977u);
}

} // namespace
10 changes: 10 additions & 0 deletions src/llfs/ioring_buffer_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,16 @@ IoRingBufferPool::Buffer::Buffer() noexcept : allocated_{nullptr}
/*explicit*/ IoRingBufferPool::Buffer::Buffer(batt::SharedPtr<const Allocated>&& allocated) noexcept
: allocated_{std::move(allocated)}
{
LLFS_VLOG_IF(1, this->allocated_)
<< BATT_INSPECT(this->allocated_->use_count()) << "->" << (this->allocated_->use_count() + 1);
}

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
IoRingBufferPool::Buffer::~Buffer() noexcept
{
LLFS_VLOG_IF(1, this->allocated_)
<< BATT_INSPECT(this->allocated_->use_count()) << "->" << (this->allocated_->use_count() - 1);
}

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
Expand Down
43 changes: 26 additions & 17 deletions src/llfs/ioring_buffer_pool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <llfs/api_types.hpp>
#include <llfs/constants.hpp>
#include <llfs/ioring.hpp>
#include <llfs/status.hpp>

#include <batteries/async/mutex.hpp>
#include <batteries/async/watch.hpp>
Expand Down Expand Up @@ -160,6 +161,13 @@ class IoRingBufferPool
*/
Buffer(const Buffer&) = default;

/** \brief Destroys this Buffer object, decrementing the ref count on the underlying memory by
* one.
*/
~Buffer() noexcept;

//----- --- -- - - - -

/** This class is copyable; all copies share the same underlying buffer memory. When the last
* copy is destroyed, the buffer is returned to the pool.
*/
Expand Down Expand Up @@ -229,12 +237,12 @@ class IoRingBufferPool

using BufferVec = batt::SmallVec<Buffer, 2>;

using AbstractHandler = batt::BasicAbstractHandler<HandlerBase, batt::StatusOr<BufferVec>&&>;
using AbstractHandler = batt::BasicAbstractHandler<HandlerBase, StatusOr<BufferVec>&&>;

template <typename Fn>
using HandlerImpl = batt::BasicHandlerImpl<Fn, HandlerBase, batt::StatusOr<BufferVec>&&>;
using HandlerImpl = batt::BasicHandlerImpl<Fn, HandlerBase, StatusOr<BufferVec>&&>;

using HandlerList = batt::BasicHandlerList<HandlerBase, batt::StatusOr<BufferVec>&&>;
using HandlerList = batt::BasicHandlerList<HandlerBase, StatusOr<BufferVec>&&>;

using BufferFreePoolList = boost::intrusive::slist<Deallocated, //
boost::intrusive::cache_last<true>, //
Expand All @@ -246,9 +254,10 @@ class IoRingBufferPool
*
* Automatically registers the buffers in the pool with the passed IoRing context.
*/
static batt::StatusOr<std::unique_ptr<IoRingBufferPool>> make_new(
const IoRing& io_ring, BufferCount count,
BufferSize size = BufferSize{Self::kMemoryUnitSize}) noexcept;
static StatusOr<std::unique_ptr<IoRingBufferPool>> make_new(const IoRing& io_ring,
BufferCount count,
BufferSize size = BufferSize{
Self::kMemoryUnitSize}) noexcept;

//+++++++++++-+-+--+----- --- -- - - - -

Expand Down Expand Up @@ -278,30 +287,30 @@ class IoRingBufferPool
/** \brief Asynchronously allocate a new buffer. Waits until a buffer becomes available and then
* invokes the passed handler.
*
* The signature of the handler is: `void (batt::StatusOr<llfs::IoRingBufferPool::Buffer>)`.
* The signature of the handler is: `void (StatusOr<llfs::IoRingBufferPool::Buffer>)`.
*/
template <typename Handler = void(batt::StatusOr<Buffer>&&)>
template <typename Handler = void(StatusOr<Buffer>&&)>
void async_allocate(Handler&& handler)
{
this->async_allocate(
BufferCount{1},
batt::bind_handler(
BATT_FORWARD(handler), [](Handler&& handler, batt::StatusOr<BufferVec>&& buffers) {
batt::bind_handler( //
BATT_FORWARD(handler), [](Handler&& handler, StatusOr<BufferVec>&& buffers) {
if (!buffers.ok()) {
BATT_FORWARD(handler)(batt::StatusOr<Buffer>{buffers.status()});
BATT_FORWARD(handler)(StatusOr<Buffer>{buffers.status()});
return;
}
BATT_CHECK_EQ(buffers->size(), 1u);
BATT_FORWARD(handler)(batt::StatusOr<Buffer>{std::move(buffers->front())});
BATT_FORWARD(handler)(StatusOr<Buffer>{std::move(buffers->front())});
}));
}

/** \brief Asynchronously allocate the specified number of buffers. Waits until enough buffers
* become available and then invokes the passed handler.
*
* The signature of the handler is: `void (batt::StatusOr<llfs::IoRingBufferPool::Buffer>)`.
* The signature of the handler is: `void (StatusOr<llfs::IoRingBufferPool::Buffer>)`.
*/
template <typename Fn = void(batt::StatusOr<BufferVec>&&)>
template <typename Fn = void(StatusOr<BufferVec>&&)>
void async_allocate(BufferCount count, Fn&& fn)
{
AbstractHandler* handler = HandlerImpl<Fn>::make_new(BATT_FORWARD(fn));
Expand All @@ -316,17 +325,17 @@ class IoRingBufferPool
/** \brief Blocks the current Task until a buffer becomes available, then allocates and returns
* it.
*/
auto await_allocate() -> batt::StatusOr<Buffer>;
auto await_allocate() -> StatusOr<Buffer>;

/** \brief Blocks the current Task until a buffer becomes available, then allocates and returns
* it.
*/
auto await_allocate(BufferCount count) -> batt::StatusOr<BufferVec>;
auto await_allocate(BufferCount count) -> StatusOr<BufferVec>;

/** \brief Attempts to allocate a buffer without blocking; if successful, returns the buffer; else
* returns batt::StatusCode::kResourceExhausted.
*/
auto try_allocate() -> batt::StatusOr<Buffer>;
auto try_allocate() -> StatusOr<Buffer>;

/** \brief Returns the number of buffers in the pool which are currently in use (allocated).
*/
Expand Down
61 changes: 61 additions & 0 deletions src/llfs/ioring_buffer_view.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//#=##=##=#==#=#==#===#+==#+==========+==+=+=+=+=+=++=+++=+++++=-++++=-+++++++++++
//
// Part of the LLFS Project, under Apache License v2.0.
// See https://www.apache.org/licenses/LICENSE-2.0 for license information.
// SPDX short identifier: Apache-2.0
//
//+++++++++++-+-+--+----- --- -- - - - -

#include <llfs/ioring_buffer_view.hpp>
//

namespace llfs {

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
template <typename SliceT>
auto BasicIoRingBufferView<SliceT>::split(usize byte_offset) noexcept -> Self
{
byte_offset = std::min(byte_offset, this->slice.size());

Self prefix{
this->buffer,
SliceT{this->slice.data(), byte_offset},
};

this->slice += byte_offset;

return prefix;
}

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
template <typename SliceT>
bool BasicIoRingBufferView<SliceT>::can_merge_with(const Self& other) const noexcept
{
return this->buffer == other.buffer //
&& get_buffer_end(this->slice) == other.slice.data();
}

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
template <typename SliceT>
bool BasicIoRingBufferView<SliceT>::merge_with(const Self& other) noexcept
{
if (!this->can_merge_with(other)) {
return false;
}
this->slice = SliceT{
this->slice.data(),
this->slice.size() + other.slice.size(),
};
return true;
}

//=#=#==#==#===============+=+=+=+=++=++++++++++++++-++-+--+-+----+---------------
// Explicitly specialize for MutableBuffer and ConstBuffer only.

template class BasicIoRingBufferView<ConstBuffer>;
template class BasicIoRingBufferView<MutableBuffer>;

} //namespace llfs
Loading