mirror of https://github.com/grpc/grpc.git
Integrate new resource quota, event engine (#27522)
* Integrate new resource quota, event engine * Automated change: Fix sanity tests * windows fix * Automated change: Fix sanity tests * Update memory_allocator.h * Automated change: Fix sanity tests * first round review feedback * review feedback * Automated change: Fix sanity tests * Update memory_quota.h * get re-export formatted right * Automated change: Fix sanity tests * Update memory_allocator.cc * Automated change: Fix sanity tests * MemoryOwner has-a MemoryAllocator * using fix * review feedback * Automated change: Fix sanity tests Co-authored-by: ctiller <ctiller@users.noreply.github.com>pull/27643/head
parent
3d83dd3776
commit
79ef60f079
30 changed files with 737 additions and 649 deletions
@ -0,0 +1,98 @@ |
|||||||
|
// Copyright 2021 The gRPC Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#ifndef GRPC_EVENT_ENGINE_INTERNAL_MEMORY_ALLOCATOR_IMPL_H |
||||||
|
#define GRPC_EVENT_ENGINE_INTERNAL_MEMORY_ALLOCATOR_IMPL_H |
||||||
|
|
||||||
|
#include <grpc/impl/codegen/port_platform.h> |
||||||
|
|
||||||
|
#include <algorithm> |
||||||
|
#include <memory> |
||||||
|
#include <type_traits> |
||||||
|
#include <vector> |
||||||
|
|
||||||
|
#include <grpc/slice.h> |
||||||
|
|
||||||
|
// forward-declaring an internal struct, not used publicly.
|
||||||
|
struct grpc_slice_buffer; |
||||||
|
|
||||||
|
namespace grpc_event_engine { |
||||||
|
namespace experimental { |
||||||
|
|
||||||
|
/// Reservation request - how much memory do we want to allocate?
|
||||||
|
class MemoryRequest { |
||||||
|
public: |
||||||
|
/// Request a fixed amount of memory.
|
||||||
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
|
MemoryRequest(size_t n) : min_(n), max_(n) {} |
||||||
|
/// Request a range of memory.
|
||||||
|
/// Requires: \a min <= \a max.
|
||||||
|
/// Requires: \a max <= max_size()
|
||||||
|
MemoryRequest(size_t min, size_t max) : min_(min), max_(max) {} |
||||||
|
|
||||||
|
/// Maximum allowable request size - hard coded to 1GB.
|
||||||
|
static constexpr size_t max_allowed_size() { return 1024 * 1024 * 1024; } |
||||||
|
|
||||||
|
/// Increase the size by \a amount.
|
||||||
|
/// Undefined behavior if min() + amount or max() + amount overflows.
|
||||||
|
MemoryRequest Increase(size_t amount) const { |
||||||
|
return MemoryRequest(min_ + amount, max_ + amount); |
||||||
|
} |
||||||
|
|
||||||
|
size_t min() const { return min_; } |
||||||
|
size_t max() const { return max_; } |
||||||
|
|
||||||
|
private: |
||||||
|
size_t min_; |
||||||
|
size_t max_; |
||||||
|
}; |
||||||
|
|
||||||
|
namespace internal { |
||||||
|
|
||||||
|
/// Underlying memory allocation interface.
|
||||||
|
/// This is an internal interface, not intended to be used by users.
|
||||||
|
/// Its interface is subject to change at any time.
|
||||||
|
class MemoryAllocatorImpl |
||||||
|
: public std::enable_shared_from_this<MemoryAllocatorImpl> { |
||||||
|
public: |
||||||
|
MemoryAllocatorImpl() {} |
||||||
|
virtual ~MemoryAllocatorImpl() {} |
||||||
|
|
||||||
|
MemoryAllocatorImpl(const MemoryAllocatorImpl&) = delete; |
||||||
|
MemoryAllocatorImpl& operator=(const MemoryAllocatorImpl&) = delete; |
||||||
|
|
||||||
|
/// Reserve bytes from the quota.
|
||||||
|
/// If we enter overcommit, reclamation will begin concurrently.
|
||||||
|
/// Returns the number of bytes reserved.
|
||||||
|
/// If MemoryRequest is invalid, this function will abort.
|
||||||
|
/// If MemoryRequest is valid, this function is infallible, and will always
|
||||||
|
/// succeed at reserving the some number of bytes between request.min() and
|
||||||
|
/// request.max() inclusively.
|
||||||
|
virtual size_t Reserve(MemoryRequest request) = 0; |
||||||
|
|
||||||
|
/// Release some bytes that were previously reserved.
|
||||||
|
/// If more bytes are released than were reserved, we will have undefined
|
||||||
|
/// behavior.
|
||||||
|
virtual void Release(size_t n) = 0; |
||||||
|
|
||||||
|
/// Shutdown this allocator.
|
||||||
|
/// Further usage of Reserve() is undefined behavior.
|
||||||
|
virtual void Shutdown() = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
} // namespace experimental
|
||||||
|
} // namespace grpc_event_engine
|
||||||
|
|
||||||
|
#endif // GRPC_EVENT_ENGINE_INTERNAL_MEMORY_ALLOCATOR_IMPL_H
|
@ -0,0 +1,210 @@ |
|||||||
|
// Copyright 2021 The gRPC Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#ifndef GRPC_EVENT_ENGINE_MEMORY_ALLOCATOR_H |
||||||
|
#define GRPC_EVENT_ENGINE_MEMORY_ALLOCATOR_H |
||||||
|
|
||||||
|
#include <grpc/impl/codegen/port_platform.h> |
||||||
|
|
||||||
|
#include <algorithm> |
||||||
|
#include <memory> |
||||||
|
#include <type_traits> |
||||||
|
#include <vector> |
||||||
|
|
||||||
|
#include <grpc/event_engine/internal/memory_allocator_impl.h> |
||||||
|
#include <grpc/slice.h> |
||||||
|
|
||||||
|
// forward-declaring an internal struct, not used publicly.
|
||||||
|
struct grpc_slice_buffer; |
||||||
|
|
||||||
|
namespace grpc_event_engine { |
||||||
|
namespace experimental { |
||||||
|
|
||||||
|
// TODO(nnoble): needs implementation
|
||||||
|
class SliceBuffer { |
||||||
|
public: |
||||||
|
SliceBuffer() { abort(); } |
||||||
|
explicit SliceBuffer(grpc_slice_buffer*) { abort(); } |
||||||
|
|
||||||
|
grpc_slice_buffer* RawSliceBuffer() { return slice_buffer_; } |
||||||
|
|
||||||
|
private: |
||||||
|
grpc_slice_buffer* slice_buffer_; |
||||||
|
}; |
||||||
|
|
||||||
|
class MemoryAllocator { |
||||||
|
public: |
||||||
|
/// Construct a MemoryAllocator given an internal::MemoryAllocatorImpl
|
||||||
|
/// implementation. The constructed MemoryAllocator will call
|
||||||
|
/// MemoryAllocatorImpl::Shutdown() upon destruction.
|
||||||
|
explicit MemoryAllocator( |
||||||
|
std::shared_ptr<internal::MemoryAllocatorImpl> allocator) |
||||||
|
: allocator_(std::move(allocator)) {} |
||||||
|
~MemoryAllocator() { |
||||||
|
if (allocator_ != nullptr) allocator_->Shutdown(); |
||||||
|
} |
||||||
|
|
||||||
|
MemoryAllocator(const MemoryAllocator&) = delete; |
||||||
|
MemoryAllocator& operator=(const MemoryAllocator&) = delete; |
||||||
|
|
||||||
|
MemoryAllocator(MemoryAllocator&&) = default; |
||||||
|
MemoryAllocator& operator=(MemoryAllocator&&) = default; |
||||||
|
|
||||||
|
/// Reserve bytes from the quota.
|
||||||
|
/// If we enter overcommit, reclamation will begin concurrently.
|
||||||
|
/// Returns the number of bytes reserved.
|
||||||
|
size_t Reserve(MemoryRequest request) { return allocator_->Reserve(request); } |
||||||
|
|
||||||
|
/// Release some bytes that were previously reserved.
|
||||||
|
void Release(size_t n) { return allocator_->Release(n); } |
||||||
|
|
||||||
|
/// Return a pointer to the underlying implementation.
|
||||||
|
/// Note that the interface of said implementatoin is unstable and likely to
|
||||||
|
/// change at any time.
|
||||||
|
internal::MemoryAllocatorImpl* get_internal_impl_ptr() { |
||||||
|
return allocator_.get(); |
||||||
|
} |
||||||
|
|
||||||
|
//
|
||||||
|
// The remainder of this type are helper functions implemented in terms of
|
||||||
|
// Reserve/Release.
|
||||||
|
//
|
||||||
|
|
||||||
|
/// An automatic releasing reservation of memory.
|
||||||
|
class Reservation { |
||||||
|
public: |
||||||
|
Reservation() = default; |
||||||
|
Reservation(const Reservation&) = delete; |
||||||
|
Reservation& operator=(const Reservation&) = delete; |
||||||
|
Reservation(Reservation&&) = default; |
||||||
|
Reservation& operator=(Reservation&&) = default; |
||||||
|
~Reservation() { |
||||||
|
if (allocator_ != nullptr) allocator_->Release(size_); |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
friend class MemoryAllocator; |
||||||
|
Reservation(std::shared_ptr<internal::MemoryAllocatorImpl> allocator, |
||||||
|
size_t size) |
||||||
|
: allocator_(std::move(allocator)), size_(size) {} |
||||||
|
|
||||||
|
std::shared_ptr<internal::MemoryAllocatorImpl> allocator_; |
||||||
|
size_t size_ = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
/// Reserve bytes from the quota and automatically release them when
|
||||||
|
/// Reservation is destroyed.
|
||||||
|
Reservation MakeReservation(MemoryRequest request) { |
||||||
|
return Reservation(allocator_, Reserve(request)); |
||||||
|
} |
||||||
|
|
||||||
|
/// Allocate a new object of type T, with constructor arguments.
|
||||||
|
/// The returned type is wrapped, and upon destruction the reserved memory
|
||||||
|
/// will be released to the allocator automatically. As such, T must have a
|
||||||
|
/// virtual destructor so we can insert the necessary hook.
|
||||||
|
template <typename T, typename... Args> |
||||||
|
typename std::enable_if<std::has_virtual_destructor<T>::value, T*>::type New( |
||||||
|
Args&&... args) { |
||||||
|
// Wrap T such that when it's destroyed, we can release memory back to the
|
||||||
|
// allocator.
|
||||||
|
class Wrapper final : public T { |
||||||
|
public: |
||||||
|
explicit Wrapper(std::shared_ptr<internal::MemoryAllocatorImpl> allocator, |
||||||
|
Args&&... args) |
||||||
|
: T(std::forward<Args>(args)...), allocator_(std::move(allocator)) {} |
||||||
|
~Wrapper() override { allocator_->Release(sizeof(*this)); } |
||||||
|
|
||||||
|
private: |
||||||
|
const std::shared_ptr<internal::MemoryAllocatorImpl> allocator_; |
||||||
|
}; |
||||||
|
Reserve(sizeof(Wrapper)); |
||||||
|
return new Wrapper(allocator_, std::forward<Args>(args)...); |
||||||
|
} |
||||||
|
|
||||||
|
/// Construct a unique_ptr immediately.
|
||||||
|
template <typename T, typename... Args> |
||||||
|
std::unique_ptr<T> MakeUnique(Args&&... args) { |
||||||
|
return std::unique_ptr<T>(New<T>(std::forward<Args>(args)...)); |
||||||
|
} |
||||||
|
|
||||||
|
/// Allocate a slice, using MemoryRequest to size the number of returned
|
||||||
|
/// bytes. For a variable length request, check the returned slice length to
|
||||||
|
/// verify how much memory was allocated. Takes care of reserving memory for
|
||||||
|
/// any relevant control structures also.
|
||||||
|
grpc_slice MakeSlice(MemoryRequest request); |
||||||
|
|
||||||
|
/// A C++ allocator for containers of T.
|
||||||
|
template <typename T> |
||||||
|
class Container { |
||||||
|
public: |
||||||
|
using value_type = T; |
||||||
|
|
||||||
|
/// Construct the allocator: \a underlying_allocator is borrowed, and must
|
||||||
|
/// outlive this object.
|
||||||
|
explicit Container(MemoryAllocator* underlying_allocator) |
||||||
|
: underlying_allocator_(underlying_allocator) {} |
||||||
|
template <typename U> |
||||||
|
explicit Container(const Container<U>& other) |
||||||
|
: underlying_allocator_(other.underlying_allocator()) {} |
||||||
|
|
||||||
|
MemoryAllocator* underlying_allocator() const { |
||||||
|
return underlying_allocator_; |
||||||
|
} |
||||||
|
|
||||||
|
T* allocate(size_t n) { |
||||||
|
underlying_allocator_->Reserve(n * sizeof(T)); |
||||||
|
return static_cast<T*>(::operator new(n * sizeof(T))); |
||||||
|
} |
||||||
|
void deallocate(T* p, size_t n) { |
||||||
|
::operator delete(p); |
||||||
|
underlying_allocator_->Release(n * sizeof(T)); |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
MemoryAllocator* underlying_allocator_; |
||||||
|
}; |
||||||
|
|
||||||
|
protected: |
||||||
|
const std::shared_ptr<internal::MemoryAllocatorImpl>& allocator() { |
||||||
|
return allocator_; |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
std::shared_ptr<internal::MemoryAllocatorImpl> allocator_; |
||||||
|
}; |
||||||
|
|
||||||
|
// Wrapper type around std::vector to make initialization against a
|
||||||
|
// MemoryAllocator based container allocator easy.
|
||||||
|
template <typename T> |
||||||
|
class Vector : public std::vector<T, MemoryAllocator::Container<T>> { |
||||||
|
public: |
||||||
|
explicit Vector(MemoryAllocator* allocator) |
||||||
|
: std::vector<T, MemoryAllocator::Container<T>>( |
||||||
|
MemoryAllocator::Container<T>(allocator)) {} |
||||||
|
}; |
||||||
|
|
||||||
|
class MemoryAllocatorFactory { |
||||||
|
public: |
||||||
|
virtual ~MemoryAllocatorFactory() = default; |
||||||
|
/// On Endpoint creation, call \a CreateMemoryAllocator to create a new
|
||||||
|
/// allocator for the endpoint.
|
||||||
|
/// Typically we'll want to:
|
||||||
|
/// auto allocator = factory->CreateMemoryAllocator();
|
||||||
|
/// auto* endpoint = allocator->New<MyEndpoint>(std::move(allocator), ...);
|
||||||
|
virtual MemoryAllocator CreateMemoryAllocator() = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace experimental
|
||||||
|
} // namespace grpc_event_engine
|
||||||
|
|
||||||
|
#endif // GRPC_EVENT_ENGINE_MEMORY_ALLOCATOR_H
|
@ -1,71 +0,0 @@ |
|||||||
// Copyright 2021 The gRPC Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
#ifndef GRPC_EVENT_ENGINE_SLICE_ALLOCATOR_H |
|
||||||
#define GRPC_EVENT_ENGINE_SLICE_ALLOCATOR_H |
|
||||||
|
|
||||||
#include <grpc/support/port_platform.h> |
|
||||||
|
|
||||||
#include <functional> |
|
||||||
|
|
||||||
#include "absl/status/status.h" |
|
||||||
|
|
||||||
// forward-declaring an internal struct, not used publicly.
|
|
||||||
struct grpc_resource_quota; |
|
||||||
struct grpc_resource_user; |
|
||||||
struct grpc_slice_buffer; |
|
||||||
|
|
||||||
namespace grpc_event_engine { |
|
||||||
namespace experimental { |
|
||||||
|
|
||||||
// TODO(nnoble): needs implementation
|
|
||||||
class SliceBuffer { |
|
||||||
public: |
|
||||||
SliceBuffer() { abort(); } |
|
||||||
explicit SliceBuffer(grpc_slice_buffer*) { abort(); } |
|
||||||
|
|
||||||
grpc_slice_buffer* RawSliceBuffer() { return slice_buffer_; } |
|
||||||
|
|
||||||
private: |
|
||||||
grpc_slice_buffer* slice_buffer_; |
|
||||||
}; |
|
||||||
|
|
||||||
class SliceAllocator { |
|
||||||
public: |
|
||||||
using AllocateCallback = std::function<void(absl::Status)>; |
|
||||||
virtual ~SliceAllocator() = default; |
|
||||||
/// Requests \a size bytes from gRPC, and populates \a dest with the allocated
|
|
||||||
/// slices. Ownership of the \a SliceBuffer is not transferred.
|
|
||||||
///
|
|
||||||
/// gRPC provides a ResourceQuota system to cap the amount of memory used by
|
|
||||||
/// the library. When a memory limit has been reached, slice allocation is
|
|
||||||
/// interrupted to attempt to reclaim memory from participating gRPC
|
|
||||||
/// internals. When there is sufficient memory available, slice allocation
|
|
||||||
/// proceeds as normal.
|
|
||||||
virtual absl::Status Allocate(size_t size, SliceBuffer* dest, |
|
||||||
SliceAllocator::AllocateCallback cb) = 0; |
|
||||||
}; |
|
||||||
|
|
||||||
class SliceAllocatorFactory { |
|
||||||
public: |
|
||||||
virtual ~SliceAllocatorFactory() = default; |
|
||||||
/// On Endpoint creation, call \a CreateSliceAllocator with the name of the
|
|
||||||
/// endpoint peer (a URI string, most likely).
|
|
||||||
virtual std::unique_ptr<SliceAllocator> CreateSliceAllocator( |
|
||||||
absl::string_view peer_name) = 0; |
|
||||||
}; |
|
||||||
|
|
||||||
} // namespace experimental
|
|
||||||
} // namespace grpc_event_engine
|
|
||||||
|
|
||||||
#endif // GRPC_EVENT_ENGINE_SLICE_ALLOCATOR_H
|
|
@ -1,67 +0,0 @@ |
|||||||
// Copyright 2021 The gRPC Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
#include <grpc/support/port_platform.h> |
|
||||||
|
|
||||||
#include "src/core/ext/transport/chttp2/transport/chttp2_slice_allocator.h" |
|
||||||
|
|
||||||
#include <functional> |
|
||||||
|
|
||||||
#include "absl/memory/memory.h" |
|
||||||
#include "absl/status/status.h" |
|
||||||
|
|
||||||
#include <grpc/event_engine/slice_allocator.h> |
|
||||||
|
|
||||||
#include "src/core/lib/iomgr/resource_quota.h" |
|
||||||
|
|
||||||
namespace grpc_event_engine { |
|
||||||
namespace experimental { |
|
||||||
|
|
||||||
Chttp2SliceAllocator::Chttp2SliceAllocator(grpc_resource_user* user) |
|
||||||
: resource_user_(user) {} |
|
||||||
|
|
||||||
Chttp2SliceAllocator::~Chttp2SliceAllocator() { |
|
||||||
if (resource_user_ != nullptr) { |
|
||||||
grpc_resource_user_unref(resource_user_); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
absl::Status Chttp2SliceAllocator::Allocate( |
|
||||||
size_t size, SliceBuffer* dest, SliceAllocator::AllocateCallback cb) { |
|
||||||
// TODO(hork): merge the implementation from the uv-ee branch.
|
|
||||||
(void)size; |
|
||||||
(void)dest; |
|
||||||
(void)cb; |
|
||||||
return absl::OkStatus(); |
|
||||||
} |
|
||||||
|
|
||||||
Chttp2SliceAllocatorFactory::Chttp2SliceAllocatorFactory( |
|
||||||
grpc_resource_quota* quota) |
|
||||||
: resource_quota_(quota) { |
|
||||||
grpc_resource_quota_ref_internal(resource_quota_); |
|
||||||
} |
|
||||||
|
|
||||||
Chttp2SliceAllocatorFactory::~Chttp2SliceAllocatorFactory() { |
|
||||||
if (resource_quota_ != nullptr) { |
|
||||||
grpc_resource_quota_unref_internal(resource_quota_); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
std::unique_ptr<SliceAllocator> |
|
||||||
Chttp2SliceAllocatorFactory::CreateSliceAllocator(absl::string_view peer_name) { |
|
||||||
return absl::make_unique<Chttp2SliceAllocator>( |
|
||||||
grpc_resource_user_create(resource_quota_, peer_name)); |
|
||||||
} |
|
||||||
|
|
||||||
} // namespace experimental
|
|
||||||
} // namespace grpc_event_engine
|
|
@ -1,74 +0,0 @@ |
|||||||
// Copyright 2021 The gRPC Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CHTTP2_SLICE_ALLOCATOR_H |
|
||||||
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CHTTP2_SLICE_ALLOCATOR_H |
|
||||||
|
|
||||||
#include <grpc/support/port_platform.h> |
|
||||||
|
|
||||||
#include <functional> |
|
||||||
|
|
||||||
#include "absl/status/status.h" |
|
||||||
|
|
||||||
#include <grpc/event_engine/slice_allocator.h> |
|
||||||
|
|
||||||
#include "src/core/lib/iomgr/resource_quota.h" |
|
||||||
|
|
||||||
namespace grpc_event_engine { |
|
||||||
namespace experimental { |
|
||||||
|
|
||||||
class Chttp2SliceAllocator |
|
||||||
: public grpc_event_engine::experimental::SliceAllocator { |
|
||||||
public: |
|
||||||
/// gRPC-internal constructor. Takes ownership of a resource_user ref from the
|
|
||||||
/// caller.
|
|
||||||
explicit Chttp2SliceAllocator(grpc_resource_user* user); |
|
||||||
// Not copyable
|
|
||||||
Chttp2SliceAllocator(Chttp2SliceAllocator& other) = delete; |
|
||||||
Chttp2SliceAllocator& operator=(const Chttp2SliceAllocator& other) = delete; |
|
||||||
// Not Moveable
|
|
||||||
Chttp2SliceAllocator(Chttp2SliceAllocator&& other) = delete; |
|
||||||
Chttp2SliceAllocator& operator=(Chttp2SliceAllocator&& other) = delete; |
|
||||||
~Chttp2SliceAllocator() override; |
|
||||||
absl::Status Allocate(size_t size, SliceBuffer* dest, |
|
||||||
SliceAllocator::AllocateCallback cb) override; |
|
||||||
|
|
||||||
private: |
|
||||||
grpc_resource_user* resource_user_; |
|
||||||
}; |
|
||||||
|
|
||||||
class Chttp2SliceAllocatorFactory |
|
||||||
: public grpc_event_engine::experimental::SliceAllocatorFactory { |
|
||||||
public: |
|
||||||
// gRPC-internal constructor
|
|
||||||
explicit Chttp2SliceAllocatorFactory(grpc_resource_quota* quota); |
|
||||||
// Not copyable
|
|
||||||
Chttp2SliceAllocatorFactory(Chttp2SliceAllocatorFactory& other) = delete; |
|
||||||
Chttp2SliceAllocatorFactory& operator=( |
|
||||||
const Chttp2SliceAllocatorFactory& other) = delete; |
|
||||||
// Not Moveable
|
|
||||||
Chttp2SliceAllocatorFactory(Chttp2SliceAllocatorFactory&& other) = delete; |
|
||||||
Chttp2SliceAllocatorFactory& operator=(Chttp2SliceAllocatorFactory&& other) = |
|
||||||
delete; |
|
||||||
~Chttp2SliceAllocatorFactory() override; |
|
||||||
std::unique_ptr<SliceAllocator> CreateSliceAllocator( |
|
||||||
absl::string_view peer_name) override; |
|
||||||
|
|
||||||
private: |
|
||||||
grpc_resource_quota* resource_quota_; |
|
||||||
}; |
|
||||||
|
|
||||||
} // namespace experimental
|
|
||||||
} // namespace grpc_event_engine
|
|
||||||
|
|
||||||
#endif // GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CHTTP2_SLICE_ALLOCATOR_H
|
|
@ -0,0 +1,70 @@ |
|||||||
|
// Copyright 2021 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include <grpc/event_engine/memory_allocator.h> |
||||||
|
|
||||||
|
#include "src/core/lib/gprpp/ref_counted.h" |
||||||
|
#include "src/core/lib/slice/slice_refcount.h" |
||||||
|
|
||||||
|
namespace grpc_event_engine { |
||||||
|
namespace experimental { |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
// Reference count for a slice allocated by MemoryAllocator::MakeSlice.
|
||||||
|
// Takes care of releasing memory back when the slice is destroyed.
|
||||||
|
class SliceRefCount { |
||||||
|
public: |
||||||
|
static void Destroy(void* p) { |
||||||
|
auto* rc = static_cast<SliceRefCount*>(p); |
||||||
|
rc->~SliceRefCount(); |
||||||
|
gpr_free(rc); |
||||||
|
} |
||||||
|
SliceRefCount(std::shared_ptr<internal::MemoryAllocatorImpl> allocator, |
||||||
|
size_t size) |
||||||
|
: base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this, |
||||||
|
&base_), |
||||||
|
allocator_(std::move(allocator)), |
||||||
|
size_(size) { |
||||||
|
// Nothing to do here.
|
||||||
|
} |
||||||
|
~SliceRefCount() { allocator_->Release(size_); } |
||||||
|
|
||||||
|
grpc_slice_refcount* base_refcount() { return &base_; } |
||||||
|
|
||||||
|
private: |
||||||
|
grpc_slice_refcount base_; |
||||||
|
grpc_core::RefCount refs_; |
||||||
|
std::shared_ptr<internal::MemoryAllocatorImpl> allocator_; |
||||||
|
size_t size_; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
grpc_slice MemoryAllocator::MakeSlice(MemoryRequest request) { |
||||||
|
auto size = Reserve(request.Increase(sizeof(SliceRefCount))); |
||||||
|
void* p = gpr_malloc(size); |
||||||
|
new (p) SliceRefCount(allocator_, size); |
||||||
|
grpc_slice slice; |
||||||
|
slice.refcount = static_cast<SliceRefCount*>(p)->base_refcount(); |
||||||
|
slice.data.refcounted.bytes = |
||||||
|
static_cast<uint8_t*>(p) + sizeof(SliceRefCount); |
||||||
|
slice.data.refcounted.length = size - sizeof(SliceRefCount); |
||||||
|
return slice; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace experimental
|
||||||
|
} // namespace grpc_event_engine
|
Loading…
Reference in new issue