diff options
Diffstat (limited to 'src/core/lib/compression')
-rw-r--r-- | src/core/lib/compression/algorithm_metadata.h | 19 | ||||
-rw-r--r-- | src/core/lib/compression/compression.cc | 273 | ||||
-rw-r--r-- | src/core/lib/compression/compression_internal.cc | 313 | ||||
-rw-r--r-- | src/core/lib/compression/compression_internal.h | 118 | ||||
-rw-r--r-- | src/core/lib/compression/message_compress.cc | 22 | ||||
-rw-r--r-- | src/core/lib/compression/message_compress.h | 9 |
6 files changed, 544 insertions, 210 deletions
diff --git a/src/core/lib/compression/algorithm_metadata.h b/src/core/lib/compression/algorithm_metadata.h index 3eb7088230..23333ac0c4 100644 --- a/src/core/lib/compression/algorithm_metadata.h +++ b/src/core/lib/compression/algorithm_metadata.h @@ -20,6 +20,7 @@ #define GRPC_CORE_LIB_COMPRESSION_ALGORITHM_METADATA_H #include <grpc/compression.h> +#include "src/core/lib/compression/compression_internal.h" #include "src/core/lib/transport/metadata.h" #ifdef __cplusplus @@ -30,14 +31,20 @@ extern "C" { grpc_slice grpc_compression_algorithm_slice( grpc_compression_algorithm algorithm); -/** Return stream compression algorithm based metadata value */ -grpc_slice grpc_stream_compression_algorithm_slice( - grpc_stream_compression_algorithm algorithm); +/** Find compression algorithm based on passed in mdstr - returns + * GRPC_COMPRESS_ALGORITHM_COUNT on failure */ +grpc_compression_algorithm grpc_compression_algorithm_from_slice( + grpc_slice str); -/** Return compression algorithm based metadata element (grpc-encoding: xxx) */ +/** Return compression algorithm based metadata element */ grpc_mdelem grpc_compression_encoding_mdelem( grpc_compression_algorithm algorithm); +/** Return message compression algorithm based metadata element (grpc-encoding: + * xxx) */ +grpc_mdelem grpc_message_compression_encoding_mdelem( + grpc_message_compression_algorithm algorithm); + /** Return stream compression algorithm based metadata element * (content-encoding: xxx) */ grpc_mdelem grpc_stream_compression_encoding_mdelem( @@ -45,8 +52,8 @@ grpc_mdelem grpc_stream_compression_encoding_mdelem( /** Find compression algorithm based on passed in mdstr - returns * GRPC_COMPRESS_ALGORITHM_COUNT on failure */ -grpc_compression_algorithm grpc_compression_algorithm_from_slice( - grpc_slice str); +grpc_message_compression_algorithm +grpc_message_compression_algorithm_from_slice(grpc_slice str); /** Find stream compression algorithm based on passed in mdstr - returns * GRPC_STREAM_COMPRESS_ALGORITHM_COUNT on failure */ diff --git a/src/core/lib/compression/compression.cc b/src/core/lib/compression/compression.cc index 1cfac23129..31349a58cd 100644 --- a/src/core/lib/compression/compression.cc +++ b/src/core/lib/compression/compression.cc @@ -23,40 +23,40 @@ #include <grpc/support/useful.h> #include "src/core/lib/compression/algorithm_metadata.h" +#include "src/core/lib/compression/compression_internal.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/transport/static_metadata.h" +int grpc_compression_algorithm_is_message( + grpc_compression_algorithm algorithm) { + return (algorithm >= GRPC_COMPRESS_MESSAGE_DEFLATE && + algorithm <= GRPC_COMPRESS_MESSAGE_GZIP) + ? 1 + : 0; +} + +int grpc_compression_algorithm_is_stream(grpc_compression_algorithm algorithm) { + return (algorithm == GRPC_COMPRESS_STREAM_GZIP) ? 1 : 0; +} + int grpc_compression_algorithm_parse(grpc_slice name, grpc_compression_algorithm *algorithm) { - /* we use strncmp not only because it's safer (even though in this case it - * doesn't matter, given that we are comparing against string literals, but - * because this way we needn't have "name" nil-terminated (useful for slice - * data, for example) */ if (grpc_slice_eq(name, GRPC_MDSTR_IDENTITY)) { *algorithm = GRPC_COMPRESS_NONE; return 1; - } else if (grpc_slice_eq(name, GRPC_MDSTR_GZIP)) { - *algorithm = GRPC_COMPRESS_GZIP; - return 1; } else if (grpc_slice_eq(name, GRPC_MDSTR_DEFLATE)) { - *algorithm = GRPC_COMPRESS_DEFLATE; - return 1; - } else { - return 0; - } -} - -int grpc_stream_compression_algorithm_parse( - grpc_slice name, grpc_stream_compression_algorithm *algorithm) { - if (grpc_slice_eq(name, GRPC_MDSTR_IDENTITY)) { - *algorithm = GRPC_STREAM_COMPRESS_NONE; + *algorithm = GRPC_COMPRESS_MESSAGE_DEFLATE; return 1; } else if (grpc_slice_eq(name, GRPC_MDSTR_GZIP)) { - *algorithm = GRPC_STREAM_COMPRESS_GZIP; + *algorithm = GRPC_COMPRESS_MESSAGE_GZIP; + return 1; + } else if (grpc_slice_eq(name, GRPC_MDSTR_STREAM_GZIP)) { + *algorithm = GRPC_COMPRESS_STREAM_GZIP; return 1; } else { return 0; } + return 0; } int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm, @@ -67,49 +67,69 @@ int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm, case GRPC_COMPRESS_NONE: *name = "identity"; return 1; - case GRPC_COMPRESS_DEFLATE: + case GRPC_COMPRESS_MESSAGE_DEFLATE: *name = "deflate"; return 1; - case GRPC_COMPRESS_GZIP: + case GRPC_COMPRESS_MESSAGE_GZIP: *name = "gzip"; return 1; + case GRPC_COMPRESS_STREAM_GZIP: + *name = "stream-gzip"; + return 1; case GRPC_COMPRESS_ALGORITHMS_COUNT: return 0; } return 0; } -int grpc_stream_compression_algorithm_name( - grpc_stream_compression_algorithm algorithm, const char **name) { - GRPC_API_TRACE( - "grpc_stream_compression_algorithm_parse(algorithm=%d, name=%p)", 2, - ((int)algorithm, name)); - switch (algorithm) { - case GRPC_STREAM_COMPRESS_NONE: - *name = "identity"; - return 1; - case GRPC_STREAM_COMPRESS_GZIP: - *name = "gzip"; - return 1; - case GRPC_STREAM_COMPRESS_ALGORITHMS_COUNT: - return 0; +grpc_compression_algorithm grpc_compression_algorithm_for_level( + grpc_compression_level level, uint32_t accepted_encodings) { + grpc_compression_algorithm algo; + if (level == GRPC_COMPRESS_LEVEL_NONE) { + return GRPC_COMPRESS_NONE; + } else if (level <= GRPC_COMPRESS_LEVEL_MESSAGE_HIGH) { + GPR_ASSERT( + grpc_compression_algorithm_from_message_stream_compression_algorithm( + &algo, + grpc_message_compression_algorithm_for_level( + grpc_compression_level_to_message_compression_level(level), + grpc_compression_bitset_to_message_bitset(accepted_encodings)), + (grpc_stream_compression_algorithm)0)); + return algo; + } else if (level <= GRPC_COMPRESS_LEVEL_STREAM_HIGH) { + GPR_ASSERT( + grpc_compression_algorithm_from_message_stream_compression_algorithm( + &algo, (grpc_message_compression_algorithm)0, + grpc_stream_compression_algorithm_for_level( + grpc_compression_level_to_stream_compression_level(level), + grpc_compression_bitset_to_stream_bitset(accepted_encodings)))); + return algo; + } else { + gpr_log(GPR_ERROR, "Unknown compression level: %d", level); + return GRPC_COMPRESS_NONE; } - return 0; } -grpc_compression_algorithm grpc_compression_algorithm_from_slice( - grpc_slice str) { - if (grpc_slice_eq(str, GRPC_MDSTR_IDENTITY)) return GRPC_COMPRESS_NONE; - if (grpc_slice_eq(str, GRPC_MDSTR_DEFLATE)) return GRPC_COMPRESS_DEFLATE; - if (grpc_slice_eq(str, GRPC_MDSTR_GZIP)) return GRPC_COMPRESS_GZIP; - return GRPC_COMPRESS_ALGORITHMS_COUNT; +void grpc_compression_options_init(grpc_compression_options *opts) { + memset(opts, 0, sizeof(*opts)); + /* all enabled by default */ + opts->enabled_algorithms_bitset = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; } -grpc_stream_compression_algorithm grpc_stream_compression_algorithm_from_slice( - grpc_slice str) { - if (grpc_slice_eq(str, GRPC_MDSTR_IDENTITY)) return GRPC_STREAM_COMPRESS_NONE; - if (grpc_slice_eq(str, GRPC_MDSTR_GZIP)) return GRPC_STREAM_COMPRESS_GZIP; - return GRPC_STREAM_COMPRESS_ALGORITHMS_COUNT; +void grpc_compression_options_enable_algorithm( + grpc_compression_options *opts, grpc_compression_algorithm algorithm) { + GPR_BITSET(&opts->enabled_algorithms_bitset, algorithm); +} + +void grpc_compression_options_disable_algorithm( + grpc_compression_options *opts, grpc_compression_algorithm algorithm) { + GPR_BITCLEAR(&opts->enabled_algorithms_bitset, algorithm); +} + +int grpc_compression_options_is_algorithm_enabled( + const grpc_compression_options *opts, + grpc_compression_algorithm algorithm) { + return GPR_BITGET(opts->enabled_algorithms_bitset, algorithm); } grpc_slice grpc_compression_algorithm_slice( @@ -117,27 +137,27 @@ grpc_slice grpc_compression_algorithm_slice( switch (algorithm) { case GRPC_COMPRESS_NONE: return GRPC_MDSTR_IDENTITY; - case GRPC_COMPRESS_DEFLATE: + case GRPC_COMPRESS_MESSAGE_DEFLATE: return GRPC_MDSTR_DEFLATE; - case GRPC_COMPRESS_GZIP: + case GRPC_COMPRESS_MESSAGE_GZIP: return GRPC_MDSTR_GZIP; + case GRPC_COMPRESS_STREAM_GZIP: + return GRPC_MDSTR_STREAM_GZIP; case GRPC_COMPRESS_ALGORITHMS_COUNT: return grpc_empty_slice(); } return grpc_empty_slice(); } -grpc_slice grpc_stream_compression_algorithm_slice( - grpc_stream_compression_algorithm algorithm) { - switch (algorithm) { - case GRPC_STREAM_COMPRESS_NONE: - return GRPC_MDSTR_IDENTITY; - case GRPC_STREAM_COMPRESS_GZIP: - return GRPC_MDSTR_GZIP; - case GRPC_STREAM_COMPRESS_ALGORITHMS_COUNT: - return grpc_empty_slice(); - } - return grpc_empty_slice(); +grpc_compression_algorithm grpc_compression_algorithm_from_slice( + grpc_slice str) { + if (grpc_slice_eq(str, GRPC_MDSTR_IDENTITY)) return GRPC_COMPRESS_NONE; + if (grpc_slice_eq(str, GRPC_MDSTR_DEFLATE)) + return GRPC_COMPRESS_MESSAGE_DEFLATE; + if (grpc_slice_eq(str, GRPC_MDSTR_GZIP)) return GRPC_COMPRESS_MESSAGE_GZIP; + if (grpc_slice_eq(str, GRPC_MDSTR_STREAM_GZIP)) + return GRPC_COMPRESS_STREAM_GZIP; + return GRPC_COMPRESS_ALGORITHMS_COUNT; } grpc_mdelem grpc_compression_encoding_mdelem( @@ -145,139 +165,14 @@ grpc_mdelem grpc_compression_encoding_mdelem( switch (algorithm) { case GRPC_COMPRESS_NONE: return GRPC_MDELEM_GRPC_ENCODING_IDENTITY; - case GRPC_COMPRESS_DEFLATE: + case GRPC_COMPRESS_MESSAGE_DEFLATE: return GRPC_MDELEM_GRPC_ENCODING_DEFLATE; - case GRPC_COMPRESS_GZIP: + case GRPC_COMPRESS_MESSAGE_GZIP: + return GRPC_MDELEM_GRPC_ENCODING_GZIP; + case GRPC_COMPRESS_STREAM_GZIP: return GRPC_MDELEM_GRPC_ENCODING_GZIP; default: break; } return GRPC_MDNULL; } - -grpc_mdelem grpc_stream_compression_encoding_mdelem( - grpc_stream_compression_algorithm algorithm) { - switch (algorithm) { - case GRPC_STREAM_COMPRESS_NONE: - return GRPC_MDELEM_CONTENT_ENCODING_IDENTITY; - case GRPC_STREAM_COMPRESS_GZIP: - return GRPC_MDELEM_CONTENT_ENCODING_GZIP; - default: - break; - } - return GRPC_MDNULL; -} - -void grpc_compression_options_init(grpc_compression_options *opts) { - memset(opts, 0, sizeof(*opts)); - /* all enabled by default */ - opts->enabled_algorithms_bitset = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; - opts->enabled_stream_compression_algorithms_bitset = - (1u << GRPC_STREAM_COMPRESS_ALGORITHMS_COUNT) - 1; -} - -void grpc_compression_options_enable_algorithm( - grpc_compression_options *opts, grpc_compression_algorithm algorithm) { - GPR_BITSET(&opts->enabled_algorithms_bitset, algorithm); -} - -void grpc_compression_options_disable_algorithm( - grpc_compression_options *opts, grpc_compression_algorithm algorithm) { - GPR_BITCLEAR(&opts->enabled_algorithms_bitset, algorithm); -} - -int grpc_compression_options_is_algorithm_enabled( - const grpc_compression_options *opts, - grpc_compression_algorithm algorithm) { - return GPR_BITGET(opts->enabled_algorithms_bitset, algorithm); -} - -int grpc_compression_options_is_stream_compression_algorithm_enabled( - const grpc_compression_options *opts, - grpc_stream_compression_algorithm algorithm) { - return GPR_BITGET(opts->enabled_stream_compression_algorithms_bitset, - algorithm); -} - -/* TODO(dgq): Add the ability to specify parameters to the individual - * compression algorithms */ -grpc_compression_algorithm grpc_compression_algorithm_for_level( - grpc_compression_level level, uint32_t accepted_encodings) { - GRPC_API_TRACE("grpc_compression_algorithm_for_level(level=%d)", 1, - ((int)level)); - if (level > GRPC_COMPRESS_LEVEL_HIGH) { - gpr_log(GPR_ERROR, "Unknown compression level %d.", (int)level); - abort(); - } - - const size_t num_supported = - GPR_BITCOUNT(accepted_encodings) - 1; /* discard NONE */ - if (level == GRPC_COMPRESS_LEVEL_NONE || num_supported == 0) { - return GRPC_COMPRESS_NONE; - } - - GPR_ASSERT(level > 0); - - /* Establish a "ranking" or compression algorithms in increasing order of - * compression. - * This is simplistic and we will probably want to introduce other dimensions - * in the future (cpu/memory cost, etc). */ - const grpc_compression_algorithm algos_ranking[] = {GRPC_COMPRESS_GZIP, - GRPC_COMPRESS_DEFLATE}; - - /* intersect algos_ranking with the supported ones keeping the ranked order */ - grpc_compression_algorithm - sorted_supported_algos[GRPC_COMPRESS_ALGORITHMS_COUNT]; - size_t algos_supported_idx = 0; - for (size_t i = 0; i < GPR_ARRAY_SIZE(algos_ranking); i++) { - const grpc_compression_algorithm alg = algos_ranking[i]; - for (size_t j = 0; j < num_supported; j++) { - if (GPR_BITGET(accepted_encodings, alg) == 1) { - /* if \a alg in supported */ - sorted_supported_algos[algos_supported_idx++] = alg; - break; - } - } - if (algos_supported_idx == num_supported) break; - } - - switch (level) { - case GRPC_COMPRESS_LEVEL_NONE: - abort(); /* should have been handled already */ - case GRPC_COMPRESS_LEVEL_LOW: - return sorted_supported_algos[0]; - case GRPC_COMPRESS_LEVEL_MED: - return sorted_supported_algos[num_supported / 2]; - case GRPC_COMPRESS_LEVEL_HIGH: - return sorted_supported_algos[num_supported - 1]; - default: - abort(); - }; -} - -GRPCAPI grpc_stream_compression_algorithm -grpc_stream_compression_algorithm_for_level( - grpc_stream_compression_level level, uint32_t accepted_stream_encodings) { - GRPC_API_TRACE("grpc_stream_compression_algorithm_for_level(level=%d)", 1, - ((int)level)); - if (level > GRPC_STREAM_COMPRESS_LEVEL_HIGH) { - gpr_log(GPR_ERROR, "Unknown compression level %d.", (int)level); - abort(); - } - - switch (level) { - case GRPC_STREAM_COMPRESS_LEVEL_NONE: - return GRPC_STREAM_COMPRESS_NONE; - case GRPC_STREAM_COMPRESS_LEVEL_LOW: - case GRPC_STREAM_COMPRESS_LEVEL_MED: - case GRPC_STREAM_COMPRESS_LEVEL_HIGH: - if (GPR_BITGET(accepted_stream_encodings, GRPC_STREAM_COMPRESS_GZIP) == - 1) { - return GRPC_STREAM_COMPRESS_GZIP; - } else { - return GRPC_STREAM_COMPRESS_NONE; - } - default: - abort(); - } -} diff --git a/src/core/lib/compression/compression_internal.cc b/src/core/lib/compression/compression_internal.cc new file mode 100644 index 0000000000..e31eb830f1 --- /dev/null +++ b/src/core/lib/compression/compression_internal.cc @@ -0,0 +1,313 @@ +/* + * + * 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 <stdlib.h> +#include <string.h> + +#include <grpc/compression.h> +#include <grpc/support/useful.h> + +#include "src/core/lib/compression/algorithm_metadata.h" +#include "src/core/lib/compression/compression_internal.h" +#include "src/core/lib/surface/api_trace.h" +#include "src/core/lib/transport/static_metadata.h" + +/* Interfaces related to MD */ + +grpc_message_compression_algorithm +grpc_message_compression_algorithm_from_slice(grpc_slice str) { + if (grpc_slice_eq(str, GRPC_MDSTR_IDENTITY)) + return GRPC_MESSAGE_COMPRESS_NONE; + if (grpc_slice_eq(str, GRPC_MDSTR_DEFLATE)) + return GRPC_MESSAGE_COMPRESS_DEFLATE; + if (grpc_slice_eq(str, GRPC_MDSTR_GZIP)) return GRPC_MESSAGE_COMPRESS_GZIP; + return GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT; +} + +grpc_stream_compression_algorithm grpc_stream_compression_algorithm_from_slice( + grpc_slice str) { + if (grpc_slice_eq(str, GRPC_MDSTR_IDENTITY)) return GRPC_STREAM_COMPRESS_NONE; + if (grpc_slice_eq(str, GRPC_MDSTR_GZIP)) return GRPC_STREAM_COMPRESS_GZIP; + return GRPC_STREAM_COMPRESS_ALGORITHMS_COUNT; +} + +grpc_mdelem grpc_message_compression_encoding_mdelem( + grpc_message_compression_algorithm algorithm) { + switch (algorithm) { + case GRPC_MESSAGE_COMPRESS_NONE: + return GRPC_MDELEM_GRPC_ENCODING_IDENTITY; + case GRPC_MESSAGE_COMPRESS_DEFLATE: + return GRPC_MDELEM_GRPC_ENCODING_DEFLATE; + case GRPC_MESSAGE_COMPRESS_GZIP: + return GRPC_MDELEM_GRPC_ENCODING_GZIP; + default: + break; + } + return GRPC_MDNULL; +} + +grpc_mdelem grpc_stream_compression_encoding_mdelem( + grpc_stream_compression_algorithm algorithm) { + switch (algorithm) { + case GRPC_STREAM_COMPRESS_NONE: + return GRPC_MDELEM_CONTENT_ENCODING_IDENTITY; + case GRPC_STREAM_COMPRESS_GZIP: + return GRPC_MDELEM_CONTENT_ENCODING_GZIP; + default: + break; + } + return GRPC_MDNULL; +} + +/* Interfaces performing transformation between compression algorithms and + * levels. */ +grpc_message_compression_level +grpc_compression_level_to_message_compression_level( + grpc_compression_level level) { + if (level >= GRPC_COMPRESS_LEVEL_COUNT) { + return GRPC_MESSAGE_COMPRESS_LEVEL_NONE; + } + return (grpc_message_compression_level)( + (uint32_t)(level - GRPC_COMPRESS_LEVEL_NONE) + + (uint32_t)GRPC_MESSAGE_COMPRESS_LEVEL_NONE); +} + +grpc_stream_compression_level +grpc_compression_level_to_stream_compression_level( + grpc_compression_level level) { + if (level >= GRPC_COMPRESS_LEVEL_COUNT) { + return GRPC_STREAM_COMPRESS_LEVEL_NONE; + } + return (grpc_stream_compression_level)( + (uint32_t)(level - (GRPC_MESSAGE_COMPRESS_LEVEL_COUNT - 1) - + GRPC_COMPRESS_LEVEL_NONE) + + (uint32_t)GRPC_STREAM_COMPRESS_LEVEL_NONE); +} + +grpc_message_compression_algorithm +grpc_compression_algorithm_to_message_compression_algorithm( + grpc_compression_algorithm algo) { + switch (algo) { + case GRPC_COMPRESS_MESSAGE_DEFLATE: + return GRPC_MESSAGE_COMPRESS_DEFLATE; + case GRPC_COMPRESS_MESSAGE_GZIP: + return GRPC_MESSAGE_COMPRESS_GZIP; + default: + return GRPC_MESSAGE_COMPRESS_NONE; + } +} + +grpc_stream_compression_algorithm +grpc_compression_algorithm_to_stream_compression_algorithm( + grpc_compression_algorithm algo) { + switch (algo) { + case GRPC_COMPRESS_STREAM_GZIP: + return GRPC_STREAM_COMPRESS_GZIP; + default: + return GRPC_STREAM_COMPRESS_NONE; + } +} + +uint32_t grpc_compression_bitset_to_message_bitset(uint32_t bitset) { + return bitset & ((1u << GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT) - 1); +} + +uint32_t grpc_compression_bitset_to_stream_bitset(uint32_t bitset) { + uint32_t identity = (bitset & 1u); + uint32_t other_bits = + (bitset >> (GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT - 1)) & + ((1u << GRPC_STREAM_COMPRESS_ALGORITHMS_COUNT) - 2); + return identity | other_bits; +} + +uint32_t grpc_compression_bitset_from_message_stream_compression_bitset( + uint32_t message_bitset, uint32_t stream_bitset) { + uint32_t offset_stream_bitset = + (stream_bitset & 1u) | + ((stream_bitset & (~1u)) << (GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT - 1)); + return message_bitset | offset_stream_bitset; +} + +int grpc_compression_algorithm_from_message_stream_compression_algorithm( + grpc_compression_algorithm *algorithm, + grpc_message_compression_algorithm message_algorithm, + grpc_stream_compression_algorithm stream_algorithm) { + if (message_algorithm != GRPC_MESSAGE_COMPRESS_NONE && + stream_algorithm != GRPC_STREAM_COMPRESS_NONE) { + *algorithm = GRPC_COMPRESS_NONE; + return 0; + } + if (message_algorithm == GRPC_MESSAGE_COMPRESS_NONE) { + switch (stream_algorithm) { + case GRPC_STREAM_COMPRESS_NONE: + *algorithm = GRPC_COMPRESS_NONE; + return 1; + case GRPC_STREAM_COMPRESS_GZIP: + *algorithm = GRPC_COMPRESS_STREAM_GZIP; + return 1; + default: + *algorithm = GRPC_COMPRESS_NONE; + return 0; + } + } else { + switch (message_algorithm) { + case GRPC_MESSAGE_COMPRESS_NONE: + *algorithm = GRPC_COMPRESS_NONE; + return 1; + case GRPC_MESSAGE_COMPRESS_DEFLATE: + *algorithm = GRPC_COMPRESS_MESSAGE_DEFLATE; + return 1; + case GRPC_MESSAGE_COMPRESS_GZIP: + *algorithm = GRPC_COMPRESS_MESSAGE_GZIP; + return 1; + default: + *algorithm = GRPC_COMPRESS_NONE; + return 0; + } + } + return 0; +} + +/* Interfaces for message compression. */ + +int grpc_message_compression_algorithm_name( + grpc_message_compression_algorithm algorithm, const char **name) { + GRPC_API_TRACE( + "grpc_message_compression_algorithm_parse(algorithm=%d, name=%p)", 2, + ((int)algorithm, name)); + switch (algorithm) { + case GRPC_MESSAGE_COMPRESS_NONE: + *name = "identity"; + return 1; + case GRPC_MESSAGE_COMPRESS_DEFLATE: + *name = "deflate"; + return 1; + case GRPC_MESSAGE_COMPRESS_GZIP: + *name = "gzip"; + return 1; + case GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT: + return 0; + } + return 0; +} + +/* TODO(dgq): Add the ability to specify parameters to the individual + * compression algorithms */ +grpc_message_compression_algorithm grpc_message_compression_algorithm_for_level( + grpc_message_compression_level level, uint32_t accepted_encodings) { + GRPC_API_TRACE("grpc_message_compression_algorithm_for_level(level=%d)", 1, + ((int)level)); + if (level > GRPC_MESSAGE_COMPRESS_LEVEL_HIGH) { + gpr_log(GPR_ERROR, "Unknown message compression level %d.", (int)level); + abort(); + } + + const size_t num_supported = + GPR_BITCOUNT(accepted_encodings) - 1; /* discard NONE */ + if (level == GRPC_MESSAGE_COMPRESS_LEVEL_NONE || num_supported == 0) { + return GRPC_MESSAGE_COMPRESS_NONE; + } + + GPR_ASSERT(level > 0); + + /* Establish a "ranking" or compression algorithms in increasing order of + * compression. + * This is simplistic and we will probably want to introduce other dimensions + * in the future (cpu/memory cost, etc). */ + const grpc_message_compression_algorithm algos_ranking[] = { + GRPC_MESSAGE_COMPRESS_GZIP, GRPC_MESSAGE_COMPRESS_DEFLATE}; + + /* intersect algos_ranking with the supported ones keeping the ranked order */ + grpc_message_compression_algorithm + sorted_supported_algos[GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT]; + size_t algos_supported_idx = 0; + for (size_t i = 0; i < GPR_ARRAY_SIZE(algos_ranking); i++) { + const grpc_message_compression_algorithm alg = algos_ranking[i]; + for (size_t j = 0; j < num_supported; j++) { + if (GPR_BITGET(accepted_encodings, alg) == 1) { + /* if \a alg in supported */ + sorted_supported_algos[algos_supported_idx++] = alg; + break; + } + } + if (algos_supported_idx == num_supported) break; + } + + switch (level) { + case GRPC_MESSAGE_COMPRESS_LEVEL_NONE: + abort(); /* should have been handled already */ + case GRPC_MESSAGE_COMPRESS_LEVEL_LOW: + return sorted_supported_algos[0]; + case GRPC_MESSAGE_COMPRESS_LEVEL_MED: + return sorted_supported_algos[num_supported / 2]; + case GRPC_MESSAGE_COMPRESS_LEVEL_HIGH: + return sorted_supported_algos[num_supported - 1]; + default: + abort(); + }; +} + +int grpc_message_compression_algorithm_parse( + grpc_slice value, grpc_message_compression_algorithm *algorithm) { + if (grpc_slice_eq(value, GRPC_MDSTR_IDENTITY)) { + *algorithm = GRPC_MESSAGE_COMPRESS_NONE; + return 1; + } else if (grpc_slice_eq(value, GRPC_MDSTR_DEFLATE)) { + *algorithm = GRPC_MESSAGE_COMPRESS_DEFLATE; + return 1; + } else if (grpc_slice_eq(value, GRPC_MDSTR_GZIP)) { + *algorithm = GRPC_MESSAGE_COMPRESS_GZIP; + return 1; + } else { + return 0; + } + return 0; +} + +/* Interfaces for stream compression. */ + +grpc_stream_compression_algorithm grpc_stream_compression_algorithm_for_level( + grpc_stream_compression_level level, uint32_t accepted_encodings) { + GRPC_API_TRACE("grpc_stream_compression_algorithm_for_level(level=%d)", 1, + ((int)level)); + if (level > GRPC_STREAM_COMPRESS_LEVEL_HIGH) { + gpr_log(GPR_ERROR, "Unknown stream compression level %d.", (int)level); + abort(); + } + + /* TODO(mxyan): Use more sophisticated scheme when more algorithms added. */ + if (level != GRPC_STREAM_COMPRESS_LEVEL_NONE && + GPR_BITGET(accepted_encodings, GRPC_STREAM_COMPRESS_GZIP)) { + return GRPC_STREAM_COMPRESS_GZIP; + } + return GRPC_STREAM_COMPRESS_NONE; +} + +int grpc_stream_compression_algorithm_parse( + grpc_slice value, grpc_stream_compression_algorithm *algorithm) { + if (grpc_slice_eq(value, GRPC_MDSTR_IDENTITY)) { + *algorithm = GRPC_STREAM_COMPRESS_NONE; + return 1; + } else if (grpc_slice_eq(value, GRPC_MDSTR_GZIP)) { + *algorithm = GRPC_STREAM_COMPRESS_GZIP; + return 1; + } else { + return 0; + } + return 0; +} diff --git a/src/core/lib/compression/compression_internal.h b/src/core/lib/compression/compression_internal.h new file mode 100644 index 0000000000..aab5324b67 --- /dev/null +++ b/src/core/lib/compression/compression_internal.h @@ -0,0 +1,118 @@ +/* + * + * Copyright 2017 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_COMPRESSION_COMPRESSION_INTERNAL_H +#define GRPC_CORE_LIB_COMPRESSION_COMPRESSION_INTERNAL_H + +#include <grpc/impl/codegen/compression_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + GRPC_MESSAGE_COMPRESS_NONE = 0, + GRPC_MESSAGE_COMPRESS_DEFLATE, + GRPC_MESSAGE_COMPRESS_GZIP, + /* TODO(ctiller): snappy */ + GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT +} grpc_message_compression_algorithm; + +/** Stream compresssion algorithms supported by gRPC */ +typedef enum { + GRPC_STREAM_COMPRESS_NONE = 0, + GRPC_STREAM_COMPRESS_GZIP, + GRPC_STREAM_COMPRESS_ALGORITHMS_COUNT +} grpc_stream_compression_algorithm; + +/** Compression levels allow a party with knowledge of its peer's accepted + * encodings to request compression in an abstract way. The level-algorithm + * mapping is performed internally and depends on the peer's supported + * compression algorithms. */ +typedef enum { + GRPC_MESSAGE_COMPRESS_LEVEL_NONE = 0, + GRPC_MESSAGE_COMPRESS_LEVEL_LOW, + GRPC_MESSAGE_COMPRESS_LEVEL_MED, + GRPC_MESSAGE_COMPRESS_LEVEL_HIGH, + GRPC_MESSAGE_COMPRESS_LEVEL_COUNT +} grpc_message_compression_level; + +/** Compression levels for stream compression algorithms */ +typedef enum { + GRPC_STREAM_COMPRESS_LEVEL_NONE = 0, + GRPC_STREAM_COMPRESS_LEVEL_LOW, + GRPC_STREAM_COMPRESS_LEVEL_MED, + GRPC_STREAM_COMPRESS_LEVEL_HIGH, + GRPC_STREAM_COMPRESS_LEVEL_COUNT +} grpc_stream_compression_level; + +/* Interfaces performing transformation between compression algorithms and + * levels. */ + +grpc_message_compression_level +grpc_compression_level_to_message_compression_level( + grpc_compression_level level); + +grpc_stream_compression_level +grpc_compression_level_to_stream_compression_level( + grpc_compression_level level); + +grpc_message_compression_algorithm +grpc_compression_algorithm_to_message_compression_algorithm( + grpc_compression_algorithm algo); + +grpc_stream_compression_algorithm +grpc_compression_algorithm_to_stream_compression_algorithm( + grpc_compression_algorithm algo); + +uint32_t grpc_compression_bitset_to_message_bitset(uint32_t bitset); + +uint32_t grpc_compression_bitset_to_stream_bitset(uint32_t bitset); + +uint32_t grpc_compression_bitset_from_message_stream_compression_bitset( + uint32_t message_bitset, uint32_t stream_bitset); + +int grpc_compression_algorithm_from_message_stream_compression_algorithm( + grpc_compression_algorithm *algorithm, + grpc_message_compression_algorithm message_algorithm, + grpc_stream_compression_algorithm stream_algorithm); + +/* Interfaces for message compression. */ + +int grpc_message_compression_algorithm_name( + grpc_message_compression_algorithm algorithm, const char **name); + +grpc_message_compression_algorithm grpc_message_compression_algorithm_for_level( + grpc_message_compression_level level, uint32_t accepted_encodings); + +int grpc_message_compression_algorithm_parse( + grpc_slice value, grpc_message_compression_algorithm *algorithm); + +/* Interfaces for stream compression. */ + +grpc_stream_compression_algorithm grpc_stream_compression_algorithm_for_level( + grpc_stream_compression_level level, uint32_t accepted_encodings); + +int grpc_stream_compression_algorithm_parse( + grpc_slice value, grpc_stream_compression_algorithm *algorithm); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_LIB_COMPRESSION_COMPRESSION_INTERNAL_H */ diff --git a/src/core/lib/compression/message_compress.cc b/src/core/lib/compression/message_compress.cc index c051e28864..d174992355 100644 --- a/src/core/lib/compression/message_compress.cc +++ b/src/core/lib/compression/message_compress.cc @@ -143,18 +143,18 @@ static int copy(grpc_slice_buffer* input, grpc_slice_buffer* output) { } static int compress_inner(grpc_exec_ctx* exec_ctx, - grpc_compression_algorithm algorithm, + grpc_message_compression_algorithm algorithm, grpc_slice_buffer* input, grpc_slice_buffer* output) { switch (algorithm) { - case GRPC_COMPRESS_NONE: + case GRPC_MESSAGE_COMPRESS_NONE: /* the fallback path always needs to be send uncompressed: we simply rely on that here */ return 0; - case GRPC_COMPRESS_DEFLATE: + case GRPC_MESSAGE_COMPRESS_DEFLATE: return zlib_compress(exec_ctx, input, output, 0); - case GRPC_COMPRESS_GZIP: + case GRPC_MESSAGE_COMPRESS_GZIP: return zlib_compress(exec_ctx, input, output, 1); - case GRPC_COMPRESS_ALGORITHMS_COUNT: + case GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT: break; } gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm); @@ -162,7 +162,7 @@ static int compress_inner(grpc_exec_ctx* exec_ctx, } int grpc_msg_compress(grpc_exec_ctx* exec_ctx, - grpc_compression_algorithm algorithm, + grpc_message_compression_algorithm algorithm, grpc_slice_buffer* input, grpc_slice_buffer* output) { if (!compress_inner(exec_ctx, algorithm, input, output)) { copy(input, output); @@ -172,16 +172,16 @@ int grpc_msg_compress(grpc_exec_ctx* exec_ctx, } int grpc_msg_decompress(grpc_exec_ctx* exec_ctx, - grpc_compression_algorithm algorithm, + grpc_message_compression_algorithm algorithm, grpc_slice_buffer* input, grpc_slice_buffer* output) { switch (algorithm) { - case GRPC_COMPRESS_NONE: + case GRPC_MESSAGE_COMPRESS_NONE: return copy(input, output); - case GRPC_COMPRESS_DEFLATE: + case GRPC_MESSAGE_COMPRESS_DEFLATE: return zlib_decompress(exec_ctx, input, output, 0); - case GRPC_COMPRESS_GZIP: + case GRPC_MESSAGE_COMPRESS_GZIP: return zlib_decompress(exec_ctx, input, output, 1); - case GRPC_COMPRESS_ALGORITHMS_COUNT: + case GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT: break; } gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm); diff --git a/src/core/lib/compression/message_compress.h b/src/core/lib/compression/message_compress.h index d2545a02c2..7c2eb99443 100644 --- a/src/core/lib/compression/message_compress.h +++ b/src/core/lib/compression/message_compress.h @@ -19,9 +19,10 @@ #ifndef GRPC_CORE_LIB_COMPRESSION_MESSAGE_COMPRESS_H #define GRPC_CORE_LIB_COMPRESSION_MESSAGE_COMPRESS_H -#include <grpc/compression.h> #include <grpc/slice_buffer.h> +#include "src/core/lib/compression/compression_internal.h" + #ifdef __cplusplus extern "C" { #endif @@ -30,18 +31,18 @@ extern "C" { On success, appends compressed slices to output and returns 1. On failure, appends uncompressed slices to output and returns 0. */ int grpc_msg_compress(grpc_exec_ctx* exec_ctx, - grpc_compression_algorithm algorithm, + grpc_message_compression_algorithm algorithm, grpc_slice_buffer* input, grpc_slice_buffer* output); /* decompress 'input' to 'output' using 'algorithm'. On success, appends slices to output and returns 1. On failure, output is unchanged, and returns 0. */ int grpc_msg_decompress(grpc_exec_ctx* exec_ctx, - grpc_compression_algorithm algorithm, + grpc_message_compression_algorithm algorithm, grpc_slice_buffer* input, grpc_slice_buffer* output); #ifdef __cplusplus } #endif -#endif /* GRPC_CORE_LIB_COMPRESSION_MESSAGE_COMPRESS_H */
\ No newline at end of file +#endif /* GRPC_CORE_LIB_COMPRESSION_MESSAGE_COMPRESS_H */ |