Revert "Reland slice changes (#28601)" (#28615)

This reverts commit b33e0d40af.
pull/28618/head
Craig Tiller 3 years ago committed by GitHub
parent fda6158600
commit 939bbfc336
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      BUILD
  2. 30
      CMakeLists.txt
  3. 2
      Makefile
  4. 23
      build_autogenerated.yaml
  5. 1
      config.m4
  6. 1
      config.w32
  7. 2
      gRPC-C++.podspec
  8. 3
      gRPC-Core.podspec
  9. 4
      grpc.def
  10. 2
      grpc.gemspec
  11. 2
      grpc.gyp
  12. 5
      include/grpc/impl/codegen/slice.h
  13. 11
      include/grpc/slice.h
  14. 2
      package.xml
  15. 2
      src/core/ext/transport/binder/transport/binder_transport.cc
  16. 66
      src/core/ext/transport/chttp2/transport/hpack_parser.cc
  17. 2
      src/core/ext/transport/chttp2/transport/parsing.cc
  18. 7
      src/core/ext/transport/cronet/transport/cronet_transport.cc
  19. 2
      src/core/ext/xds/xds_api.cc
  20. 2
      src/core/ext/xds/xds_server_config_fetcher.cc
  21. 2
      src/core/lib/compression/compression.cc
  22. 2
      src/core/lib/compression/compression_internal.cc
  23. 22
      src/core/lib/event_engine/memory_allocator.cc
  24. 1
      src/core/lib/iomgr/error.cc
  25. 2
      src/core/lib/security/authorization/evaluate_args.cc
  26. 1
      src/core/lib/security/credentials/external/file_external_account_credentials.cc
  27. 257
      src/core/lib/slice/slice.cc
  28. 43
      src/core/lib/slice/slice.h
  29. 269
      src/core/lib/slice/slice_intern.cc
  30. 42
      src/core/lib/slice/slice_internal.h
  31. 16
      src/core/lib/slice/slice_refcount.cc
  32. 74
      src/core/lib/slice/slice_refcount.h
  33. 136
      src/core/lib/slice/slice_refcount_base.h
  34. 200
      src/core/lib/slice/slice_utils.h
  35. 2
      src/core/lib/surface/call.cc
  36. 2
      src/core/lib/surface/init.cc
  37. 24
      src/core/lib/surface/server.cc
  38. 4
      src/core/lib/surface/server.h
  39. 6
      src/cpp/ext/filters/census/client_filter.cc
  40. 2
      src/cpp/ext/filters/census/server_filter.cc
  41. 1
      src/python/grpcio/grpc_core_dependencies.py
  42. 8
      src/ruby/ext/grpc/rb_grpc_imports.generated.c
  43. 12
      src/ruby/ext/grpc/rb_grpc_imports.generated.h
  44. 5
      test/core/end2end/fuzzers/api_fuzzer.cc
  45. 6
      test/core/end2end/fuzzers/api_fuzzer.proto
  46. 12
      test/core/slice/BUILD
  47. 67
      test/core/slice/slice_intern_test.cc
  48. 7
      test/core/slice/slice_test.cc
  49. 4
      test/core/surface/public_headers_must_be_c89.c
  50. 9
      test/core/transport/chttp2/hpack_encoder_test.cc
  51. 11
      test/core/util/evaluate_args_test_util.h
  52. 2
      test/cpp/end2end/channelz_service_test.cc
  53. 2
      tools/doxygen/Doxyfile.c++.internal
  54. 2
      tools/doxygen/Doxyfile.core.internal
  55. 24
      tools/run_tests/generated/tests.json

@ -1573,6 +1573,7 @@ grpc_cc_library(
hdrs = [
"src/core/lib/slice/slice_refcount.h",
"src/core/lib/slice/slice_refcount_base.h",
"src/core/lib/slice/slice_utils.h",
],
public_hdrs = [
"include/grpc/slice.h",
@ -1886,6 +1887,7 @@ grpc_cc_library(
"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_intern.cc",
"src/core/lib/slice/slice_split.cc",
"src/core/lib/surface/api_trace.cc",
"src/core/lib/surface/builtins.cc",

30
CMakeLists.txt generated

@ -735,6 +735,7 @@ if(gRPC_BUILD_TESTS)
endif()
add_dependencies(buildtests_c server_test)
add_dependencies(buildtests_c slice_buffer_test)
add_dependencies(buildtests_c slice_intern_test)
add_dependencies(buildtests_c slice_split_test)
add_dependencies(buildtests_c slice_string_helpers_test)
add_dependencies(buildtests_c sockaddr_resolver_test)
@ -2082,6 +2083,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_intern.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_split.cc
src/core/lib/slice/slice_string_helpers.cc
@ -2667,6 +2669,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_intern.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_split.cc
src/core/lib/slice/slice_string_helpers.cc
@ -6705,6 +6708,33 @@ target_link_libraries(slice_buffer_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(slice_intern_test
test/core/slice/slice_intern_test.cc
)
target_include_directories(slice_intern_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(slice_intern_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
)
endif()
if(gRPC_BUILD_TESTS)

2
Makefile generated

@ -1566,6 +1566,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_intern.cc \
src/core/lib/slice/slice_refcount.cc \
src/core/lib/slice/slice_split.cc \
src/core/lib/slice/slice_string_helpers.cc \
@ -1998,6 +1999,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_intern.cc \
src/core/lib/slice/slice_refcount.cc \
src/core/lib/slice/slice_split.cc \
src/core/lib/slice/slice_string_helpers.cc \

@ -932,6 +932,7 @@ libs:
- src/core/lib/slice/slice_refcount_base.h
- src/core/lib/slice/slice_split.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/lib/slice/slice_utils.h
- src/core/lib/surface/api_trace.h
- src/core/lib/surface/builtins.h
- src/core/lib/surface/call.h
@ -1533,6 +1534,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_intern.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_split.cc
- src/core/lib/slice/slice_string_helpers.cc
@ -1989,6 +1991,7 @@ libs:
- src/core/lib/slice/slice_refcount_base.h
- src/core/lib/slice/slice_split.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/lib/slice/slice_utils.h
- src/core/lib/surface/api_trace.h
- src/core/lib/surface/builtins.h
- src/core/lib/surface/call.h
@ -2265,6 +2268,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_intern.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_split.cc
- src/core/lib/slice/slice_string_helpers.cc
@ -3766,6 +3770,7 @@ targets:
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_refcount_base.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/lib/slice/slice_utils.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/event_engine/memory_allocator.cc
@ -4016,6 +4021,15 @@ targets:
deps:
- grpc_test_util
uses_polling: false
- name: slice_intern_test
build: test
language: c
headers: []
src:
- test/core/slice/slice_intern_test.cc
deps:
- grpc_test_util
uses_polling: false
- name: slice_split_test
build: test
language: c
@ -4038,6 +4052,7 @@ targets:
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_refcount_base.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/lib/slice/slice_utils.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/slice/slice.cc
@ -4515,6 +4530,7 @@ targets:
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_refcount_base.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/lib/slice/slice_utils.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/event_engine/memory_allocator.cc
@ -5007,6 +5023,7 @@ targets:
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_refcount_base.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/lib/slice/slice_utils.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/event_engine/memory_allocator.cc
@ -5639,6 +5656,7 @@ targets:
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_refcount_base.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/lib/slice/slice_utils.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/iomgr/combiner.cc
@ -5848,6 +5866,7 @@ targets:
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_refcount_base.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/lib/slice/slice_utils.h
- test/core/promise/test_wakeup_schedulers.h
src:
- src/core/lib/debug/trace.cc
@ -6612,6 +6631,7 @@ targets:
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_refcount_base.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/lib/slice/slice_utils.h
- test/core/resource_quota/call_checker.h
src:
- src/core/lib/debug/trace.cc
@ -6917,6 +6937,7 @@ targets:
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_refcount_base.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/lib/slice/slice_utils.h
- test/core/promise/test_wakeup_schedulers.h
src:
- src/core/lib/debug/trace.cc
@ -7269,6 +7290,7 @@ targets:
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_refcount_base.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/lib/slice/slice_utils.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/event_engine/memory_allocator.cc
@ -7705,6 +7727,7 @@ targets:
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_refcount_base.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/lib/slice/slice_utils.h
- test/core/util/build.h
src:
- src/core/lib/debug/trace.cc

1
config.m4 generated

@ -628,6 +628,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_intern.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

@ -594,6 +594,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_intern.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

@ -805,6 +805,7 @@ Pod::Spec.new do |s|
'src/core/lib/slice/slice_refcount_base.h',
'src/core/lib/slice/slice_split.h',
'src/core/lib/slice/slice_string_helpers.h',
'src/core/lib/slice/slice_utils.h',
'src/core/lib/surface/api_trace.h',
'src/core/lib/surface/builtins.h',
'src/core/lib/surface/call.h',
@ -1538,6 +1539,7 @@ Pod::Spec.new do |s|
'src/core/lib/slice/slice_refcount_base.h',
'src/core/lib/slice/slice_split.h',
'src/core/lib/slice/slice_string_helpers.h',
'src/core/lib/slice/slice_utils.h',
'src/core/lib/surface/api_trace.h',
'src/core/lib/surface/builtins.h',
'src/core/lib/surface/call.h',

3
gRPC-Core.podspec generated

@ -1327,6 +1327,7 @@ 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_intern.cc',
'src/core/lib/slice/slice_internal.h',
'src/core/lib/slice/slice_refcount.cc',
'src/core/lib/slice/slice_refcount.h',
@ -1335,6 +1336,7 @@ Pod::Spec.new do |s|
'src/core/lib/slice/slice_split.h',
'src/core/lib/slice/slice_string_helpers.cc',
'src/core/lib/slice/slice_string_helpers.h',
'src/core/lib/slice/slice_utils.h',
'src/core/lib/surface/api_trace.cc',
'src/core/lib/surface/api_trace.h',
'src/core/lib/surface/builtins.cc',
@ -2080,6 +2082,7 @@ Pod::Spec.new do |s|
'src/core/lib/slice/slice_refcount_base.h',
'src/core/lib/slice/slice_split.h',
'src/core/lib/slice/slice_string_helpers.h',
'src/core/lib/slice/slice_utils.h',
'src/core/lib/surface/api_trace.h',
'src/core/lib/surface/builtins.h',
'src/core/lib/surface/call.h',

4
grpc.def generated

@ -190,6 +190,7 @@ EXPORTS
grpc_slice_new_with_len
grpc_slice_malloc
grpc_slice_malloc_large
grpc_slice_intern
grpc_slice_from_copied_string
grpc_slice_from_copied_buffer
grpc_slice_from_static_string
@ -200,6 +201,8 @@ EXPORTS
grpc_slice_split_tail_maybe_ref
grpc_slice_split_head
grpc_empty_slice
grpc_slice_default_hash_impl
grpc_slice_default_eq_impl
grpc_slice_eq
grpc_slice_cmp
grpc_slice_str_cmp
@ -207,6 +210,7 @@ EXPORTS
grpc_slice_rchr
grpc_slice_chr
grpc_slice_slice
grpc_slice_hash
grpc_slice_is_equivalent
grpc_slice_dup
grpc_slice_to_c_string

2
grpc.gemspec generated

@ -1246,6 +1246,7 @@ 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_intern.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 )
@ -1254,6 +1255,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/slice/slice_split.h )
s.files += %w( src/core/lib/slice/slice_string_helpers.cc )
s.files += %w( src/core/lib/slice/slice_string_helpers.h )
s.files += %w( src/core/lib/slice/slice_utils.h )
s.files += %w( src/core/lib/surface/api_trace.cc )
s.files += %w( src/core/lib/surface/api_trace.h )
s.files += %w( src/core/lib/surface/builtins.cc )

2
grpc.gyp generated

@ -1014,6 +1014,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_intern.cc',
'src/core/lib/slice/slice_refcount.cc',
'src/core/lib/slice/slice_split.cc',
'src/core/lib/slice/slice_string_helpers.cc',
@ -1418,6 +1419,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_intern.cc',
'src/core/lib/slice/slice_refcount.cc',
'src/core/lib/slice/slice_split.cc',
'src/core/lib/slice/slice_string_helpers.cc',

@ -58,10 +58,7 @@ struct grpc_slice_refcount;
Multiple grpc_slice values may share a ref count.
If the slice does not have a refcount, it represents an inlined small piece
of data that is copied by value.
As a special case, a slice can be given refcount == uintptr_t(1), meaning
that the slice represents external data that is not refcounted. */
of data that is copied by value. */
struct grpc_slice {
struct grpc_slice_refcount* refcount;
union grpc_slice_data {

@ -69,6 +69,12 @@ GPRAPI grpc_slice grpc_slice_malloc_large(size_t length);
#define GRPC_SLICE_MALLOC(len) grpc_slice_malloc(len)
/** Intern a slice:
The return value for two invocations of this function with the same sequence
of bytes is a slice which points to the same memory. */
GPRAPI grpc_slice grpc_slice_intern(grpc_slice slice);
/** Create a slice by copying a string.
Does not preserve null terminators.
Equivalent to:
@ -123,6 +129,9 @@ GPRAPI grpc_slice grpc_slice_split_head(grpc_slice* s, size_t split);
GPRAPI grpc_slice grpc_empty_slice(void);
GPRAPI uint32_t grpc_slice_default_hash_impl(grpc_slice s);
GPRAPI int grpc_slice_default_eq_impl(grpc_slice a, grpc_slice b);
GPRAPI int grpc_slice_eq(grpc_slice a, grpc_slice b);
/** Returns <0 if a < b, ==0 if a == b, >0 if a > b
@ -142,6 +151,8 @@ GPRAPI int grpc_slice_chr(grpc_slice s, char c);
if it's not found */
GPRAPI int grpc_slice_slice(grpc_slice haystack, grpc_slice needle);
GPRAPI uint32_t grpc_slice_hash(grpc_slice s);
/** Do two slices point at the same memory, with the same length
If a or b is inlined, actually compares data */
GPRAPI int grpc_slice_is_equivalent(grpc_slice a, grpc_slice b);

2
package.xml generated

@ -1226,6 +1226,7 @@
<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_intern.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" />
@ -1234,6 +1235,7 @@
<file baseinstalldir="/" name="src/core/lib/slice/slice_split.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_string_helpers.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_string_helpers.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_utils.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/api_trace.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/api_trace.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/builtins.cc" role="src" />

@ -36,7 +36,7 @@
#include "src/core/ext/transport/binder/wire_format/wire_reader_impl.h"
#include "src/core/ext/transport/binder/wire_format/wire_writer.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_utils.h"
#include "src/core/lib/transport/byte_stream.h"
#include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/transport/metadata_batch.h"

@ -647,6 +647,17 @@ class HPackParser::Input {
// Helper to parse a string and turn it into a slice with appropriate memory
// management characteristics
class HPackParser::String {
public:
// Helper to specify a string should be internalized
struct Intern {};
// Helper to specify a string should be externalized
struct Extern {};
private:
// Forward declare take functions... we'll need them in the public interface
Slice Take(Extern);
Slice Take(Intern);
public:
String(const String&) = delete;
String& operator=(const String&) = delete;
@ -660,7 +671,11 @@ class HPackParser::String {
}
// Take the value and leave this empty
Slice Take();
// Use Intern/Extern to choose memory management
template <typename T>
auto Take() -> decltype(this->Take(T())) {
return Take(T());
}
// Return a reference to the value as a string view
absl::string_view string_view() const {
@ -947,11 +962,13 @@ class HPackParser::Parser {
case 1:
switch (cur & 0xf) {
case 0: // literal key
return FinishHeaderOmitFromTable(ParseLiteralKey());
return FinishHeaderOmitFromTable(ParseLiteralKey<String::Extern>());
case 0xf: // varint encoded key index
return FinishHeaderOmitFromTable(ParseVarIdxKey(0xf));
return FinishHeaderOmitFromTable(
ParseVarIdxKey<String::Extern>(0xf));
default: // inline encoded key index
return FinishHeaderOmitFromTable(ParseIdxKey(cur & 0xf));
return FinishHeaderOmitFromTable(
ParseIdxKey<String::Extern>(cur & 0xf));
}
// Update max table size.
// First byte format: 001xxxxx
@ -978,20 +995,23 @@ class HPackParser::Parser {
case 4:
if (cur == 0x40) {
// literal key
return FinishHeaderAndAddToTable(ParseLiteralKey());
return FinishHeaderAndAddToTable(ParseLiteralKey<String::Intern>());
}
ABSL_FALLTHROUGH_INTENDED;
case 5:
case 6:
// inline encoded key index
return FinishHeaderAndAddToTable(ParseIdxKey(cur & 0x3f));
return FinishHeaderAndAddToTable(
ParseIdxKey<String::Intern>(cur & 0x3f));
case 7:
if (cur == 0x7f) {
// varint encoded key index
return FinishHeaderAndAddToTable(ParseVarIdxKey(0x3f));
return FinishHeaderAndAddToTable(
ParseVarIdxKey<String::Intern>(0x3f));
} else {
// inline encoded key index
return FinishHeaderAndAddToTable(ParseIdxKey(cur & 0x3f));
return FinishHeaderAndAddToTable(
ParseIdxKey<String::Intern>(cur & 0x3f));
}
// Indexed Header Field Representation
// First byte format: 1xxxxxxx
@ -1093,6 +1113,7 @@ class HPackParser::Parser {
}
// Parse a string encoded key and a string encoded value
template <typename TakeValueType>
absl::optional<HPackTable::Memento> ParseLiteralKey() {
auto key = String::Parse(input_);
if (!key.has_value()) return {};
@ -1101,7 +1122,7 @@ class HPackParser::Parser {
return {};
}
auto key_string = key->string_view();
auto value_slice = value->Take();
auto value_slice = value->Take<TakeValueType>();
const auto transport_size = key_string.size() + value_slice.size() +
hpack_constants::kEntryOverhead;
return grpc_metadata_batch::Parse(
@ -1112,6 +1133,7 @@ class HPackParser::Parser {
}
// Parse an index encoded key and a string encoded value
template <typename TakeValueType>
absl::optional<HPackTable::Memento> ParseIdxKey(uint32_t index) {
const auto* elem = table_->Lookup(index);
if (GPR_UNLIKELY(elem == nullptr)) {
@ -1120,17 +1142,19 @@ class HPackParser::Parser {
}
auto value = ParseValueString(elem->is_binary_header());
if (GPR_UNLIKELY(!value.has_value())) return {};
return elem->WithNewValue(
value->Take(), [=](absl::string_view error, const Slice& value) {
ReportMetadataParseError(elem->key(), error, value.as_string_view());
});
return elem->WithNewValue(value->Take<TakeValueType>(),
[=](absl::string_view error, const Slice& value) {
ReportMetadataParseError(
elem->key(), error, value.as_string_view());
});
}
// Parse a varint index encoded key and a string encoded value
template <typename TakeValueType>
absl::optional<HPackTable::Memento> ParseVarIdxKey(uint32_t offset) {
auto index = input_->ParseVarint(offset);
if (GPR_UNLIKELY(!index.has_value())) return {};
return ParseIdxKey(*index);
return ParseIdxKey<TakeValueType>(*index);
}
// Parse a string, figuring out if it's binary or not by the key name.
@ -1226,7 +1250,7 @@ class HPackParser::Parser {
const LogInfo log_info_;
};
Slice HPackParser::String::Take() {
Slice HPackParser::String::Take(Extern) {
if (auto* p = absl::get_if<Slice>(&value_)) {
return p->Copy();
} else if (auto* p = absl::get_if<absl::Span<const uint8_t>>(&value_)) {
@ -1237,6 +1261,18 @@ Slice HPackParser::String::Take() {
GPR_UNREACHABLE_CODE(return Slice());
}
Slice HPackParser::String::Take(Intern) {
ManagedMemorySlice m;
if (auto* p = absl::get_if<Slice>(&value_)) {
m = ManagedMemorySlice(&p->c_slice());
} else if (auto* p = absl::get_if<absl::Span<const uint8_t>>(&value_)) {
m = ManagedMemorySlice(reinterpret_cast<const char*>(p->data()), p->size());
} else if (auto* p = absl::get_if<std::vector<uint8_t>>(&value_)) {
m = ManagedMemorySlice(reinterpret_cast<const char*>(p->data()), p->size());
}
return Slice(m);
}
/* PUBLIC INTERFACE */
HPackParser::HPackParser() = default;

@ -28,8 +28,8 @@
#include "src/core/ext/transport/chttp2/transport/internal.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/slice/slice_utils.h"
#include "src/core/lib/transport/http2_errors.h"
#include "src/core/lib/transport/status_conversion.h"
#include "src/core/lib/transport/timeout_encoding.h"

@ -410,10 +410,11 @@ static void convert_cronet_array_to_metadata(
grpc_slice value;
if (absl::EndsWith(header_array->headers[i].key, "-bin")) {
value = grpc_slice_from_static_string(header_array->headers[i].value);
value = grpc_chttp2_base64_decode_with_length(
value, grpc_chttp2_base64_infer_length_after_decode(value));
value = grpc_slice_intern(grpc_chttp2_base64_decode_with_length(
value, grpc_chttp2_base64_infer_length_after_decode(value)));
} else {
value = grpc_slice_from_static_string(header_array->headers[i].value);
value = grpc_slice_intern(
grpc_slice_from_static_string(header_array->headers[i].value));
}
mds->Append(header_array->headers[i].key, grpc_core::Slice(value),
[&](absl::string_view error, const grpc_core::Slice& value) {

@ -57,7 +57,7 @@
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/socket_utils.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_utils.h"
#include "src/core/lib/uri/uri_parser.h"
namespace grpc_core {

@ -37,7 +37,7 @@
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/socket_utils.h"
#include "src/core/lib/security/credentials/xds/xds_credentials.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_utils.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/server.h"
#include "src/core/lib/transport/error_utils.h"

@ -25,7 +25,7 @@
#include "src/core/lib/compression/compression_internal.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_utils.h"
#include "src/core/lib/surface/api_trace.h"
int grpc_compression_algorithm_is_message(grpc_compression_algorithm) {

@ -33,7 +33,7 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_utils.h"
#include "src/core/lib/surface/api_trace.h"
namespace grpc_core {

@ -26,24 +26,28 @@ namespace {
// Reference count for a slice allocated by MemoryAllocator::MakeSlice.
// Takes care of releasing memory back when the slice is destroyed.
class SliceRefCount : public grpc_slice_refcount {
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)
: grpc_slice_refcount(Destroy),
: base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
&base_),
allocator_(std::move(allocator)),
size_(size) {
// Nothing to do here.
}
~SliceRefCount() { allocator_->Release(size_); }
private:
static void Destroy(grpc_slice_refcount* p) {
auto* rc = static_cast<SliceRefCount*>(p);
rc->~SliceRefCount();
gpr_free(rc);
}
grpc_slice_refcount* base_refcount() { return &base_; }
private:
grpc_slice_refcount base_;
std::atomic<size_t> refs_{1};
std::shared_ptr<internal::MemoryAllocatorImpl> allocator_;
size_t size_;
};
@ -55,7 +59,7 @@ grpc_slice MemoryAllocator::MakeSlice(MemoryRequest request) {
void* p = gpr_malloc(size);
new (p) SliceRefCount(allocator_, size);
grpc_slice slice;
slice.refcount = static_cast<SliceRefCount*>(p);
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);

@ -35,6 +35,7 @@
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/error_internal.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_utils.h"
grpc_core::DebugOnlyTraceFlag grpc_trace_error_refcount(false,
"error_refcount");

@ -22,7 +22,7 @@
#include "src/core/lib/address_utils/sockaddr_utils.h"
#include "src/core/lib/gprpp/host_port.h"
#include "src/core/lib/security/credentials/tls/tls_utils.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_utils.h"
namespace grpc_core {

@ -21,6 +21,7 @@
#include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_utils.h"
namespace grpc_core {

@ -18,8 +18,6 @@
#include <grpc/support/port_platform.h>
#include "src/core/lib/slice/slice.h"
#include <string.h>
#include <grpc/slice.h>
@ -29,7 +27,6 @@
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_refcount_base.h"
char* grpc_slice_to_c_string(grpc_slice slice) {
char* out = static_cast<char*>(gpr_malloc(GRPC_SLICE_LENGTH(slice) + 1));
@ -38,9 +35,7 @@ char* grpc_slice_to_c_string(grpc_slice slice) {
return out;
}
grpc_slice grpc_empty_slice(void) {
return grpc_core::slice_detail::EmptySlice();
}
grpc_slice grpc_empty_slice(void) { return grpc_core::UnmanagedMemorySlice(); }
grpc_slice grpc_slice_copy(grpc_slice s) {
grpc_slice out = GRPC_SLICE_MALLOC(GRPC_SLICE_LENGTH(s));
@ -51,21 +46,30 @@ grpc_slice grpc_slice_copy(grpc_slice s) {
namespace grpc_core {
/* grpc_slice_from_static_string support structure - a refcount that does
nothing */
grpc_slice_refcount kNoopRefcount(grpc_slice_refcount::Type::NOP);
static_assert(std::is_trivially_destructible<decltype(kNoopRefcount)>::value,
"kNoopRefcount must be trivially destructible.");
/* grpc_slice_new support structures - we create a refcount object extended
with the user provided data pointer & destroy function */
class NewSliceRefcount : public grpc_slice_refcount {
class NewSliceRefcount {
public:
static void Destroy(void* arg) { delete static_cast<NewSliceRefcount*>(arg); }
NewSliceRefcount(void (*destroy)(void*), void* user_data)
: grpc_slice_refcount(Destroy),
: base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
&base_),
user_destroy_(destroy),
user_data_(user_data) {}
~NewSliceRefcount() { user_destroy_(user_data_); }
private:
static void Destroy(grpc_slice_refcount* arg) {
delete static_cast<NewSliceRefcount*>(arg);
}
grpc_slice_refcount* base_refcount() { return &base_; }
private:
grpc_slice_refcount base_;
std::atomic<size_t> refs_{1};
void (*user_destroy_)(void*);
void* user_data_;
};
@ -73,8 +77,7 @@ class NewSliceRefcount : public grpc_slice_refcount {
} // namespace grpc_core
size_t grpc_slice_memory_usage(grpc_slice s) {
if (s.refcount == nullptr ||
s.refcount == grpc_slice_refcount::NoopRefcount()) {
if (s.refcount == nullptr || s.refcount == &grpc_core::kNoopRefcount) {
return 0;
} else {
return s.data.refcounted.length;
@ -82,18 +85,19 @@ size_t grpc_slice_memory_usage(grpc_slice s) {
}
grpc_slice grpc_slice_from_static_buffer(const void* s, size_t len) {
return grpc_core::StaticSlice::FromStaticBuffer(s, len).TakeCSlice();
return grpc_core::ExternallyManagedSlice(s, len);
}
grpc_slice grpc_slice_from_static_string(const char* s) {
return grpc_core::StaticSlice::FromStaticString(s).TakeCSlice();
return grpc_core::ExternallyManagedSlice(s, strlen(s));
}
grpc_slice grpc_slice_new_with_user_data(void* p, size_t len,
void (*destroy)(void*),
void* user_data) {
grpc_slice slice;
slice.refcount = new grpc_core::NewSliceRefcount(destroy, user_data);
slice.refcount =
(new grpc_core::NewSliceRefcount(destroy, user_data))->base_refcount();
slice.data.refcounted.bytes = static_cast<uint8_t*>(p);
slice.data.refcounted.length = len;
return slice;
@ -107,51 +111,68 @@ grpc_slice grpc_slice_new(void* p, size_t len, void (*destroy)(void*)) {
namespace grpc_core {
/* grpc_slice_new_with_len support structures - we create a refcount object
extended with the user provided data pointer & destroy function */
class NewWithLenSliceRefcount : public grpc_slice_refcount {
class NewWithLenSliceRefcount {
public:
static void Destroy(void* arg) {
delete static_cast<NewWithLenSliceRefcount*>(arg);
}
NewWithLenSliceRefcount(void (*destroy)(void*, size_t), void* user_data,
size_t user_length)
: grpc_slice_refcount(Destroy),
: base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
&base_),
user_data_(user_data),
user_length_(user_length),
user_destroy_(destroy) {}
~NewWithLenSliceRefcount() { user_destroy_(user_data_, user_length_); }
private:
static void Destroy(grpc_slice_refcount* arg) {
delete static_cast<NewWithLenSliceRefcount*>(arg);
}
grpc_slice_refcount* base_refcount() { return &base_; }
private:
grpc_slice_refcount base_;
std::atomic<size_t> refs_{1};
void* user_data_;
size_t user_length_;
void (*user_destroy_)(void*, size_t);
};
/** grpc_slice_from_moved_(string|buffer) ref count .*/
class MovedStringSliceRefCount : public grpc_slice_refcount {
class MovedStringSliceRefCount {
public:
explicit MovedStringSliceRefCount(UniquePtr<char>&& str)
: grpc_slice_refcount(Destroy), str_(std::move(str)) {}
: base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
&base_),
str_(std::move(str)) {}
grpc_slice_refcount* base_refcount() { return &base_; }
private:
static void Destroy(grpc_slice_refcount* arg) {
static void Destroy(void* arg) {
delete static_cast<MovedStringSliceRefCount*>(arg);
}
grpc_slice_refcount base_;
std::atomic<size_t> refs_{1};
UniquePtr<char> str_;
};
// grpc_slice_from_cpp_string() ref count.
class MovedCppStringSliceRefCount : public grpc_slice_refcount {
class MovedCppStringSliceRefCount {
public:
explicit MovedCppStringSliceRefCount(std::string&& str)
: grpc_slice_refcount(Destroy), str_(std::move(str)) {}
: base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
&base_),
str_(std::move(str)) {}
grpc_slice_refcount* base_refcount() { return &base_; }
private:
static void Destroy(grpc_slice_refcount* arg) {
static void Destroy(void* arg) {
delete static_cast<MovedCppStringSliceRefCount*>(arg);
}
grpc_slice_refcount base_;
std::atomic<size_t> refs_{1};
std::string str_;
};
@ -160,17 +181,44 @@ class MovedCppStringSliceRefCount : public grpc_slice_refcount {
grpc_slice grpc_slice_new_with_len(void* p, size_t len,
void (*destroy)(void*, size_t)) {
grpc_slice slice;
slice.refcount = new grpc_core::NewWithLenSliceRefcount(destroy, p, len);
slice.refcount = (new grpc_core::NewWithLenSliceRefcount(destroy, p, len))
->base_refcount();
slice.data.refcounted.bytes = static_cast<uint8_t*>(p);
slice.data.refcounted.length = len;
return slice;
}
grpc_slice grpc_slice_from_copied_buffer(const char* source, size_t len) {
if (len == 0) return grpc_empty_slice();
grpc_slice out = grpc_slice_malloc(len);
memcpy(GRPC_SLICE_START_PTR(out), source, len);
return out;
grpc_core::UnmanagedMemorySlice::UnmanagedMemorySlice(const char* source,
size_t length) {
if (length <= sizeof(data.inlined.bytes)) {
refcount = nullptr;
data.inlined.length = static_cast<uint8_t>(length);
} else {
HeapInit(length);
}
if (length > 0) {
memcpy(GRPC_SLICE_START_PTR(*this), source, length);
}
}
grpc_core::UnmanagedMemorySlice::UnmanagedMemorySlice(const char* source)
: grpc_core::UnmanagedMemorySlice::UnmanagedMemorySlice(source,
strlen(source)) {}
grpc_slice grpc_slice_from_copied_buffer(const char* source, size_t length) {
grpc_slice slice;
if (length <= sizeof(slice.data.inlined.bytes)) {
slice.refcount = nullptr;
slice.data.inlined.length = length;
} else {
// Create a ref-counted slice.
slice = grpc_core::UnmanagedMemorySlice(
length, grpc_core::UnmanagedMemorySlice::ForceHeapAllocation());
}
if (length > 0) {
memcpy(GRPC_SLICE_START_PTR(slice), source, length);
}
return slice;
}
grpc_slice grpc_slice_from_copied_string(const char* source) {
@ -186,7 +234,8 @@ grpc_slice grpc_slice_from_moved_buffer(grpc_core::UniquePtr<char> p,
slice.data.inlined.length = len;
memcpy(GRPC_SLICE_START_PTR(slice), ptr, len);
} else {
slice.refcount = new grpc_core::MovedStringSliceRefCount(std::move(p));
slice.refcount = (new grpc_core::MovedStringSliceRefCount(std::move(p)))
->base_refcount();
slice.data.refcounted.bytes = ptr;
slice.data.refcounted.length = len;
}
@ -208,44 +257,94 @@ grpc_slice grpc_slice_from_cpp_string(std::string str) {
slice.data.refcounted.bytes =
reinterpret_cast<uint8_t*>(const_cast<char*>(str.data()));
slice.data.refcounted.length = str.size();
slice.refcount = new grpc_core::MovedCppStringSliceRefCount(std::move(str));
slice.refcount =
(new grpc_core::MovedCppStringSliceRefCount(std::move(str)))
->base_refcount();
}
return slice;
}
namespace {
class MallocRefCount {
public:
static void Destroy(void* arg) {
MallocRefCount* r = static_cast<MallocRefCount*>(arg);
r->~MallocRefCount();
gpr_free(r);
}
MallocRefCount()
: base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
&base_) {}
~MallocRefCount() = default;
grpc_slice_refcount* base_refcount() { return &base_; }
private:
grpc_slice_refcount base_;
std::atomic<size_t> refs_{1};
};
} // namespace
grpc_slice grpc_slice_malloc_large(size_t length) {
grpc_slice slice;
uint8_t* memory = new uint8_t[sizeof(grpc_slice_refcount) + length];
slice.refcount = new (memory) grpc_slice_refcount(
[](grpc_slice_refcount* p) { delete[] reinterpret_cast<uint8_t*>(p); });
slice.data.refcounted.bytes = memory + sizeof(grpc_slice_refcount);
slice.data.refcounted.length = length;
return slice;
return grpc_core::UnmanagedMemorySlice(
length, grpc_core::UnmanagedMemorySlice::ForceHeapAllocation());
}
void grpc_core::UnmanagedMemorySlice::HeapInit(size_t length) {
/* Memory layout used by the slice created here:
+-----------+----------------------------------------------------------+
| refcount | bytes |
+-----------+----------------------------------------------------------+
refcount is a malloc_refcount
bytes is an array of bytes of the requested length
Both parts are placed in the same allocation returned from gpr_malloc */
auto* rc =
static_cast<MallocRefCount*>(gpr_malloc(sizeof(MallocRefCount) + length));
/* Initial refcount on rc is 1 - and it's up to the caller to release
this reference. */
new (rc) MallocRefCount();
/* Build up the slice to be returned. */
/* The slices refcount points back to the allocated block. */
refcount = rc->base_refcount();
/* The data bytes are placed immediately after the refcount struct */
data.refcounted.bytes = reinterpret_cast<uint8_t*>(rc + 1);
/* And the length of the block is set to the requested length */
data.refcounted.length = length;
}
grpc_slice grpc_slice_malloc(size_t length) {
if (length <= GRPC_SLICE_INLINED_SIZE) {
grpc_slice slice;
slice.refcount = nullptr;
slice.data.inlined.length = length;
return slice;
return grpc_core::UnmanagedMemorySlice(length);
}
grpc_core::UnmanagedMemorySlice::UnmanagedMemorySlice(size_t length) {
if (length > sizeof(data.inlined.bytes)) {
HeapInit(length);
} else {
return grpc_slice_malloc_large(length);
/* small slice: just inline the data */
refcount = nullptr;
data.inlined.length = static_cast<uint8_t>(length);
}
}
static grpc_slice sub_no_ref(const grpc_slice& source, size_t begin,
size_t end) {
grpc_slice subset;
template <typename Slice>
static Slice sub_no_ref(const Slice& source, size_t begin, size_t end) {
Slice subset;
GPR_ASSERT(end >= begin);
if (source.refcount != nullptr) {
if (source.refcount) {
/* Enforce preconditions */
GPR_ASSERT(source.data.refcounted.length >= end);
/* Build the result */
subset.refcount = source.refcount;
subset.refcount = source.refcount->sub_refcount();
/* Point into the source array */
subset.data.refcounted.bytes = source.data.refcounted.bytes + begin;
subset.data.refcounted.length = end - begin;
@ -264,6 +363,11 @@ grpc_slice grpc_slice_sub_no_ref(grpc_slice source, size_t begin, size_t end) {
return sub_no_ref(source, begin, end);
}
grpc_core::UnmanagedMemorySlice grpc_slice_sub_no_ref(
const grpc_core::UnmanagedMemorySlice& source, size_t begin, size_t end) {
return sub_no_ref(source, begin, end);
}
grpc_slice grpc_slice_sub(grpc_slice source, size_t begin, size_t end) {
grpc_slice subset;
@ -275,9 +379,7 @@ grpc_slice grpc_slice_sub(grpc_slice source, size_t begin, size_t end) {
} else {
subset = grpc_slice_sub_no_ref(source, begin, end);
/* Bump the refcount */
if (subset.refcount != grpc_slice_refcount::NoopRefcount()) {
subset.refcount->Ref();
}
subset.refcount->Ref();
}
return subset;
}
@ -295,12 +397,6 @@ grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice* source, size_t split,
memcpy(tail.data.inlined.bytes, source->data.inlined.bytes + split,
tail.data.inlined.length);
source->data.inlined.length = static_cast<uint8_t>(split);
} else if (source->refcount == grpc_slice_refcount::NoopRefcount()) {
/* refcount == NoopRefcount(), so we can just split in-place */
tail.refcount = grpc_slice_refcount::NoopRefcount();
tail.data.refcounted.bytes = source->data.refcounted.bytes + split;
tail.data.refcounted.length = source->data.refcounted.length - split;
source->data.refcounted.length = split;
} else {
size_t tail_length = source->data.refcounted.length - split;
GPR_ASSERT(source->data.refcounted.length >= split);
@ -311,22 +407,23 @@ grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice* source, size_t split,
tail.data.inlined.length = static_cast<uint8_t>(tail_length);
memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split,
tail_length);
source->refcount = source->refcount->sub_refcount();
} else {
/* Build the result */
switch (ref_whom) {
case GRPC_SLICE_REF_TAIL:
tail.refcount = source->refcount;
source->refcount = grpc_slice_refcount::NoopRefcount();
tail.refcount = source->refcount->sub_refcount();
source->refcount = &grpc_core::kNoopRefcount;
break;
case GRPC_SLICE_REF_HEAD:
tail.refcount = grpc_slice_refcount::NoopRefcount();
tail.refcount = &grpc_core::kNoopRefcount;
source->refcount = source->refcount->sub_refcount();
break;
case GRPC_SLICE_REF_BOTH:
tail.refcount = source->refcount;
tail.refcount = source->refcount->sub_refcount();
source->refcount = source->refcount->sub_refcount();
/* Bump the refcount */
if (tail.refcount != grpc_slice_refcount::NoopRefcount()) {
tail.refcount->Ref();
}
tail.refcount->Ref();
break;
}
/* Point into the source array */
@ -362,20 +459,20 @@ grpc_slice grpc_slice_split_head(grpc_slice* source, size_t split) {
head.refcount = nullptr;
head.data.inlined.length = static_cast<uint8_t>(split);
memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split);
source->refcount = source->refcount->sub_refcount();
source->data.refcounted.bytes += split;
source->data.refcounted.length -= split;
} else {
GPR_ASSERT(source->data.refcounted.length >= split);
/* Build the result */
head.refcount = source->refcount;
head.refcount = source->refcount->sub_refcount();
/* Bump the refcount */
if (head.refcount != grpc_slice_refcount::NoopRefcount()) {
head.refcount->Ref();
}
head.refcount->Ref();
/* Point into the source array */
head.data.refcounted.bytes = source->data.refcounted.bytes;
head.data.refcounted.length = split;
source->refcount = source->refcount->sub_refcount();
source->data.refcounted.bytes += split;
source->data.refcounted.length -= split;
}
@ -383,13 +480,21 @@ grpc_slice grpc_slice_split_head(grpc_slice* source, size_t split) {
return head;
}
int grpc_slice_eq(grpc_slice a, grpc_slice b) {
int grpc_slice_default_eq_impl(grpc_slice a, grpc_slice b) {
if (GRPC_SLICE_LENGTH(a) != GRPC_SLICE_LENGTH(b)) return false;
if (GRPC_SLICE_LENGTH(a) == 0) return true;
return 0 == memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
GRPC_SLICE_LENGTH(a));
}
int grpc_slice_eq(grpc_slice a, grpc_slice b) {
if (a.refcount && b.refcount &&
a.refcount->GetType() == b.refcount->GetType()) {
return a.refcount->Eq(a, b);
}
return grpc_slice_default_eq_impl(a, b);
}
int grpc_slice_differs_refcounted(const grpc_slice& a,
const grpc_slice& b_not_inline) {
size_t a_len;

@ -25,8 +25,6 @@
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_refcount.h"
#include "src/core/lib/slice/slice_refcount_base.h"
// Herein lies grpc_core::Slice and its team of thin wrappers around grpc_slice.
// They aim to keep you safe by providing strong guarantees around lifetime and
@ -105,8 +103,6 @@ class BaseSlice {
return grpc_slice_is_equivalent(slice_, other.slice_);
}
uint32_t Hash() const { return grpc_slice_hash_internal(slice_); }
protected:
BaseSlice() : slice_(EmptySlice()) {}
explicit BaseSlice(const grpc_slice& slice) : slice_(slice) {}
@ -166,7 +162,7 @@ inline bool operator!=(const grpc_slice& a, const BaseSlice& b) {
template <typename Out>
struct CopyConstructors {
static Out FromCopiedString(const char* s) {
return FromCopiedBuffer(s, strlen(s));
return Out(grpc_slice_from_copied_string(s));
}
static Out FromCopiedString(absl::string_view s) {
return FromCopiedBuffer(s.data(), s.size());
@ -175,7 +171,7 @@ struct CopyConstructors {
return Out(grpc_slice_from_cpp_string(std::move(s)));
}
static Out FromCopiedBuffer(const char* p, size_t len) {
return Out(grpc_slice_from_copied_buffer(p, len));
return Out(UnmanagedMemorySlice(p, len));
}
template <typename Buffer>
@ -194,20 +190,11 @@ struct CopyConstructors {
template <typename Out>
struct StaticConstructors {
static Out FromStaticString(const char* s) {
return FromStaticBuffer(s, strlen(s));
return Out(grpc_slice_from_static_string(s));
}
static Out FromStaticString(absl::string_view s) {
return FromStaticBuffer(s.data(), s.size());
}
static Out FromStaticBuffer(const void* s, size_t len) {
grpc_slice slice;
slice.refcount = grpc_slice_refcount::NoopRefcount();
slice.data.refcounted.bytes =
const_cast<uint8_t*>(static_cast<const uint8_t*>(s));
slice.data.refcounted.length = len;
return Out(slice);
return Out(ExternallyManagedSlice(s.data(), s.size()));
}
};
@ -219,8 +206,11 @@ class StaticSlice : public slice_detail::BaseSlice,
StaticSlice() = default;
explicit StaticSlice(const grpc_slice& slice)
: slice_detail::BaseSlice(slice) {
GPR_DEBUG_ASSERT(slice.refcount == grpc_slice_refcount::NoopRefcount());
GPR_DEBUG_ASSERT(slice.refcount->GetType() ==
grpc_slice_refcount::Type::NOP);
}
explicit StaticSlice(const StaticMetadataSlice& slice)
: slice_detail::BaseSlice(slice) {}
StaticSlice(const StaticSlice& other)
: slice_detail::BaseSlice(other.c_slice()) {}
@ -242,7 +232,8 @@ class MutableSlice : public slice_detail::BaseSlice,
MutableSlice() = default;
explicit MutableSlice(const grpc_slice& slice)
: slice_detail::BaseSlice(slice) {
GPR_DEBUG_ASSERT(slice.refcount == nullptr || slice.refcount->IsUnique());
GPR_DEBUG_ASSERT(slice.refcount == nullptr ||
slice.refcount->IsRegularUnique());
}
~MutableSlice() { grpc_slice_unref_internal(c_slice()); }
@ -306,7 +297,7 @@ class Slice : public slice_detail::BaseSlice,
if (c_slice().refcount == nullptr) {
return Slice(c_slice());
}
if (c_slice().refcount == grpc_slice_refcount::NoopRefcount()) {
if (c_slice().refcount->GetType() == grpc_slice_refcount::Type::NOP) {
return Slice(grpc_slice_copy(c_slice()));
}
return Slice(TakeCSlice());
@ -318,7 +309,7 @@ class Slice : public slice_detail::BaseSlice,
if (c_slice().refcount == nullptr) {
return Slice(c_slice());
}
if (c_slice().refcount == grpc_slice_refcount::NoopRefcount()) {
if (c_slice().refcount->GetType() == grpc_slice_refcount::Type::NOP) {
return Slice(grpc_slice_copy(c_slice()));
}
return Slice(grpc_slice_ref_internal(c_slice()));
@ -336,8 +327,8 @@ class Slice : public slice_detail::BaseSlice,
if (c_slice().refcount == nullptr) {
return MutableSlice(c_slice());
}
if (c_slice().refcount != grpc_slice_refcount::NoopRefcount() &&
c_slice().refcount->IsUnique()) {
if (c_slice().refcount->GetType() == grpc_slice_refcount::Type::REGULAR &&
c_slice().refcount->IsRegularUnique()) {
return MutableSlice(TakeCSlice());
}
return MutableSlice(grpc_slice_copy(c_slice()));
@ -368,15 +359,11 @@ class Slice : public slice_detail::BaseSlice,
const uint8_t* begin, const uint8_t* end) {
grpc_slice out;
out.refcount = r;
if (r != grpc_slice_refcount::NoopRefcount()) r->Ref();
r->Ref();
out.data.refcounted.bytes = const_cast<uint8_t*>(begin);
out.data.refcounted.length = end - begin;
return Slice(out);
}
static Slice FromExternalString(absl::string_view str) {
return FromStaticString(str);
}
};
} // namespace grpc_core

@ -0,0 +1,269 @@
/*
*
* Copyright 2016 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 <inttypes.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/gpr/murmur_hash.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/iomgr/iomgr_internal.h" /* for iomgr_abort_on_leaks() */
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/slice/slice_utils.h"
#define LOG2_SHARD_COUNT 5
#define SHARD_COUNT (1 << LOG2_SHARD_COUNT)
#define INITIAL_SHARD_CAPACITY 8
#define TABLE_IDX(hash, capacity) (((hash) >> LOG2_SHARD_COUNT) % (capacity))
#define SHARD_IDX(hash) ((hash) & ((1 << LOG2_SHARD_COUNT) - 1))
using grpc_core::InternedSliceRefcount;
typedef struct slice_shard {
grpc_core::Mutex mu;
InternedSliceRefcount** strs;
size_t count;
size_t capacity;
} slice_shard;
static slice_shard* g_shards;
namespace grpc_core {
/* hash seed: decided at initialization time */
uint32_t g_hash_seed;
static bool g_forced_hash_seed = false;
InternedSliceRefcount::~InternedSliceRefcount() {
slice_shard* shard = &g_shards[SHARD_IDX(this->hash)];
MutexLock lock(&shard->mu);
InternedSliceRefcount** prev_next;
InternedSliceRefcount* cur;
for (prev_next = &shard->strs[TABLE_IDX(this->hash, shard->capacity)],
cur = *prev_next;
cur != this; prev_next = &cur->bucket_next, cur = cur->bucket_next) {
}
*prev_next = cur->bucket_next;
shard->count--;
}
} // namespace grpc_core
static void grow_shard(slice_shard* shard) {
GPR_TIMER_SCOPE("grow_strtab", 0);
size_t capacity = shard->capacity * 2;
size_t i;
InternedSliceRefcount** strtab;
InternedSliceRefcount *s, *next;
strtab = static_cast<InternedSliceRefcount**>(
gpr_zalloc(sizeof(InternedSliceRefcount*) * capacity));
for (i = 0; i < shard->capacity; i++) {
for (s = shard->strs[i]; s; s = next) {
size_t idx = TABLE_IDX(s->hash, capacity);
next = s->bucket_next;
s->bucket_next = strtab[idx];
strtab[idx] = s;
}
}
gpr_free(shard->strs);
shard->strs = strtab;
shard->capacity = capacity;
}
grpc_core::InternedSlice::InternedSlice(InternedSliceRefcount* s) {
refcount = &s->base;
data.refcounted.bytes = reinterpret_cast<uint8_t*>(s + 1);
data.refcounted.length = s->length;
}
uint32_t grpc_slice_default_hash_impl(grpc_slice s) {
return gpr_murmur_hash3(GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s),
grpc_core::g_hash_seed);
}
uint32_t grpc_slice_hash(grpc_slice s) { return grpc_slice_hash_internal(s); }
grpc_slice grpc_slice_intern(grpc_slice slice) {
/* TODO(arjunroy): At present, this is capable of returning either a static or
an interned slice. This yields weirdness like the constructor for
ManagedMemorySlice instantiating itself as an instance of a derived type
(StaticMetadataSlice or InternedSlice). Should reexamine. */
return grpc_core::ManagedMemorySlice(&slice);
}
// Helper methods to enable us to select appropriately overloaded slice methods
// whether we're dealing with a slice, or a buffer with length, when interning
// strings. Helpers for FindOrCreateInternedSlice().
static const char* GetBuffer(const std::pair<const char*, size_t>& buflen) {
return buflen.first;
}
static size_t GetLength(const std::pair<const char*, size_t>& buflen) {
return buflen.second;
}
static const void* GetBuffer(const grpc_slice& slice) {
return GRPC_SLICE_START_PTR(slice);
}
static size_t GetLength(const grpc_slice& slice) {
return GRPC_SLICE_LENGTH(slice);
}
// Creates an interned slice for a string that does not currently exist in the
// intern table. SliceArgs is either a const grpc_slice& or a const
// pair<const char*, size_t>&. Hash is the pre-computed hash value. We must
// already hold the shard lock. Helper for FindOrCreateInternedSlice().
//
// Returns: a newly interned slice.
template <typename SliceArgs>
static InternedSliceRefcount* InternNewStringLocked(slice_shard* shard,
size_t shard_idx,
uint32_t hash,
const SliceArgs& args) {
/* string data goes after the internal_string header */
size_t len = GetLength(args);
const void* buffer = GetBuffer(args);
InternedSliceRefcount* s =
static_cast<InternedSliceRefcount*>(gpr_malloc(sizeof(*s) + len));
new (s) grpc_core::InternedSliceRefcount(len, hash, shard->strs[shard_idx]);
// TODO(arjunroy): Investigate why hpack tried to intern the nullptr string.
// https://github.com/grpc/grpc/pull/20110#issuecomment-526729282
if (len > 0) {
memcpy(reinterpret_cast<char*>(s + 1), buffer, len);
}
shard->strs[shard_idx] = s;
shard->count++;
if (shard->count > shard->capacity * 2) {
grow_shard(shard);
}
return s;
}
// Attempt to see if the provided slice or string matches an existing interned
// slice. SliceArgs... is either a const grpc_slice& or a string and length. In
// either case, hash is the pre-computed hash value. We must already hold the
// shard lock. Helper for FindOrCreateInternedSlice().
//
// Returns: a pre-existing matching static slice, or null.
template <typename SliceArgs>
static InternedSliceRefcount* MatchInternedSliceLocked(uint32_t hash,
size_t idx,
const SliceArgs& args) {
InternedSliceRefcount* s;
slice_shard* shard = &g_shards[SHARD_IDX(hash)];
/* search for an existing string */
for (s = shard->strs[idx]; s; s = s->bucket_next) {
if (s->hash == hash && grpc_core::InternedSlice(s) == args) {
if (grpc_core::IncrementIfNonzero(&s->refcnt)) {
return s;
}
}
}
return nullptr;
}
// Attempt to see if the provided slice or string matches an existing interned
// slice, and failing that, create an interned slice with its contents. Returns
// either the existing matching interned slice or the newly created one.
// SliceArgs is either a const grpc_slice& or const pair<const char*, size_t>&.
// In either case, hash is the pre-computed hash value. We do not hold the
// shard lock here, but do take it.
//
// Returns: an interned slice, either pre-existing/matched or newly created.
template <typename SliceArgs>
static InternedSliceRefcount* FindOrCreateInternedSlice(uint32_t hash,
const SliceArgs& args) {
slice_shard* shard = &g_shards[SHARD_IDX(hash)];
grpc_core::MutexLock lock(&shard->mu);
const size_t idx = TABLE_IDX(hash, shard->capacity);
InternedSliceRefcount* s = MatchInternedSliceLocked(hash, idx, args);
if (s == nullptr) {
s = InternNewStringLocked(shard, idx, hash, args);
}
return s;
}
grpc_core::ManagedMemorySlice::ManagedMemorySlice(const char* string)
: grpc_core::ManagedMemorySlice::ManagedMemorySlice(string,
strlen(string)) {}
grpc_core::ManagedMemorySlice::ManagedMemorySlice(const char* buf, size_t len) {
GPR_TIMER_SCOPE("grpc_slice_intern", 0);
const uint32_t hash = gpr_murmur_hash3(buf, len, g_hash_seed);
*this = grpc_core::InternedSlice(FindOrCreateInternedSlice(
hash, std::pair<const char*, size_t>(buf, len)));
}
grpc_core::ManagedMemorySlice::ManagedMemorySlice(const grpc_slice* slice_ptr) {
GPR_TIMER_SCOPE("grpc_slice_intern", 0);
const grpc_slice& slice = *slice_ptr;
const uint32_t hash = grpc_slice_hash_internal(slice);
*this = grpc_core::InternedSlice(FindOrCreateInternedSlice(hash, slice));
}
void grpc_test_only_set_slice_hash_seed(uint32_t seed) {
grpc_core::g_hash_seed = seed;
grpc_core::g_forced_hash_seed = true;
}
void grpc_slice_intern_init(void) {
if (!grpc_core::g_forced_hash_seed) {
grpc_core::g_hash_seed =
static_cast<uint32_t>(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
}
g_shards = new slice_shard[SHARD_COUNT];
for (size_t i = 0; i < SHARD_COUNT; i++) {
slice_shard* shard = &g_shards[i];
shard->count = 0;
shard->capacity = INITIAL_SHARD_CAPACITY;
shard->strs = static_cast<InternedSliceRefcount**>(
gpr_zalloc(sizeof(*shard->strs) * shard->capacity));
}
}
void grpc_slice_intern_shutdown(void) {
for (size_t i = 0; i < SHARD_COUNT; i++) {
slice_shard* shard = &g_shards[i];
/* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
if (shard->count != 0) {
gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata strings were leaked",
shard->count);
for (size_t j = 0; j < shard->capacity; j++) {
for (InternedSliceRefcount* s = shard->strs[j]; s; s = s->bucket_next) {
char* text = grpc_dump_slice(grpc_core::InternedSlice(s),
GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_DEBUG, "LEAKED: %s", text);
gpr_free(text);
}
}
if (grpc_iomgr_abort_on_leaks()) {
abort();
}
}
gpr_free(shard->strs);
}
delete[] g_shards;
}

@ -23,8 +23,6 @@
#include <string.h>
#include "absl/strings/string_view.h"
#include <grpc/slice.h>
#include <grpc/slice_buffer.h>
#include <grpc/support/log.h>
@ -33,6 +31,7 @@
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/slice/slice_refcount.h"
#include "src/core/lib/slice/slice_utils.h"
void grpc_slice_buffer_reset_and_unref_internal(grpc_slice_buffer* sb);
void grpc_slice_buffer_partial_unref_internal(grpc_slice_buffer* sb,
@ -53,6 +52,21 @@ void grpc_slice_buffer_remove_first(grpc_slice_buffer* sb);
void grpc_slice_buffer_sub_first(grpc_slice_buffer* sb, size_t begin,
size_t end);
/* Check if a slice is interned */
bool grpc_slice_is_interned(const grpc_slice& slice);
inline bool grpc_slice_is_interned(const grpc_slice& slice) {
return (slice.refcount &&
(slice.refcount->GetType() == grpc_slice_refcount::Type::INTERNED));
}
inline bool grpc_slice_static_interned_equal(const grpc_slice& a,
const grpc_slice& b) {
GPR_DEBUG_ASSERT(grpc_slice_is_interned(a) && grpc_slice_is_interned(b));
return a.refcount == b.refcount;
}
void grpc_slice_intern_init(void);
void grpc_slice_intern_shutdown(void);
void grpc_test_only_set_slice_hash_seed(uint32_t seed);
// if slice matches a static slice, returns the static slice
// otherwise returns the passed in slice (without reffing it)
@ -63,11 +77,21 @@ grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
uint32_t grpc_static_slice_hash(grpc_slice s);
int grpc_static_slice_eq(grpc_slice a, grpc_slice b);
inline uint32_t grpc_slice_hash_internal(const grpc_slice& s) {
inline uint32_t grpc_slice_hash_refcounted(const grpc_slice& s) {
GPR_DEBUG_ASSERT(s.refcount != nullptr);
return s.refcount->Hash(s);
}
inline uint32_t grpc_slice_default_hash_internal(const grpc_slice& s) {
return gpr_murmur_hash3(GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s),
grpc_core::g_hash_seed);
}
inline uint32_t grpc_slice_hash_internal(const grpc_slice& s) {
return s.refcount == nullptr ? grpc_slice_default_hash_internal(s)
: grpc_slice_hash_refcounted(s);
}
grpc_slice grpc_slice_from_moved_buffer(grpc_core::UniquePtr<char> p,
size_t len);
grpc_slice grpc_slice_from_moved_string(grpc_core::UniquePtr<char> p);
@ -78,6 +102,9 @@ grpc_slice grpc_slice_from_cpp_string(std::string str);
// 0. All other slices will return the size of the allocated chars.
size_t grpc_slice_memory_usage(grpc_slice s);
grpc_core::UnmanagedMemorySlice grpc_slice_sub_no_ref(
const grpc_core::UnmanagedMemorySlice& source, size_t begin, size_t end);
namespace grpc_core {
struct SliceHash {
@ -86,15 +113,6 @@ struct SliceHash {
}
};
extern uint32_t g_hash_seed;
// Converts grpc_slice to absl::string_view.
inline absl::string_view StringViewFromSlice(const grpc_slice& slice) {
return absl::string_view(
reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(slice)),
GRPC_SLICE_LENGTH(slice));
}
} // namespace grpc_core
inline bool operator==(const grpc_slice& s1, const grpc_slice& s2) {

@ -15,19 +15,3 @@
#include <grpc/support/port_platform.h>
#include "src/core/lib/slice/slice_refcount.h"
#include <random>
namespace grpc_core {
uint32_t g_hash_seed = []() {
std::random_device rd;
std::uniform_int_distribution<uint32_t> dist;
return dist(rd);
}();
} // namespace grpc_core
void grpc_test_only_set_slice_hash_seed(uint32_t seed) {
grpc_core::g_hash_seed = seed;
}

@ -27,18 +27,88 @@
namespace grpc_core {
extern uint32_t g_hash_seed;
extern grpc_slice_refcount kNoopRefcount;
// TODO(ctiller): when this is removed, remove the std::atomic* in
// grpc_slice_refcount and just put it there directly.
struct InternedSliceRefcount {
static void Destroy(void* arg) {
auto* rc = static_cast<InternedSliceRefcount*>(arg);
rc->~InternedSliceRefcount();
gpr_free(rc);
}
InternedSliceRefcount(size_t length, uint32_t hash,
InternedSliceRefcount* bucket_next)
: base(grpc_slice_refcount::Type::INTERNED, &refcnt, Destroy, this, &sub),
sub(grpc_slice_refcount::Type::REGULAR, &refcnt, Destroy, this, &sub),
length(length),
hash(hash),
bucket_next(bucket_next) {}
~InternedSliceRefcount();
grpc_slice_refcount base;
grpc_slice_refcount sub;
const size_t length;
std::atomic<size_t> refcnt{1};
const uint32_t hash;
InternedSliceRefcount* bucket_next;
};
} // namespace grpc_core
inline size_t grpc_refcounted_slice_length(const grpc_slice& slice) {
GPR_DEBUG_ASSERT(slice.refcount != nullptr);
return slice.data.refcounted.length;
}
inline const uint8_t* grpc_refcounted_slice_data(const grpc_slice& slice) {
GPR_DEBUG_ASSERT(slice.refcount != nullptr);
return slice.data.refcounted.bytes;
}
inline int grpc_slice_refcount::Eq(const grpc_slice& a, const grpc_slice& b) {
GPR_DEBUG_ASSERT(a.refcount != nullptr);
GPR_DEBUG_ASSERT(a.refcount == this);
switch (ref_type_) {
case Type::INTERNED:
return a.refcount == b.refcount;
case Type::NOP:
case Type::REGULAR:
break;
}
if (grpc_refcounted_slice_length(a) != GRPC_SLICE_LENGTH(b)) return false;
if (grpc_refcounted_slice_length(a) == 0) return true;
return 0 == memcmp(grpc_refcounted_slice_data(a), GRPC_SLICE_START_PTR(b),
grpc_refcounted_slice_length(a));
}
inline uint32_t grpc_slice_refcount::Hash(const grpc_slice& slice) {
GPR_DEBUG_ASSERT(slice.refcount != nullptr);
GPR_DEBUG_ASSERT(slice.refcount == this);
switch (ref_type_) {
case Type::INTERNED:
return reinterpret_cast<grpc_core::InternedSliceRefcount*>(slice.refcount)
->hash;
case Type::NOP:
case Type::REGULAR:
break;
}
return gpr_murmur_hash3(grpc_refcounted_slice_data(slice),
grpc_refcounted_slice_length(slice),
grpc_core::g_hash_seed);
}
inline const grpc_slice& grpc_slice_ref_internal(const grpc_slice& slice) {
if (reinterpret_cast<uintptr_t>(slice.refcount) > 1) {
if (slice.refcount) {
slice.refcount->Ref();
}
return slice;
}
inline void grpc_slice_unref_internal(const grpc_slice& slice) {
if (reinterpret_cast<uintptr_t>(slice.refcount) > 1) {
if (slice.refcount) {
slice.refcount->Unref();
}
}

@ -23,39 +23,143 @@
#include <grpc/support/log.h>
// grpc_slice_refcount : A reference count for grpc_slice.
//
// Non-inlined grpc_slice objects are refcounted. Historically this was
// implemented via grpc_slice_refcount, a C-style polymorphic class using a
// manually managed vtable of operations. Subclasses would define their own
// vtable; the 'virtual' methods (ref, unref, equals and hash) would simply call
// the function pointers in the vtable as necessary.
//
// Unfortunately, this leads to some inefficiencies in the generated code that
// can be improved upon. For example, equality checking for interned slices is a
// simple equality check on the refcount pointer. With the vtable approach, this
// would translate to roughly the following (high-level) instructions:
//
// grpc_slice_equals(slice1, slice2):
// load vtable->eq -> eq_func
// call eq_func(slice1, slice2)
//
// interned_slice_equals(slice1, slice2)
// load slice1.ref -> r1
// load slice2.ref -> r2
// cmp r1, r2 -> retval
// ret retval
//
// This leads to a function call for a function defined in another translation
// unit, which imposes memory barriers, which reduces the compiler's ability to
// optimize (in addition to the added overhead of call/ret). Additionally, it
// may be harder to reason about branch prediction when we're jumping to
// essentially arbitrarily provided function pointers.
//
// In addition, it is arguable that while virtualization was helpful for
// Equals()/Hash() methods, that it was fundamentally unnecessary for
// Ref()/Unref().
//
// Instead, grpc_slice_refcount provides the same functionality as the C-style
// virtual class, but in a de-virtualized manner - Eq(), Hash(), Ref() and
// Unref() are provided within this header file. Fastpaths for Eq()/Hash()
// (interned and static metadata slices), as well as the Ref() operation, can
// all be inlined without any memory barriers.
//
// It does this by:
// 1. Using grpc_core::RefCount<> (header-only) for Ref/Unref. Two special cases
// need support: No-op ref/unref (eg. static metadata slices) and stream
// slice references (where all the slices share the streamref). This is in
// addition to the normal case of '1 slice, 1 ref'.
// To support these cases, we explicitly track a nullable pointer to the
// underlying RefCount<>. No-op ref/unref is used by checking the pointer for
// null, and doing nothing if it is. Both stream slice refs and 'normal'
// slices use the same path for Ref/Unref (by targeting the non-null
// pointer).
//
// 2. introducing the notion of grpc_slice_refcount::Type. This describes if a
// slice ref is used by a static metadata slice, an interned slice, or other
// slices. We switch on the slice ref type in order to provide fastpaths for
// Equals() and Hash().
//
// In total, this saves us roughly 1-2% latency for unary calls, with smaller
// calls benefitting. The effect is present, but not as useful, for larger calls
// where the cost of sending the data dominates.
// TODO(arjunroy): Investigate if this can be removed with strongly typed
// grpc_slices.
struct grpc_slice_refcount {
public:
typedef void (*DestroyerFn)(grpc_slice_refcount*);
static grpc_slice_refcount* NoopRefcount() {
return reinterpret_cast<grpc_slice_refcount*>(1);
}
enum class Type {
INTERNED, // Refcount for an interned slice.
NOP, // No-Op
REGULAR // Refcount for non-static-metadata, non-interned slices.
};
typedef void (*DestroyerFn)(void*);
grpc_slice_refcount() = default;
explicit grpc_slice_refcount(Type t) : ref_type_(t) {}
explicit grpc_slice_refcount(grpc_slice_refcount* sub) : sub_refcount_(sub) {}
// Regular constructor for grpc_slice_refcount.
//
// Parameters:
// 1. DestroyerFn destroyer_fn
// Called when the refcount goes to 0, with 'this' as parameter.
explicit grpc_slice_refcount(DestroyerFn destroyer_fn)
: destroyer_fn_(destroyer_fn) {}
// 1. grpc_slice_refcount::Type type
// Whether we are the refcount for a static
// metadata slice, an interned slice, or any other kind of slice.
//
// 2. std::atomic<size_t>* ref
// The pointer to the actual underlying grpc_core::RefCount.
// TODO(ctiller): remove the pointer indirection and just put the refcount on
// this object once we remove interning.
//
// 3. DestroyerFn destroyer_fn
// Called when the refcount goes to 0, with destroyer_arg as parameter.
//
// 4. void* destroyer_arg
// Argument for the virtualized destructor.
//
// 5. grpc_slice_refcount* sub
// Argument used for interned slices.
grpc_slice_refcount(grpc_slice_refcount::Type type, std::atomic<size_t>* ref,
DestroyerFn destroyer_fn, void* destroyer_arg,
grpc_slice_refcount* sub)
: ref_(ref),
ref_type_(type),
sub_refcount_(sub),
dest_fn_(destroyer_fn),
destroy_fn_arg_(destroyer_arg) {}
// Initializer for static refcounts.
grpc_slice_refcount(grpc_slice_refcount* sub, Type type)
: ref_type_(type), sub_refcount_(sub) {}
void Ref() { ref_.fetch_add(1, std::memory_order_relaxed); }
Type GetType() const { return ref_type_; }
int Eq(const grpc_slice& a, const grpc_slice& b);
uint32_t Hash(const grpc_slice& slice);
void Ref() {
if (ref_ == nullptr) return;
ref_->fetch_add(1, std::memory_order_relaxed);
}
void Unref() {
if (ref_.fetch_sub(1, std::memory_order_acq_rel) == 1) {
destroyer_fn_(this);
if (ref_ == nullptr) return;
if (ref_->fetch_sub(1, std::memory_order_acq_rel) == 1) {
dest_fn_(destroy_fn_arg_);
}
}
// Is this the only instance?
// Only for type REGULAR, is this the only instance?
// For this to be useful the caller needs to ensure that if this is the only
// instance, no other instance could be created during this call.
bool IsUnique() const { return ref_.load(std::memory_order_relaxed) == 1; }
bool IsRegularUnique() {
GPR_DEBUG_ASSERT(ref_type_ == Type::REGULAR);
return ref_->load(std::memory_order_relaxed) == 1;
}
grpc_slice_refcount* sub_refcount() const { return sub_refcount_; }
private:
std::atomic<size_t> ref_{1};
DestroyerFn destroyer_fn_ = nullptr;
std::atomic<size_t>* ref_ = nullptr;
const Type ref_type_ = Type::REGULAR;
grpc_slice_refcount* sub_refcount_ = this;
DestroyerFn dest_fn_ = nullptr;
void* destroy_fn_arg_ = nullptr;
};
#endif // GRPC_CORE_LIB_SLICE_SLICE_REFCOUNT_BASE_H

@ -0,0 +1,200 @@
/*
*
* Copyright 2019 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_UTILS_H
#define GRPC_CORE_LIB_SLICE_SLICE_UTILS_H
#include <grpc/support/port_platform.h>
#include <cstring>
#include "absl/strings/string_view.h"
#include <grpc/slice.h>
#include "src/core/lib/gpr/murmur_hash.h"
namespace grpc_core {
extern uint32_t g_hash_seed;
} // namespace grpc_core
// When we compare two slices, and we know the latter is not inlined, we can
// short circuit our comparison operator. We specifically use differs()
// semantics instead of equals() semantics due to more favourable code
// generation when using differs(). Specifically, we may use the output of
// grpc_slice_differs_refcounted for control flow. If we use differs()
// semantics, we end with a tailcall to memcmp(). If we use equals() semantics,
// we need to invert the result that memcmp provides us, which costs several
// instructions to do so. If we're using the result for control flow (i.e.
// branching based on the output) then we're just performing the extra
// operations to invert the result pointlessly. Concretely, we save 6 ops on
// x86-64/clang with differs().
int grpc_slice_differs_refcounted(const grpc_slice& a,
const grpc_slice& b_not_inline);
// When we compare two slices, and we *know* that one of them is static or
// interned, we can short circuit our slice equality function. The second slice
// here must be static or interned; slice a can be any slice, inlined or not.
inline bool grpc_slice_eq_static_interned(const grpc_slice& a,
const grpc_slice& b_static_interned) {
if (a.refcount == b_static_interned.refcount) {
return true;
}
return !grpc_slice_differs_refcounted(a, b_static_interned);
}
// TODO(arjunroy): These type declarations ought to be in
// src/core/lib/slice/slice_internal.h instead; they are here due to a circular
// header depedency between slice_internal.h and
// src/core/lib/transport/metadata.h. We need to fix this circular reference and
// when we do, move these type declarations.
//
// Internal slice type declarations.
// Externally, a grpc_slice is a grpc_slice is a grpc_slice.
// Internally, we may have heap allocated slices, static slices, interned
// slices, and inlined slices. If we know the specific type of slice
// we're dealing with, we can save cycles (e.g. fast-paths when we know we don't
// need to take a reference on a slice). Rather than introducing new methods
// ad-hoc in these cases, we rely on type-system backed overloads to keep
// internal APIs clean.
//
// For each overload, the definition and layout of the underlying slice does not
// change; this is purely type-system information.
namespace grpc_core {
// There are two main types of slices: those that have their memory
// managed by the slice library and those that do not.
//
// The following types of slices are not managed:
// - inlined slices (i.e., refcount is null)
// - slices that have a custom refcount type (i.e., not STATIC or INTERNED)
// - slices where the memory is managed by some external agent. The slice is not
// ref-counted by grpc, and the programmer is responsible for ensuring the
// data is valid for the duration of the period that grpc may access it.
//
// The following types of slices are managed:
// - static metadata slices (i.e., refcount type is STATIC)
// - interned slices (i.e., refcount type is INTERNED)
//
// This categorization is reflected in the following hierarchy:
//
// - grpc_slice
// > - UnmanagedMemorySlice
// > - ExternallyManagedSlice
// - ManagedMemorySlice
// > - InternedSlice
// - StaticMetadataSlice
//
struct ManagedMemorySlice : public grpc_slice {
ManagedMemorySlice() {
refcount = nullptr;
data.refcounted.bytes = nullptr;
data.refcounted.length = 0;
}
explicit ManagedMemorySlice(const char* string);
ManagedMemorySlice(const char* buf, size_t len);
explicit ManagedMemorySlice(const grpc_slice* slice);
bool operator==(const grpc_slice& other) const {
if (refcount == other.refcount) {
return true;
}
return !grpc_slice_differs_refcounted(other, *this);
}
bool operator!=(const grpc_slice& other) const { return !(*this == other); }
bool operator==(std::pair<const char*, size_t> buflen) const {
return data.refcounted.length == buflen.second && buflen.first != nullptr &&
memcmp(buflen.first, data.refcounted.bytes, buflen.second) == 0;
}
};
struct UnmanagedMemorySlice : public grpc_slice {
// TODO(arjunroy): Can we use a default=false param instead of this enum?
enum class ForceHeapAllocation {};
UnmanagedMemorySlice() {
refcount = nullptr;
data.inlined.length = 0;
}
explicit UnmanagedMemorySlice(const char* source);
UnmanagedMemorySlice(const char* source, size_t length);
// The first constructor creates a slice that may be heap allocated, or
// inlined in the slice structure if length is small enough
// (< GRPC_SLICE_INLINED_SIZE). The second constructor forces heap alloc.
explicit UnmanagedMemorySlice(size_t length);
explicit UnmanagedMemorySlice(size_t length, const ForceHeapAllocation&) {
HeapInit(length);
}
private:
void HeapInit(size_t length);
};
extern grpc_slice_refcount kNoopRefcount;
struct ExternallyManagedSlice : public UnmanagedMemorySlice {
ExternallyManagedSlice()
: ExternallyManagedSlice(&kNoopRefcount, 0, nullptr) {}
explicit ExternallyManagedSlice(const char* s)
: ExternallyManagedSlice(s, strlen(s)) {}
ExternallyManagedSlice(const void* s, size_t len)
: ExternallyManagedSlice(
&kNoopRefcount, len,
reinterpret_cast<uint8_t*>(const_cast<void*>(s))) {}
ExternallyManagedSlice(grpc_slice_refcount* ref, size_t length,
uint8_t* bytes) {
refcount = ref;
data.refcounted.length = length;
data.refcounted.bytes = bytes;
}
bool operator==(const grpc_slice& other) const {
return data.refcounted.length == GRPC_SLICE_LENGTH(other) &&
memcmp(data.refcounted.bytes, GRPC_SLICE_START_PTR(other),
data.refcounted.length) == 0;
}
bool operator!=(const grpc_slice& other) const { return !(*this == other); }
uint32_t Hash() {
return gpr_murmur_hash3(data.refcounted.bytes, data.refcounted.length,
g_hash_seed);
}
};
struct StaticMetadataSlice : public ManagedMemorySlice {
StaticMetadataSlice(grpc_slice_refcount* ref, size_t length,
const uint8_t* bytes) {
refcount = ref;
data.refcounted.length = length;
// NB: grpc_slice may or may not point to a static slice, but we are
// definitely pointing to static data here. Since we are not changing
// the underlying C-type, we need a const_cast here.
data.refcounted.bytes = const_cast<uint8_t*>(bytes);
}
};
struct InternedSliceRefcount;
struct InternedSlice : public ManagedMemorySlice {
explicit InternedSlice(InternedSliceRefcount* s);
};
// Converts grpc_slice to absl::string_view.
inline absl::string_view StringViewFromSlice(const grpc_slice& slice) {
return absl::string_view(
reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(slice)),
GRPC_SLICE_LENGTH(slice));
}
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_SLICE_SLICE_UTILS_H */

@ -50,9 +50,9 @@
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_split.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/slice/slice_utils.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call_test_only.h"
#include "src/core/lib/surface/channel.h"

@ -104,6 +104,7 @@ void grpc_init(void) {
grpc_core::Fork::GlobalInit();
grpc_fork_handlers_auto_register();
grpc_stats_init();
grpc_slice_intern_init();
grpc_core::channelz::ChannelzRegistry::Init();
grpc_security_pre_init();
grpc_core::ApplicationCallbackExecCtx::GlobalInit();
@ -139,6 +140,7 @@ void grpc_shutdown_internal_locked(void)
grpc_iomgr_shutdown();
gpr_timers_global_destroy();
grpc_tracer_shutdown();
grpc_slice_intern_shutdown();
grpc_core::channelz::ChannelzRegistry::Shutdown();
grpc_stats_shutdown();
grpc_core::Fork::GlobalShutdown();

@ -982,7 +982,19 @@ class Server::ChannelData::ConnectivityWatcher
//
Server::ChannelData::~ChannelData() {
registered_methods_.reset();
if (registered_methods_ != nullptr) {
for (const ChannelRegisteredMethod& crm : *registered_methods_) {
grpc_slice_unref_internal(crm.method);
GPR_DEBUG_ASSERT(crm.method.refcount == &kNoopRefcount ||
crm.method.refcount == nullptr);
if (crm.has_host) {
grpc_slice_unref_internal(crm.host);
GPR_DEBUG_ASSERT(crm.host.refcount == &kNoopRefcount ||
crm.host.refcount == nullptr);
}
}
registered_methods_.reset();
}
if (server_ != nullptr) {
if (server_->channelz_node_ != nullptr && channelz_socket_uuid_ != 0) {
server_->channelz_node_->RemoveChildSocket(channelz_socket_uuid_);
@ -1015,11 +1027,11 @@ void Server::ChannelData::InitTransport(RefCountedPtr<Server> server,
registered_methods_ =
absl::make_unique<std::vector<ChannelRegisteredMethod>>(slots);
for (std::unique_ptr<RegisteredMethod>& rm : server_->registered_methods_) {
Slice host;
Slice method = Slice::FromExternalString(rm->method);
ExternallyManagedSlice host;
ExternallyManagedSlice method(rm->method.c_str());
const bool has_host = !rm->host.empty();
if (has_host) {
host = Slice::FromExternalString(rm->host.c_str());
host = ExternallyManagedSlice(rm->host.c_str());
}
uint32_t hash = MixHash32(has_host ? host.Hash() : 0, method.Hash());
uint32_t probes = 0;
@ -1034,9 +1046,9 @@ void Server::ChannelData::InitTransport(RefCountedPtr<Server> server,
crm->flags = rm->flags;
crm->has_host = has_host;
if (has_host) {
crm->host = std::move(host);
crm->host = host;
}
crm->method = std::move(method);
crm->method = method;
}
GPR_ASSERT(slots <= UINT32_MAX);
registered_method_max_probes_ = max_probes;

@ -176,8 +176,8 @@ class Server : public InternallyRefCounted<Server>,
RegisteredMethod* server_registered_method = nullptr;
uint32_t flags;
bool has_host;
Slice method;
Slice host;
ExternallyManagedSlice method;
ExternallyManagedSlice host;
};
class RequestMatcherInterface;

@ -100,9 +100,9 @@ void OpenCensusCallTracer::OpenCensusCallAttemptTracer::
size_t tracing_len = TraceContextSerialize(context_.Context(), tracing_buf,
kMaxTraceContextLen);
if (tracing_len > 0) {
send_initial_metadata->Set(
grpc_core::GrpcTraceBinMetadata(),
grpc_core::Slice::FromCopiedBuffer(tracing_buf, tracing_len));
send_initial_metadata->Set(grpc_core::GrpcTraceBinMetadata(),
grpc_core::Slice(grpc_core::UnmanagedMemorySlice(
tracing_buf, tracing_len)));
}
grpc_slice tags = grpc_empty_slice();
// TODO(unknown): Add in tagging serialization.

@ -128,7 +128,7 @@ void CensusServerCallData::StartTransportStreamOpBatch(
if (len > 0) {
op->send_trailing_metadata()->batch()->Set(
grpc_core::GrpcServerStatsBinMetadata(),
grpc_core::Slice::FromCopiedBuffer(stats_buf_, len));
grpc_core::Slice(grpc_core::UnmanagedMemorySlice(stats_buf_, len)));
}
}
// Call next op.

@ -603,6 +603,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_intern.cc',
'src/core/lib/slice/slice_refcount.cc',
'src/core/lib/slice/slice_split.cc',
'src/core/lib/slice/slice_string_helpers.cc',

@ -213,6 +213,7 @@ grpc_slice_new_with_user_data_type grpc_slice_new_with_user_data_import;
grpc_slice_new_with_len_type grpc_slice_new_with_len_import;
grpc_slice_malloc_type grpc_slice_malloc_import;
grpc_slice_malloc_large_type grpc_slice_malloc_large_import;
grpc_slice_intern_type grpc_slice_intern_import;
grpc_slice_from_copied_string_type grpc_slice_from_copied_string_import;
grpc_slice_from_copied_buffer_type grpc_slice_from_copied_buffer_import;
grpc_slice_from_static_string_type grpc_slice_from_static_string_import;
@ -223,6 +224,8 @@ grpc_slice_split_tail_type grpc_slice_split_tail_import;
grpc_slice_split_tail_maybe_ref_type grpc_slice_split_tail_maybe_ref_import;
grpc_slice_split_head_type grpc_slice_split_head_import;
grpc_empty_slice_type grpc_empty_slice_import;
grpc_slice_default_hash_impl_type grpc_slice_default_hash_impl_import;
grpc_slice_default_eq_impl_type grpc_slice_default_eq_impl_import;
grpc_slice_eq_type grpc_slice_eq_import;
grpc_slice_cmp_type grpc_slice_cmp_import;
grpc_slice_str_cmp_type grpc_slice_str_cmp_import;
@ -230,6 +233,7 @@ grpc_slice_buf_start_eq_type grpc_slice_buf_start_eq_import;
grpc_slice_rchr_type grpc_slice_rchr_import;
grpc_slice_chr_type grpc_slice_chr_import;
grpc_slice_slice_type grpc_slice_slice_import;
grpc_slice_hash_type grpc_slice_hash_import;
grpc_slice_is_equivalent_type grpc_slice_is_equivalent_import;
grpc_slice_dup_type grpc_slice_dup_import;
grpc_slice_to_c_string_type grpc_slice_to_c_string_import;
@ -499,6 +503,7 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_slice_new_with_len_import = (grpc_slice_new_with_len_type) GetProcAddress(library, "grpc_slice_new_with_len");
grpc_slice_malloc_import = (grpc_slice_malloc_type) GetProcAddress(library, "grpc_slice_malloc");
grpc_slice_malloc_large_import = (grpc_slice_malloc_large_type) GetProcAddress(library, "grpc_slice_malloc_large");
grpc_slice_intern_import = (grpc_slice_intern_type) GetProcAddress(library, "grpc_slice_intern");
grpc_slice_from_copied_string_import = (grpc_slice_from_copied_string_type) GetProcAddress(library, "grpc_slice_from_copied_string");
grpc_slice_from_copied_buffer_import = (grpc_slice_from_copied_buffer_type) GetProcAddress(library, "grpc_slice_from_copied_buffer");
grpc_slice_from_static_string_import = (grpc_slice_from_static_string_type) GetProcAddress(library, "grpc_slice_from_static_string");
@ -509,6 +514,8 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_slice_split_tail_maybe_ref_import = (grpc_slice_split_tail_maybe_ref_type) GetProcAddress(library, "grpc_slice_split_tail_maybe_ref");
grpc_slice_split_head_import = (grpc_slice_split_head_type) GetProcAddress(library, "grpc_slice_split_head");
grpc_empty_slice_import = (grpc_empty_slice_type) GetProcAddress(library, "grpc_empty_slice");
grpc_slice_default_hash_impl_import = (grpc_slice_default_hash_impl_type) GetProcAddress(library, "grpc_slice_default_hash_impl");
grpc_slice_default_eq_impl_import = (grpc_slice_default_eq_impl_type) GetProcAddress(library, "grpc_slice_default_eq_impl");
grpc_slice_eq_import = (grpc_slice_eq_type) GetProcAddress(library, "grpc_slice_eq");
grpc_slice_cmp_import = (grpc_slice_cmp_type) GetProcAddress(library, "grpc_slice_cmp");
grpc_slice_str_cmp_import = (grpc_slice_str_cmp_type) GetProcAddress(library, "grpc_slice_str_cmp");
@ -516,6 +523,7 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_slice_rchr_import = (grpc_slice_rchr_type) GetProcAddress(library, "grpc_slice_rchr");
grpc_slice_chr_import = (grpc_slice_chr_type) GetProcAddress(library, "grpc_slice_chr");
grpc_slice_slice_import = (grpc_slice_slice_type) GetProcAddress(library, "grpc_slice_slice");
grpc_slice_hash_import = (grpc_slice_hash_type) GetProcAddress(library, "grpc_slice_hash");
grpc_slice_is_equivalent_import = (grpc_slice_is_equivalent_type) GetProcAddress(library, "grpc_slice_is_equivalent");
grpc_slice_dup_import = (grpc_slice_dup_type) GetProcAddress(library, "grpc_slice_dup");
grpc_slice_to_c_string_import = (grpc_slice_to_c_string_type) GetProcAddress(library, "grpc_slice_to_c_string");

@ -614,6 +614,9 @@ extern grpc_slice_malloc_type grpc_slice_malloc_import;
typedef grpc_slice(*grpc_slice_malloc_large_type)(size_t length);
extern grpc_slice_malloc_large_type grpc_slice_malloc_large_import;
#define grpc_slice_malloc_large grpc_slice_malloc_large_import
typedef grpc_slice(*grpc_slice_intern_type)(grpc_slice slice);
extern grpc_slice_intern_type grpc_slice_intern_import;
#define grpc_slice_intern grpc_slice_intern_import
typedef grpc_slice(*grpc_slice_from_copied_string_type)(const char* source);
extern grpc_slice_from_copied_string_type grpc_slice_from_copied_string_import;
#define grpc_slice_from_copied_string grpc_slice_from_copied_string_import
@ -644,6 +647,12 @@ extern grpc_slice_split_head_type grpc_slice_split_head_import;
typedef grpc_slice(*grpc_empty_slice_type)(void);
extern grpc_empty_slice_type grpc_empty_slice_import;
#define grpc_empty_slice grpc_empty_slice_import
typedef uint32_t(*grpc_slice_default_hash_impl_type)(grpc_slice s);
extern grpc_slice_default_hash_impl_type grpc_slice_default_hash_impl_import;
#define grpc_slice_default_hash_impl grpc_slice_default_hash_impl_import
typedef int(*grpc_slice_default_eq_impl_type)(grpc_slice a, grpc_slice b);
extern grpc_slice_default_eq_impl_type grpc_slice_default_eq_impl_import;
#define grpc_slice_default_eq_impl grpc_slice_default_eq_impl_import
typedef int(*grpc_slice_eq_type)(grpc_slice a, grpc_slice b);
extern grpc_slice_eq_type grpc_slice_eq_import;
#define grpc_slice_eq grpc_slice_eq_import
@ -665,6 +674,9 @@ extern grpc_slice_chr_type grpc_slice_chr_import;
typedef int(*grpc_slice_slice_type)(grpc_slice haystack, grpc_slice needle);
extern grpc_slice_slice_type grpc_slice_slice_import;
#define grpc_slice_slice grpc_slice_slice_import
typedef uint32_t(*grpc_slice_hash_type)(grpc_slice s);
extern grpc_slice_hash_type grpc_slice_hash_import;
#define grpc_slice_hash grpc_slice_hash_import
typedef int(*grpc_slice_is_equivalent_type)(grpc_slice a, grpc_slice b);
extern grpc_slice_is_equivalent_type grpc_slice_is_equivalent_import;
#define grpc_slice_is_equivalent grpc_slice_is_equivalent_import

@ -381,6 +381,11 @@ class Call : public std::enable_shared_from_this<Call> {
template <typename T>
grpc_slice ReadSlice(const T& s) {
grpc_slice slice = grpc_slice_from_cpp_string(s.value());
if (s.intern()) {
auto interned_slice = grpc_slice_intern(slice);
grpc_slice_unref(slice);
slice = interned_slice;
}
unref_slices_.push_back(slice);
return slice;
}

@ -19,15 +19,13 @@ package api_fuzzer;
message Empty {}
message ByteSlice {
reserved 2;
reserved "intern";
bytes value = 1;
bool intern = 2;
}
message StringSlice {
reserved 2;
reserved "intern";
string value = 1;
bool intern = 2;
}
message ResourceQuota {}

@ -95,6 +95,18 @@ grpc_cc_test(
],
)
grpc_cc_test(
name = "slice_intern_test",
srcs = ["slice_intern_test.cc"],
language = "C++",
uses_polling = False,
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "slice_string_helpers_test",
srcs = ["slice_string_helpers_test.cc"],

@ -0,0 +1,67 @@
/*
*
* 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 <inttypes.h>
#include <string.h>
#include <grpc/grpc.h>
#include <grpc/slice.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/slice/slice_internal.h"
#include "test/core/util/test_config.h"
#define LOG_TEST_NAME(x) gpr_log(GPR_INFO, "%s", x);
static void test_slice_interning(void) {
LOG_TEST_NAME("test_slice_interning");
grpc_init();
grpc_slice src1 = grpc_slice_from_copied_string("hello123456789123456789");
grpc_slice src2 = grpc_slice_from_copied_string("hello123456789123456789");
// Explicitly checking that the slices are at different addresses prevents
// failure with windows opt 64bit build.
// See https://github.com/grpc/grpc/issues/20519
GPR_ASSERT(&src1 != &src2);
GPR_ASSERT(GRPC_SLICE_START_PTR(src1) != GRPC_SLICE_START_PTR(src2));
grpc_slice interned1 = grpc_slice_intern(src1);
grpc_slice interned2 = grpc_slice_intern(src2);
GPR_ASSERT(GRPC_SLICE_START_PTR(interned1) ==
GRPC_SLICE_START_PTR(interned2));
GPR_ASSERT(GRPC_SLICE_START_PTR(interned1) != GRPC_SLICE_START_PTR(src1));
GPR_ASSERT(GRPC_SLICE_START_PTR(interned2) != GRPC_SLICE_START_PTR(src2));
grpc_slice_unref(src1);
grpc_slice_unref(src2);
grpc_slice_unref(interned1);
grpc_slice_unref(interned2);
grpc_shutdown();
}
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_slice_interning();
grpc_shutdown();
return 0;
}

@ -358,7 +358,8 @@ size_t SumSlice(const Slice& slice) {
TEST(SliceTest, ExternalAsOwned) {
auto external_string = absl::make_unique<std::string>(RandomString(1024));
Slice slice = Slice::FromExternalString(*external_string);
Slice slice(ExternallyManagedSlice(external_string->data(),
external_string->length()));
const auto initial_sum = SumSlice(slice);
Slice owned = slice.AsOwned();
EXPECT_EQ(initial_sum, SumSlice(owned));
@ -374,7 +375,9 @@ TEST(SliceTest, ExternalAsOwned) {
TEST(SliceTest, ExternalTakeOwned) {
std::unique_ptr<std::string> external_string(
new std::string(RandomString(1024)));
SumSlice(Slice::FromExternalString(*external_string).TakeOwned());
SumSlice(Slice(ExternallyManagedSlice(external_string->data(),
external_string->length()))
.TakeOwned());
}
TEST(SliceTest, StaticSlice) {

@ -257,6 +257,7 @@ int main(int argc, char **argv) {
printf("%lx", (unsigned long) grpc_slice_new_with_len);
printf("%lx", (unsigned long) grpc_slice_malloc);
printf("%lx", (unsigned long) grpc_slice_malloc_large);
printf("%lx", (unsigned long) grpc_slice_intern);
printf("%lx", (unsigned long) grpc_slice_from_copied_string);
printf("%lx", (unsigned long) grpc_slice_from_copied_buffer);
printf("%lx", (unsigned long) grpc_slice_from_static_string);
@ -267,6 +268,8 @@ int main(int argc, char **argv) {
printf("%lx", (unsigned long) grpc_slice_split_tail_maybe_ref);
printf("%lx", (unsigned long) grpc_slice_split_head);
printf("%lx", (unsigned long) grpc_empty_slice);
printf("%lx", (unsigned long) grpc_slice_default_hash_impl);
printf("%lx", (unsigned long) grpc_slice_default_eq_impl);
printf("%lx", (unsigned long) grpc_slice_eq);
printf("%lx", (unsigned long) grpc_slice_cmp);
printf("%lx", (unsigned long) grpc_slice_str_cmp);
@ -274,6 +277,7 @@ int main(int argc, char **argv) {
printf("%lx", (unsigned long) grpc_slice_rchr);
printf("%lx", (unsigned long) grpc_slice_chr);
printf("%lx", (unsigned long) grpc_slice_slice);
printf("%lx", (unsigned long) grpc_slice_hash);
printf("%lx", (unsigned long) grpc_slice_is_equivalent);
printf("%lx", (unsigned long) grpc_slice_dup);
printf("%lx", (unsigned long) grpc_slice_to_c_string);

@ -50,6 +50,7 @@ int g_failure = 0;
typedef struct {
bool eof;
bool use_true_binary_metadata;
bool only_intern_key;
} verify_params;
/* verify that the output frames that are generated by encoding the stream
@ -168,8 +169,11 @@ static void verify(const verify_params params, const char* expected,
for (i = 0; i < nheaders; i++) {
char* key = va_arg(l, char*);
char* value = va_arg(l, char*);
b.Append(key, grpc_core::Slice::FromStaticString(value),
CrashOnAppendError);
grpc_slice value_slice = grpc_slice_from_static_string(value);
if (!params.only_intern_key) {
value_slice = grpc_slice_intern(value_slice);
}
b.Append(key, grpc_core::Slice(value_slice), CrashOnAppendError);
}
va_end(l);
@ -208,6 +212,7 @@ static void test_basic_headers() {
verify_params params = {
false,
false,
false,
};
verify(params, "000005 0104 deadbeef 00 0161 0161", 1, "a", "a");
verify(params, "00000a 0104 deadbeef 00 0161 0161 00 0162 0163", 2, "a", "a",

@ -33,11 +33,12 @@ class EvaluateArgsTestUtil {
~EvaluateArgsTestUtil() { delete channel_args_; }
void AddPairToMetadata(const char* key, const char* value) {
metadata_.Append(key, Slice::FromStaticString(value),
[](absl::string_view, const Slice&) {
// We should never ever see an error here.
abort();
});
metadata_.Append(
key, Slice(grpc_slice_intern(grpc_slice_from_static_string(value))),
[](absl::string_view, const Slice&) {
// We should never ever see an error here.
abort();
});
}
void SetLocalEndpoint(absl::string_view local_uri) {

@ -38,7 +38,7 @@
#include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h"
#include "src/core/lib/security/security_connector/ssl_utils.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_utils.h"
#include "src/cpp/client/secure_credentials.h"
#include "src/proto/grpc/channelz/channelz.grpc.pb.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h"

@ -2225,6 +2225,7 @@ 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_intern.cc \
src/core/lib/slice/slice_internal.h \
src/core/lib/slice/slice_refcount.cc \
src/core/lib/slice/slice_refcount.h \
@ -2233,6 +2234,7 @@ src/core/lib/slice/slice_split.cc \
src/core/lib/slice/slice_split.h \
src/core/lib/slice/slice_string_helpers.cc \
src/core/lib/slice/slice_string_helpers.h \
src/core/lib/slice/slice_utils.h \
src/core/lib/surface/api_trace.cc \
src/core/lib/surface/api_trace.h \
src/core/lib/surface/builtins.cc \

@ -2024,6 +2024,7 @@ 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_intern.cc \
src/core/lib/slice/slice_internal.h \
src/core/lib/slice/slice_refcount.cc \
src/core/lib/slice/slice_refcount.h \
@ -2032,6 +2033,7 @@ src/core/lib/slice/slice_split.cc \
src/core/lib/slice/slice_split.h \
src/core/lib/slice/slice_string_helpers.cc \
src/core/lib/slice/slice_string_helpers.h \
src/core/lib/slice/slice_utils.h \
src/core/lib/surface/README.md \
src/core/lib/surface/api_trace.cc \
src/core/lib/surface/api_trace.h \

@ -2151,6 +2151,30 @@
],
"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": "slice_intern_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,

Loading…
Cancel
Save