[slice] Introduce grpc_core::SliceBuffer (#29635)

* A starter SliceBuffer implementation

* Add comments and fix sanity checks

* Minor fixes

* more minor fixes

* Addressing review comments and adding a slice_buffer_test

* fix sanity checks

* regenerate projects

* fixing undefined function error

* reverting changes from memory_allocator.cc and adding them to src/core/lib/slice/slice_buffer.cc to allow memory allocator lib to build correctly

* fix sanity checks

* adding an open source slice definition

* regnerate projects

* fix asan error

* Automated change: Fix sanity tests

* addressing review comments

* fix sanity checks

* regenerate projects

* update

* fix sanity checks

* Converting slice buffer to retarin ownership of the underlying ctype

* [slice_buffer] Introduce grpc_core::SliceBuffer

* add test

* Automated change: Fix sanity tests

* missing files

* Automated change: Fix sanity tests

* Automated change: Fix sanity tests

* sanity

Co-authored-by: Vignesh Babu <vigneshbabu@google.com>
Co-authored-by: Vignesh2208 <Vignesh2208@users.noreply.github.com>
Co-authored-by: ctiller <ctiller@users.noreply.github.com>
pull/29655/head
Craig Tiller 3 years ago committed by GitHub
parent 48749f739e
commit 7798e3b741
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 20
      BUILD
  2. 94
      CMakeLists.txt
  3. 2
      Makefile
  4. 32
      build_autogenerated.yaml
  5. 1
      config.m4
  6. 1
      config.w32
  7. 2
      gRPC-C++.podspec
  8. 3
      gRPC-Core.podspec
  9. 2
      grpc.gemspec
  10. 2
      grpc.gyp
  11. 2
      package.xml
  12. 47
      src/core/lib/slice/slice_buffer.cc
  13. 106
      src/core/lib/slice/slice_buffer.h
  14. 35
      src/core/lib/slice/slice_buffer_api.cc
  15. 1
      src/python/grpcio/grpc_core_dependencies.py
  16. 12
      test/core/slice/BUILD
  17. 193
      test/core/slice/c_slice_buffer_test.cc
  18. 246
      test/core/slice/slice_buffer_test.cc
  19. 2
      tools/doxygen/Doxyfile.c++.internal
  20. 2
      tools/doxygen/Doxyfile.core.internal
  21. 72
      tools/run_tests/generated/tests.json
  22. 4
      tools/run_tests/sanity/core_banned_functions.py

20
BUILD

@ -1648,6 +1648,7 @@ grpc_cc_library(
"src/core/lib/slice/slice_string_helpers.cc",
],
hdrs = [
"include/grpc/slice.h",
"src/core/lib/slice/slice.h",
"src/core/lib/slice/slice_internal.h",
"src/core/lib/slice/slice_string_helpers.h",
@ -1659,6 +1660,22 @@ grpc_cc_library(
],
)
grpc_cc_library(
name = "slice_buffer",
srcs = [
"src/core/lib/slice/slice_buffer.cc",
],
hdrs = [
"include/grpc/slice_buffer.h",
"src/core/lib/slice/slice_buffer.h",
],
deps = [
"gpr_base",
"slice",
"slice_refcount",
],
)
grpc_cc_library(
name = "error",
srcs = [
@ -2012,7 +2029,7 @@ grpc_cc_library(
"src/core/lib/slice/b64.cc",
"src/core/lib/slice/percent_encoding.cc",
"src/core/lib/slice/slice_api.cc",
"src/core/lib/slice/slice_buffer.cc",
"src/core/lib/slice/slice_buffer_api.cc",
"src/core/lib/slice/slice_split.cc",
"src/core/lib/surface/api_trace.cc",
"src/core/lib/surface/builtins.cc",
@ -2246,6 +2263,7 @@ grpc_cc_library(
"resource_quota",
"resource_quota_trace",
"slice",
"slice_buffer",
"slice_refcount",
"sockaddr_utils",
"table",

94
CMakeLists.txt generated

@ -771,6 +771,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_c bin_decoder_test)
add_dependencies(buildtests_c bin_encoder_test)
add_dependencies(buildtests_c buffer_list_test)
add_dependencies(buildtests_c c_slice_buffer_test)
add_dependencies(buildtests_c channel_stack_test)
add_dependencies(buildtests_c check_gcp_environment_linux_test)
add_dependencies(buildtests_c check_gcp_environment_windows_test)
@ -889,7 +890,6 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_c tcp_server_posix_test)
endif()
add_dependencies(buildtests_c test_core_gpr_time_test)
add_dependencies(buildtests_c test_core_slice_slice_buffer_test)
add_dependencies(buildtests_c thd_test)
add_dependencies(buildtests_c threadpool_test)
add_dependencies(buildtests_c time_averaged_stats_test)
@ -1140,6 +1140,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx test_core_event_engine_slice_buffer_test)
add_dependencies(buildtests_cxx test_core_gprpp_time_test)
add_dependencies(buildtests_cxx test_core_security_credentials_test)
add_dependencies(buildtests_cxx test_core_slice_slice_buffer_test)
add_dependencies(buildtests_cxx test_core_slice_slice_test)
add_dependencies(buildtests_cxx test_cpp_client_credentials_test)
add_dependencies(buildtests_cxx test_cpp_server_credentials_test)
@ -2203,6 +2204,7 @@ add_library(grpc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_api.cc
src/core/lib/slice/slice_buffer.cc
src/core/lib/slice/slice_buffer_api.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_split.cc
src/core/lib/slice/slice_string_helpers.cc
@ -2776,6 +2778,7 @@ add_library(grpc_unsecure
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_api.cc
src/core/lib/slice/slice_buffer.cc
src/core/lib/slice/slice_buffer_api.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_split.cc
src/core/lib/slice/slice_string_helpers.cc
@ -4799,6 +4802,33 @@ target_link_libraries(buffer_list_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(c_slice_buffer_test
test/core/slice/c_slice_buffer_test.cc
)
target_include_directories(c_slice_buffer_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
)
target_link_libraries(c_slice_buffer_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
)
endif()
if(gRPC_BUILD_TESTS)
@ -7000,33 +7030,6 @@ target_link_libraries(test_core_gpr_time_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(test_core_slice_slice_buffer_test
test/core/slice/slice_buffer_test.cc
)
target_include_directories(test_core_slice_slice_buffer_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
)
target_link_libraries(test_core_slice_slice_buffer_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
)
endif()
if(gRPC_BUILD_TESTS)
@ -15941,6 +15944,41 @@ target_link_libraries(test_core_security_credentials_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(test_core_slice_slice_buffer_test
test/core/slice/slice_buffer_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(test_core_slice_slice_buffer_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(test_core_slice_slice_buffer_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
)
endif()
if(gRPC_BUILD_TESTS)

2
Makefile generated

@ -1621,6 +1621,7 @@ LIBGRPC_SRC = \
src/core/lib/slice/slice.cc \
src/core/lib/slice/slice_api.cc \
src/core/lib/slice/slice_buffer.cc \
src/core/lib/slice/slice_buffer_api.cc \
src/core/lib/slice/slice_refcount.cc \
src/core/lib/slice/slice_split.cc \
src/core/lib/slice/slice_string_helpers.cc \
@ -2037,6 +2038,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/slice/slice.cc \
src/core/lib/slice/slice_api.cc \
src/core/lib/slice/slice_buffer.cc \
src/core/lib/slice/slice_buffer_api.cc \
src/core/lib/slice/slice_refcount.cc \
src/core/lib/slice/slice_split.cc \
src/core/lib/slice/slice_string_helpers.cc \

@ -915,6 +915,7 @@ libs:
- src/core/lib/slice/b64.h
- src/core/lib/slice/percent_encoding.h
- src/core/lib/slice/slice.h
- src/core/lib/slice/slice_buffer.h
- src/core/lib/slice/slice_internal.h
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_refcount_base.h
@ -1580,6 +1581,7 @@ libs:
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_api.cc
- src/core/lib/slice/slice_buffer.cc
- src/core/lib/slice/slice_buffer_api.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_split.cc
- src/core/lib/slice/slice_string_helpers.cc
@ -2071,6 +2073,7 @@ libs:
- src/core/lib/slice/b64.h
- src/core/lib/slice/percent_encoding.h
- src/core/lib/slice/slice.h
- src/core/lib/slice/slice_buffer.h
- src/core/lib/slice/slice_internal.h
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_refcount_base.h
@ -2382,6 +2385,7 @@ libs:
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_api.cc
- src/core/lib/slice/slice_buffer.cc
- src/core/lib/slice/slice_buffer_api.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_split.cc
- src/core/lib/slice/slice_string_helpers.cc
@ -3357,6 +3361,15 @@ targets:
- test/core/iomgr/buffer_list_test.cc
deps:
- grpc_test_util
- name: c_slice_buffer_test
build: test
language: c
headers: []
src:
- test/core/slice/c_slice_buffer_test.cc
deps:
- grpc_test_util
uses_polling: false
- name: channel_stack_test
build: test
language: c
@ -4216,15 +4229,6 @@ targets:
deps:
- grpc_test_util
uses_polling: false
- name: test_core_slice_slice_buffer_test
build: test
language: c
headers: []
src:
- test/core/slice/slice_buffer_test.cc
deps:
- grpc_test_util
uses_polling: false
- name: thd_test
build: test
language: c
@ -7744,6 +7748,16 @@ targets:
- test/core/security/credentials_test.cc
deps:
- grpc_test_util
- name: test_core_slice_slice_buffer_test
gtest: true
build: test
language: c++
headers: []
src:
- test/core/slice/slice_buffer_test.cc
deps:
- grpc_test_util
uses_polling: false
- name: test_core_slice_slice_test
gtest: true
build: test

1
config.m4 generated

@ -687,6 +687,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/slice/slice.cc \
src/core/lib/slice/slice_api.cc \
src/core/lib/slice/slice_buffer.cc \
src/core/lib/slice/slice_buffer_api.cc \
src/core/lib/slice/slice_refcount.cc \
src/core/lib/slice/slice_split.cc \
src/core/lib/slice/slice_string_helpers.cc \

1
config.w32 generated

@ -653,6 +653,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\slice\\slice.cc " +
"src\\core\\lib\\slice\\slice_api.cc " +
"src\\core\\lib\\slice\\slice_buffer.cc " +
"src\\core\\lib\\slice\\slice_buffer_api.cc " +
"src\\core\\lib\\slice\\slice_refcount.cc " +
"src\\core\\lib\\slice\\slice_split.cc " +
"src\\core\\lib\\slice\\slice_string_helpers.cc " +

2
gRPC-C++.podspec generated

@ -882,6 +882,7 @@ Pod::Spec.new do |s|
'src/core/lib/slice/b64.h',
'src/core/lib/slice/percent_encoding.h',
'src/core/lib/slice/slice.h',
'src/core/lib/slice/slice_buffer.h',
'src/core/lib/slice/slice_internal.h',
'src/core/lib/slice/slice_refcount.h',
'src/core/lib/slice/slice_refcount_base.h',
@ -1697,6 +1698,7 @@ Pod::Spec.new do |s|
'src/core/lib/slice/b64.h',
'src/core/lib/slice/percent_encoding.h',
'src/core/lib/slice/slice.h',
'src/core/lib/slice/slice_buffer.h',
'src/core/lib/slice/slice_internal.h',
'src/core/lib/slice/slice_refcount.h',
'src/core/lib/slice/slice_refcount_base.h',

3
gRPC-Core.podspec generated

@ -1470,6 +1470,8 @@ Pod::Spec.new do |s|
'src/core/lib/slice/slice.h',
'src/core/lib/slice/slice_api.cc',
'src/core/lib/slice/slice_buffer.cc',
'src/core/lib/slice/slice_buffer.h',
'src/core/lib/slice/slice_buffer_api.cc',
'src/core/lib/slice/slice_internal.h',
'src/core/lib/slice/slice_refcount.cc',
'src/core/lib/slice/slice_refcount.h',
@ -2305,6 +2307,7 @@ Pod::Spec.new do |s|
'src/core/lib/slice/b64.h',
'src/core/lib/slice/percent_encoding.h',
'src/core/lib/slice/slice.h',
'src/core/lib/slice/slice_buffer.h',
'src/core/lib/slice/slice_internal.h',
'src/core/lib/slice/slice_refcount.h',
'src/core/lib/slice/slice_refcount_base.h',

2
grpc.gemspec generated

@ -1385,6 +1385,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/slice/slice.h )
s.files += %w( src/core/lib/slice/slice_api.cc )
s.files += %w( src/core/lib/slice/slice_buffer.cc )
s.files += %w( src/core/lib/slice/slice_buffer.h )
s.files += %w( src/core/lib/slice/slice_buffer_api.cc )
s.files += %w( src/core/lib/slice/slice_internal.h )
s.files += %w( src/core/lib/slice/slice_refcount.cc )
s.files += %w( src/core/lib/slice/slice_refcount.h )

2
grpc.gyp generated

@ -976,6 +976,7 @@
'src/core/lib/slice/slice.cc',
'src/core/lib/slice/slice_api.cc',
'src/core/lib/slice/slice_buffer.cc',
'src/core/lib/slice/slice_buffer_api.cc',
'src/core/lib/slice/slice_refcount.cc',
'src/core/lib/slice/slice_split.cc',
'src/core/lib/slice/slice_string_helpers.cc',
@ -1399,6 +1400,7 @@
'src/core/lib/slice/slice.cc',
'src/core/lib/slice/slice_api.cc',
'src/core/lib/slice/slice_buffer.cc',
'src/core/lib/slice/slice_buffer_api.cc',
'src/core/lib/slice/slice_refcount.cc',
'src/core/lib/slice/slice_split.cc',
'src/core/lib/slice/slice_string_helpers.cc',

2
package.xml generated

@ -1367,6 +1367,8 @@
<file baseinstalldir="/" name="src/core/lib/slice/slice.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_api.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_buffer.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_buffer.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_buffer_api.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_internal.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_refcount.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_refcount.h" role="src" />

@ -18,9 +18,11 @@
#include <grpc/support/port_platform.h>
#include <stdint.h>
#include "src/core/lib/slice/slice_buffer.h"
#include <string.h>
#include <cstdint>
#include <utility>
#include <grpc/slice.h>
@ -28,10 +30,33 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_refcount.h"
namespace grpc_core {
void SliceBuffer::Append(Slice slice) {
grpc_slice_buffer_add(&slice_buffer_, slice.TakeCSlice());
}
size_t SliceBuffer::AppendIndexed(Slice slice) {
return grpc_slice_buffer_add_indexed(&slice_buffer_, slice.TakeCSlice());
}
Slice SliceBuffer::TakeFirst() {
return Slice(grpc_slice_buffer_take_first(&slice_buffer_));
}
void SliceBuffer::Prepend(Slice slice) {
grpc_slice_buffer_undo_take_first(&slice_buffer_, slice.TakeCSlice());
}
Slice SliceBuffer::RefSlice(size_t index) {
return Slice(grpc_slice_ref_internal(slice_buffer_.slices[index]));
}
} // namespace grpc_core
/* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */
#define GROW(x) (3 * (x) / 2)
@ -95,15 +120,6 @@ void grpc_slice_buffer_destroy_internal(grpc_slice_buffer* sb) {
}
}
void grpc_slice_buffer_destroy(grpc_slice_buffer* sb) {
if (grpc_core::ExecCtx::Get() == nullptr) {
grpc_core::ExecCtx exec_ctx;
grpc_slice_buffer_destroy_internal(sb);
} else {
grpc_slice_buffer_destroy_internal(sb);
}
}
uint8_t* grpc_slice_buffer_tiny_add(grpc_slice_buffer* sb, size_t n) {
grpc_slice* back;
uint8_t* out;
@ -219,15 +235,6 @@ void grpc_slice_buffer_reset_and_unref_internal(grpc_slice_buffer* sb) {
sb->slices = sb->base_slices;
}
void grpc_slice_buffer_reset_and_unref(grpc_slice_buffer* sb) {
if (grpc_core::ExecCtx::Get() == nullptr) {
grpc_core::ExecCtx exec_ctx;
grpc_slice_buffer_reset_and_unref_internal(sb);
} else {
grpc_slice_buffer_reset_and_unref_internal(sb);
}
}
void grpc_slice_buffer_swap(grpc_slice_buffer* a, grpc_slice_buffer* b) {
size_t a_offset = static_cast<size_t>(a->slices - a->base_slices);
size_t b_offset = static_cast<size_t>(b->slices - b->base_slices);

@ -0,0 +1,106 @@
// Copyright 2022 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_LIB_SLICE_SLICE_BUFFER_Habc_SLICE_BUFFER_H
#define GRPC_CORE_LIB_SLICE_SLICE_BUFFER_Habc_SLICE_BUFFER_H
#include <grpc/support/port_platform.h>
#include <string.h>
#include <grpc/slice.h>
#include <grpc/slice_buffer.h>
#include "src/core/lib/slice/slice.h"
namespace grpc_core {
/// A slice buffer holds the memory for a collection of slices.
/// The SliceBuffer object itself is meant to only hide the C-style API,
/// and won't hold the data itself. In terms of lifespan, the
/// grpc_slice_buffer ought to be kept somewhere inside the caller's objects,
/// like a transport or an endpoint.
///
/// This lifespan rule is likely to change in the future, as we may
/// collapse the grpc_slice_buffer structure straight into this class.
///
/// The SliceBuffer API is basically a replica of the grpc_slice_buffer's,
/// and its documentation will move here once we remove the C structure,
/// which should happen before the Event Engine's API is no longer
/// an experimental API.
class SliceBuffer {
public:
explicit SliceBuffer() { grpc_slice_buffer_init(&slice_buffer_); }
SliceBuffer(const SliceBuffer& other) = delete;
SliceBuffer(SliceBuffer&& other) noexcept {
grpc_slice_buffer_init(&slice_buffer_);
grpc_slice_buffer_move_into(&slice_buffer_, &other.slice_buffer_);
}
/// Upon destruction, the underlying raw slice buffer is cleaned out and all
/// slices are unreffed.
~SliceBuffer() { grpc_slice_buffer_destroy(&slice_buffer_); }
SliceBuffer& operator=(SliceBuffer&& other) noexcept {
grpc_slice_buffer_move_into(&slice_buffer_, &other.slice_buffer_);
return *this;
}
/// Appends a new slice into the SliceBuffer and makes an attempt to merge
/// this slice with the last slice in the SliceBuffer.
void Append(Slice slice);
/// Adds a new slice into the SliceBuffer at the next available index.
/// Returns the index at which the new slice is added.
size_t AppendIndexed(Slice slice);
/// Returns the number of slices held by the SliceBuffer.
size_t Count() { return slice_buffer_.count; }
/// Removes/deletes the last n bytes in the SliceBuffer.
void RemoveLastNBytes(size_t n) {
grpc_slice_buffer_trim_end(&slice_buffer_, n, nullptr);
}
/// Move the first n bytes of the SliceBuffer into a memory pointed to by dst.
void MoveFirstNBytesIntoBuffer(size_t n, void* dst) {
grpc_slice_buffer_move_first_into_buffer(&slice_buffer_, n, dst);
}
/// Removes and unrefs all slices in the SliceBuffer.
void Clear() { grpc_slice_buffer_reset_and_unref(&slice_buffer_); }
/// Removes the first slice in the SliceBuffer and returns it.
Slice TakeFirst();
/// Prepends the slice to the the front of the SliceBuffer.
void Prepend(Slice slice);
/// Increased the ref-count of slice at the specified index and returns the
/// associated slice.
Slice RefSlice(size_t index);
/// The total number of bytes held by the SliceBuffer
size_t Length() { return slice_buffer_.length; }
/// Return a pointer to the back raw grpc_slice_buffer
grpc_slice_buffer* RawSliceBuffer() { return &slice_buffer_; }
private:
/// The backing raw slice buffer.
grpc_slice_buffer slice_buffer_;
};
} // namespace grpc_core
#endif // GRPC_CORE_LIB_SLICE_SLICE_BUFFER_H

@ -0,0 +1,35 @@
/*
*
* Copyright 2015 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/slice.h>
#include <grpc/slice_buffer.h>
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/slice/slice_internal.h"
void grpc_slice_buffer_destroy(grpc_slice_buffer* sb) {
grpc_core::ExecCtx exec_ctx;
grpc_slice_buffer_destroy_internal(sb);
}
void grpc_slice_buffer_reset_and_unref(grpc_slice_buffer* sb) {
grpc_core::ExecCtx exec_ctx;
grpc_slice_buffer_reset_and_unref_internal(sb);
}

@ -662,6 +662,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/slice/slice.cc',
'src/core/lib/slice/slice_api.cc',
'src/core/lib/slice/slice_buffer.cc',
'src/core/lib/slice/slice_buffer_api.cc',
'src/core/lib/slice/slice_refcount.cc',
'src/core/lib/slice/slice_split.cc',
'src/core/lib/slice/slice_string_helpers.cc',

@ -126,6 +126,18 @@ grpc_cc_test(
grpc_cc_test(
name = "slice_buffer_test",
srcs = ["slice_buffer_test.cc"],
external_deps = ["gtest"],
uses_event_engine = False,
uses_polling = False,
deps = [
"//:grpc",
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "c_slice_buffer_test",
srcs = ["c_slice_buffer_test.cc"],
language = "C++",
uses_event_engine = False,
uses_polling = False,

@ -0,0 +1,193 @@
/*
*
* Copyright 2015 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/grpc.h>
#include <grpc/slice_buffer.h>
#include <grpc/support/log.h>
#include "src/core/lib/slice/slice_internal.h"
#include "test/core/util/test_config.h"
static constexpr size_t kTotalDataLength = 4096;
void test_slice_buffer_add() {
grpc_slice_buffer buf;
grpc_slice aaa = grpc_slice_from_copied_string("aaa");
grpc_slice bb = grpc_slice_from_copied_string("bb");
size_t i;
grpc_slice_buffer_init(&buf);
for (i = 0; i < 10; i++) {
grpc_slice_ref(aaa);
grpc_slice_ref(bb);
grpc_slice_buffer_add(&buf, aaa);
grpc_slice_buffer_add(&buf, bb);
}
GPR_ASSERT(buf.count > 0);
GPR_ASSERT(buf.length == 50);
grpc_slice_buffer_reset_and_unref(&buf);
GPR_ASSERT(buf.count == 0);
GPR_ASSERT(buf.length == 0);
for (i = 0; i < 10; i++) {
grpc_slice_ref(aaa);
grpc_slice_ref(bb);
grpc_slice_buffer_add(&buf, aaa);
grpc_slice_buffer_add(&buf, bb);
}
GPR_ASSERT(buf.count > 0);
GPR_ASSERT(buf.length == 50);
for (i = 0; i < 10; i++) {
grpc_slice_buffer_pop(&buf);
grpc_slice_unref(aaa);
grpc_slice_unref(bb);
}
GPR_ASSERT(buf.count == 0);
GPR_ASSERT(buf.length == 0);
grpc_slice_buffer_destroy(&buf);
}
static void free_data(void* data, size_t len) {
GPR_ASSERT(len == kTotalDataLength);
gpr_free(data);
}
void test_slice_buffer_add_contiguous_slices() {
grpc_slice_buffer buf;
grpc_slice_buffer_init(&buf);
char* data = reinterpret_cast<char*>(gpr_malloc(kTotalDataLength));
GPR_ASSERT(data != nullptr);
grpc_slice a = grpc_slice_new_with_len(data, kTotalDataLength, free_data);
grpc_slice s1 = grpc_slice_split_head(&a, kTotalDataLength / 4);
grpc_slice s2 = grpc_slice_split_head(&a, kTotalDataLength / 4);
grpc_slice s3 = grpc_slice_split_head(&a, kTotalDataLength / 4);
grpc_slice_buffer_add(&buf, s1);
GPR_ASSERT(buf.count == 1);
GPR_ASSERT(buf.length == kTotalDataLength / 4);
grpc_slice_buffer_add(&buf, s2);
GPR_ASSERT(buf.count == 1);
GPR_ASSERT(buf.length == kTotalDataLength / 2);
grpc_slice_buffer_add(&buf, s3);
GPR_ASSERT(buf.count == 1);
GPR_ASSERT(buf.length == 3 * kTotalDataLength / 4);
grpc_slice_buffer_add(&buf, a);
GPR_ASSERT(buf.count == 1);
GPR_ASSERT(buf.length == kTotalDataLength);
grpc_slice_buffer_destroy(&buf);
}
void test_slice_buffer_move_first() {
grpc_slice slices[3];
grpc_slice_buffer src;
grpc_slice_buffer dst;
int idx = 0;
size_t src_len = 0;
size_t dst_len = 0;
slices[0] = grpc_slice_from_copied_string("aaa");
slices[1] = grpc_slice_from_copied_string("bbbb");
slices[2] = grpc_slice_from_copied_string("ccc");
grpc_slice_buffer_init(&src);
grpc_slice_buffer_init(&dst);
for (idx = 0; idx < 3; idx++) {
grpc_slice_ref(slices[idx]);
/* For this test, it is important that we add each slice at a new
slice index */
grpc_slice_buffer_add_indexed(&src, slices[idx]);
grpc_slice_buffer_add_indexed(&dst, slices[idx]);
}
/* Case 1: Move more than the first slice's length from src to dst */
src_len = src.length;
dst_len = dst.length;
grpc_slice_buffer_move_first(&src, 4, &dst);
src_len -= 4;
dst_len += 4;
GPR_ASSERT(src.length == src_len);
GPR_ASSERT(dst.length == dst_len);
/* src now has two slices ["bbb"] and ["ccc"] */
/* Case 2: Move the first slice from src to dst */
grpc_slice_buffer_move_first(&src, 3, &dst);
src_len -= 3;
dst_len += 3;
GPR_ASSERT(src.length == src_len);
GPR_ASSERT(dst.length == dst_len);
/* src now has one slice ["ccc"] */
/* Case 3: Move less than the first slice's length from src to dst*/
grpc_slice_buffer_move_first(&src, 2, &dst);
src_len -= 2;
dst_len += 2;
GPR_ASSERT(src.length == src_len);
GPR_ASSERT(dst.length == dst_len);
}
void test_slice_buffer_first() {
grpc_slice slices[3];
slices[0] = grpc_slice_from_copied_string("aaa");
slices[1] = grpc_slice_from_copied_string("bbbb");
slices[2] = grpc_slice_from_copied_string("ccccc");
grpc_slice_buffer buf;
grpc_slice_buffer_init(&buf);
for (int idx = 0; idx < 3; ++idx) {
grpc_slice_ref(slices[idx]);
grpc_slice_buffer_add_indexed(&buf, slices[idx]);
}
grpc_slice* first = grpc_slice_buffer_peek_first(&buf);
GPR_ASSERT(GPR_SLICE_LENGTH(*first) == GPR_SLICE_LENGTH(slices[0]));
GPR_ASSERT(buf.count == 3);
GPR_ASSERT(buf.length == 12);
grpc_slice_buffer_sub_first(&buf, 1, 2);
first = grpc_slice_buffer_peek_first(&buf);
GPR_ASSERT(GPR_SLICE_LENGTH(*first) == 1);
GPR_ASSERT(buf.count == 3);
GPR_ASSERT(buf.length == 10);
grpc_slice_buffer_remove_first(&buf);
first = grpc_slice_buffer_peek_first(&buf);
GPR_ASSERT(GPR_SLICE_LENGTH(*first) == GPR_SLICE_LENGTH(slices[1]));
GPR_ASSERT(buf.count == 2);
GPR_ASSERT(buf.length == 9);
grpc_slice_buffer_remove_first(&buf);
first = grpc_slice_buffer_peek_first(&buf);
GPR_ASSERT(GPR_SLICE_LENGTH(*first) == GPR_SLICE_LENGTH(slices[2]));
GPR_ASSERT(buf.count == 1);
GPR_ASSERT(buf.length == 5);
grpc_slice_buffer_remove_first(&buf);
GPR_ASSERT(buf.count == 0);
GPR_ASSERT(buf.length == 0);
}
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(&argc, argv);
grpc_init();
test_slice_buffer_add();
test_slice_buffer_add_contiguous_slices();
test_slice_buffer_move_first();
test_slice_buffer_first();
grpc_shutdown();
return 0;
}

@ -1,193 +1,81 @@
/*
*
* Copyright 2015 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.
*
*/
// Copyright 2022 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/lib/slice/slice_buffer.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <grpc/event_engine/slice_buffer.h>
#include <grpc/grpc.h>
#include <grpc/slice_buffer.h>
#include <grpc/support/log.h>
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice.h"
#include "test/core/util/test_config.h"
static constexpr size_t kTotalDataLength = 4096;
void test_slice_buffer_add() {
grpc_slice_buffer buf;
grpc_slice aaa = grpc_slice_from_copied_string("aaa");
grpc_slice bb = grpc_slice_from_copied_string("bb");
size_t i;
using ::grpc_core::Slice;
using ::grpc_core::SliceBuffer;
grpc_slice_buffer_init(&buf);
for (i = 0; i < 10; i++) {
grpc_slice_ref(aaa);
grpc_slice_ref(bb);
grpc_slice_buffer_add(&buf, aaa);
grpc_slice_buffer_add(&buf, bb);
}
GPR_ASSERT(buf.count > 0);
GPR_ASSERT(buf.length == 50);
grpc_slice_buffer_reset_and_unref(&buf);
GPR_ASSERT(buf.count == 0);
GPR_ASSERT(buf.length == 0);
for (i = 0; i < 10; i++) {
grpc_slice_ref(aaa);
grpc_slice_ref(bb);
grpc_slice_buffer_add(&buf, aaa);
grpc_slice_buffer_add(&buf, bb);
}
GPR_ASSERT(buf.count > 0);
GPR_ASSERT(buf.length == 50);
for (i = 0; i < 10; i++) {
grpc_slice_buffer_pop(&buf);
grpc_slice_unref(aaa);
grpc_slice_unref(bb);
}
GPR_ASSERT(buf.count == 0);
GPR_ASSERT(buf.length == 0);
grpc_slice_buffer_destroy(&buf);
}
static void free_data(void* data, size_t len) {
GPR_ASSERT(len == kTotalDataLength);
gpr_free(data);
}
static constexpr int kNewSliceLength = 100;
void test_slice_buffer_add_contiguous_slices() {
grpc_slice_buffer buf;
grpc_slice_buffer_init(&buf);
char* data = reinterpret_cast<char*>(gpr_malloc(kTotalDataLength));
GPR_ASSERT(data != nullptr);
grpc_slice a = grpc_slice_new_with_len(data, kTotalDataLength, free_data);
grpc_slice s1 = grpc_slice_split_head(&a, kTotalDataLength / 4);
grpc_slice s2 = grpc_slice_split_head(&a, kTotalDataLength / 4);
grpc_slice s3 = grpc_slice_split_head(&a, kTotalDataLength / 4);
grpc_slice_buffer_add(&buf, s1);
GPR_ASSERT(buf.count == 1);
GPR_ASSERT(buf.length == kTotalDataLength / 4);
grpc_slice_buffer_add(&buf, s2);
GPR_ASSERT(buf.count == 1);
GPR_ASSERT(buf.length == kTotalDataLength / 2);
grpc_slice_buffer_add(&buf, s3);
GPR_ASSERT(buf.count == 1);
GPR_ASSERT(buf.length == 3 * kTotalDataLength / 4);
grpc_slice_buffer_add(&buf, a);
GPR_ASSERT(buf.count == 1);
GPR_ASSERT(buf.length == kTotalDataLength);
grpc_slice_buffer_destroy(&buf);
Slice MakeSlice(size_t len) {
GPR_ASSERT(len > 0);
unsigned char* contents = reinterpret_cast<unsigned char*>(new char[len]);
memset(contents, 'a', len);
return Slice(grpc_slice_new(contents, len, gpr_free));
}
void test_slice_buffer_move_first() {
grpc_slice slices[3];
grpc_slice_buffer src;
grpc_slice_buffer dst;
int idx = 0;
size_t src_len = 0;
size_t dst_len = 0;
slices[0] = grpc_slice_from_copied_string("aaa");
slices[1] = grpc_slice_from_copied_string("bbbb");
slices[2] = grpc_slice_from_copied_string("ccc");
grpc_slice_buffer_init(&src);
grpc_slice_buffer_init(&dst);
for (idx = 0; idx < 3; idx++) {
grpc_slice_ref(slices[idx]);
/* For this test, it is important that we add each slice at a new
slice index */
grpc_slice_buffer_add_indexed(&src, slices[idx]);
grpc_slice_buffer_add_indexed(&dst, slices[idx]);
}
/* Case 1: Move more than the first slice's length from src to dst */
src_len = src.length;
dst_len = dst.length;
grpc_slice_buffer_move_first(&src, 4, &dst);
src_len -= 4;
dst_len += 4;
GPR_ASSERT(src.length == src_len);
GPR_ASSERT(dst.length == dst_len);
/* src now has two slices ["bbb"] and ["ccc"] */
/* Case 2: Move the first slice from src to dst */
grpc_slice_buffer_move_first(&src, 3, &dst);
src_len -= 3;
dst_len += 3;
GPR_ASSERT(src.length == src_len);
GPR_ASSERT(dst.length == dst_len);
/* src now has one slice ["ccc"] */
/* Case 3: Move less than the first slice's length from src to dst*/
grpc_slice_buffer_move_first(&src, 2, &dst);
src_len -= 2;
dst_len += 2;
GPR_ASSERT(src.length == src_len);
GPR_ASSERT(dst.length == dst_len);
TEST(SliceBufferTest, AddAndRemoveTest) {
SliceBuffer sb;
Slice first_slice = MakeSlice(kNewSliceLength);
Slice second_slice = MakeSlice(kNewSliceLength);
Slice first_slice_copy = first_slice.Copy();
sb.Append(std::move(first_slice));
sb.Append(std::move(second_slice));
ASSERT_EQ(sb.Count(), 2);
ASSERT_EQ(sb.Length(), 2 * kNewSliceLength);
Slice popped = sb.TakeFirst();
ASSERT_EQ(popped, first_slice_copy);
ASSERT_EQ(sb.Count(), 1);
ASSERT_EQ(sb.Length(), kNewSliceLength);
sb.Prepend(std::move(popped));
ASSERT_EQ(sb.Count(), 2);
ASSERT_EQ(sb.Length(), 2 * kNewSliceLength);
sb.Clear();
ASSERT_EQ(sb.Count(), 0);
ASSERT_EQ(sb.Length(), 0);
}
void test_slice_buffer_first() {
grpc_slice slices[3];
slices[0] = grpc_slice_from_copied_string("aaa");
slices[1] = grpc_slice_from_copied_string("bbbb");
slices[2] = grpc_slice_from_copied_string("ccccc");
grpc_slice_buffer buf;
grpc_slice_buffer_init(&buf);
for (int idx = 0; idx < 3; ++idx) {
grpc_slice_ref(slices[idx]);
grpc_slice_buffer_add_indexed(&buf, slices[idx]);
}
grpc_slice* first = grpc_slice_buffer_peek_first(&buf);
GPR_ASSERT(GPR_SLICE_LENGTH(*first) == GPR_SLICE_LENGTH(slices[0]));
GPR_ASSERT(buf.count == 3);
GPR_ASSERT(buf.length == 12);
grpc_slice_buffer_sub_first(&buf, 1, 2);
first = grpc_slice_buffer_peek_first(&buf);
GPR_ASSERT(GPR_SLICE_LENGTH(*first) == 1);
GPR_ASSERT(buf.count == 3);
GPR_ASSERT(buf.length == 10);
grpc_slice_buffer_remove_first(&buf);
first = grpc_slice_buffer_peek_first(&buf);
GPR_ASSERT(GPR_SLICE_LENGTH(*first) == GPR_SLICE_LENGTH(slices[1]));
GPR_ASSERT(buf.count == 2);
GPR_ASSERT(buf.length == 9);
grpc_slice_buffer_remove_first(&buf);
first = grpc_slice_buffer_peek_first(&buf);
GPR_ASSERT(GPR_SLICE_LENGTH(*first) == GPR_SLICE_LENGTH(slices[2]));
GPR_ASSERT(buf.count == 1);
GPR_ASSERT(buf.length == 5);
grpc_slice_buffer_remove_first(&buf);
GPR_ASSERT(buf.count == 0);
GPR_ASSERT(buf.length == 0);
TEST(SliceBufferTest, SliceRefTest) {
SliceBuffer sb;
Slice first_slice = MakeSlice(kNewSliceLength);
Slice second_slice = MakeSlice(kNewSliceLength + 1);
Slice first_slice_copy = first_slice.Copy();
Slice second_slice_copy = second_slice.Copy();
ASSERT_EQ(sb.AppendIndexed(std::move(first_slice)), 0);
ASSERT_EQ(sb.AppendIndexed(std::move(second_slice)), 1);
Slice first_reffed = sb.RefSlice(0);
Slice second_reffed = sb.RefSlice(1);
ASSERT_EQ(first_reffed, first_slice_copy);
ASSERT_EQ(second_reffed, second_slice_copy);
ASSERT_EQ(sb.Count(), 2);
ASSERT_EQ(sb.Length(), 2 * kNewSliceLength + 1);
sb.Clear();
}
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(&argc, argv);
grpc_init();
test_slice_buffer_add();
test_slice_buffer_add_contiguous_slices();
test_slice_buffer_move_first();
test_slice_buffer_first();
grpc_shutdown();
return 0;
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -2367,6 +2367,8 @@ src/core/lib/slice/slice.cc \
src/core/lib/slice/slice.h \
src/core/lib/slice/slice_api.cc \
src/core/lib/slice/slice_buffer.cc \
src/core/lib/slice/slice_buffer.h \
src/core/lib/slice/slice_buffer_api.cc \
src/core/lib/slice/slice_internal.h \
src/core/lib/slice/slice_refcount.cc \
src/core/lib/slice/slice_refcount.h \

@ -2162,6 +2162,8 @@ src/core/lib/slice/slice.cc \
src/core/lib/slice/slice.h \
src/core/lib/slice/slice_api.cc \
src/core/lib/slice/slice_buffer.cc \
src/core/lib/slice/slice_buffer.h \
src/core/lib/slice/slice_buffer_api.cc \
src/core/lib/slice/slice_internal.h \
src/core/lib/slice/slice_refcount.cc \
src/core/lib/slice/slice_refcount.h \

@ -525,6 +525,30 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": false,
"language": "c",
"name": "c_slice_buffer_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,
@ -2309,30 +2333,6 @@
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": false,
"language": "c",
"name": "test_core_slice_slice_buffer_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,
@ -6925,6 +6925,30 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "test_core_slice_slice_buffer_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,

@ -29,9 +29,9 @@ BANNED_EXCEPT = {
'grpc_resource_quota_unref(': [
'src/core/lib/resource_quota/api.cc', 'src/core/lib/surface/server.cc'
],
'grpc_slice_buffer_destroy(': ['src/core/lib/slice/slice_buffer.cc'],
'grpc_slice_buffer_destroy(': ['src/core/lib/slice/slice_buffer_api.cc'],
'grpc_slice_buffer_reset_and_unref(': [
'src/core/lib/slice/slice_buffer.cc'
'src/core/lib/slice/slice_buffer_api.cc'
],
'grpc_slice_ref(': ['src/core/lib/slice/slice_api.cc'],
'grpc_slice_unref(': ['src/core/lib/slice/slice_api.cc'],

Loading…
Cancel
Save