aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar David Garcia Quintas <dgq@google.com>2016-03-17 22:51:52 -0700
committerGravatar David Garcia Quintas <dgq@google.com>2016-03-17 22:51:52 -0700
commit13c2f6e69d04804b4c1cba6380b54f6adb80cee0 (patch)
tree5b62e2d0c5bb267e12e125ea5421c3e96c483157
parent921f4b0a6e0c77f8c1d0f48b72d7087a21f5e311 (diff)
Implemented compression level algorithms properly (as a function of the accepted algorithms by the call's peer.
-rw-r--r--include/grpc/compression.h6
-rw-r--r--src/core/compression/compression_algorithm.c46
-rw-r--r--src/core/surface/call.c6
-rw-r--r--src/core/surface/call.h9
-rw-r--r--src/cpp/server/server_context.cc3
-rw-r--r--test/core/compression/compression_test.c102
6 files changed, 152 insertions, 20 deletions
diff --git a/include/grpc/compression.h b/include/grpc/compression.h
index acc168a6ee..70ba393261 100644
--- a/include/grpc/compression.h
+++ b/include/grpc/compression.h
@@ -55,11 +55,13 @@ GRPCAPI int grpc_compression_algorithm_parse(
GRPCAPI int grpc_compression_algorithm_name(
grpc_compression_algorithm algorithm, char **name);
-/** Returns the compression algorithm corresponding to \a level.
+/** Returns the compression algorithm corresponding to \a level for the
+ * compression algorithms encoded in the \a accepted_encodings bitset.
*
* It abort()s for unknown levels . */
GRPCAPI grpc_compression_algorithm
-grpc_compression_algorithm_for_level(grpc_compression_level level);
+grpc_compression_algorithm_for_level(grpc_compression_level level,
+ uint32_t accepted_encodings);
GRPCAPI void grpc_compression_options_init(grpc_compression_options *opts);
diff --git a/src/core/compression/compression_algorithm.c b/src/core/compression/compression_algorithm.c
index 6f3a8eb28e..a76abc372f 100644
--- a/src/core/compression/compression_algorithm.c
+++ b/src/core/compression/compression_algorithm.c
@@ -128,20 +128,56 @@ grpc_mdelem *grpc_compression_encoding_mdelem(
/* 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) {
+ 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[num_supported];
+ 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:
- return GRPC_COMPRESS_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 GRPC_COMPRESS_DEFLATE;
+ return sorted_supported_algos[num_supported - 1];
default:
- gpr_log(GPR_ERROR, "Unknown compression level %d.", (int)level);
abort();
- }
+ };
}
void grpc_compression_options_init(grpc_compression_options *opts) {
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index 1b117aa6b8..7dd74d86b4 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -1481,3 +1481,9 @@ void *grpc_call_context_get(grpc_call *call, grpc_context_index elem) {
}
uint8_t grpc_call_is_client(grpc_call *call) { return call->is_client; }
+
+grpc_compression_algorithm grpc_call_compression_for_level(
+ grpc_call *call, grpc_compression_level level) {
+ return grpc_compression_algorithm_for_level(level,
+ call->encodings_accepted_by_peer);
+}
diff --git a/src/core/surface/call.h b/src/core/surface/call.h
index 0bbffb98ae..0b3f543fe4 100644
--- a/src/core/surface/call.h
+++ b/src/core/surface/call.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,7 +38,9 @@
#include "src/core/channel/context.h"
#include "src/core/surface/api_trace.h"
#include "src/core/surface/surface_trace.h"
+
#include <grpc/grpc.h>
+#include <grpc/impl/codegen/compression_types.h>
#ifdef __cplusplus
extern "C" {
@@ -102,6 +104,11 @@ void *grpc_call_context_get(grpc_call *call, grpc_context_index elem);
uint8_t grpc_call_is_client(grpc_call *call);
+/* Return an appropriate compression algorithm for the requested compression \a
+ * level in the context of \a call. */
+grpc_compression_algorithm grpc_call_compression_for_level(
+ grpc_call *call, grpc_compression_level level);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc
index eb49b21037..5d12ce2ecf 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -43,6 +43,7 @@
#include <grpc/support/log.h>
#include "src/core/channel/compress_filter.h"
+#include "src/core/surface/call.h"
#include "src/cpp/common/create_auth_context.h"
namespace grpc {
@@ -197,7 +198,7 @@ bool ServerContext::IsCancelled() const {
void ServerContext::set_compression_level(grpc_compression_level level) {
const grpc_compression_algorithm algorithm_for_level =
- grpc_compression_algorithm_for_level(level);
+ grpc_call_compression_for_level(call_, level);
set_compression_algorithm(algorithm_for_level);
}
diff --git a/test/core/compression/compression_test.c b/test/core/compression/compression_test.c
index 26d7b2b6cc..5d8231fd7f 100644
--- a/test/core/compression/compression_test.c
+++ b/test/core/compression/compression_test.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -93,18 +93,98 @@ static void test_compression_algorithm_name(void) {
}
static void test_compression_algorithm_for_level(void) {
- size_t i;
- grpc_compression_level levels[] = {
- GRPC_COMPRESS_LEVEL_NONE, GRPC_COMPRESS_LEVEL_LOW,
- GRPC_COMPRESS_LEVEL_MED, GRPC_COMPRESS_LEVEL_HIGH};
- grpc_compression_algorithm algorithms[] = {
- GRPC_COMPRESS_NONE, GRPC_COMPRESS_DEFLATE, GRPC_COMPRESS_DEFLATE,
- GRPC_COMPRESS_DEFLATE};
gpr_log(GPR_DEBUG, "test_compression_algorithm_for_level");
- for (i = 0; i < GPR_ARRAY_SIZE(levels); i++) {
- GPR_ASSERT(algorithms[i] ==
- grpc_compression_algorithm_for_level(levels[i]));
+ {
+ /* accept only identity (aka none) */
+ uint32_t accepted_encodings = 0;
+ GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_NONE); /* always */
+
+ GPR_ASSERT(GRPC_COMPRESS_NONE ==
+ grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_NONE,
+ accepted_encodings));
+
+ GPR_ASSERT(GRPC_COMPRESS_NONE ==
+ grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_LOW,
+ accepted_encodings));
+
+ GPR_ASSERT(GRPC_COMPRESS_NONE ==
+ grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_MED,
+ accepted_encodings));
+
+ GPR_ASSERT(GRPC_COMPRESS_NONE ==
+ grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_HIGH,
+ accepted_encodings));
+ }
+
+ {
+ /* accept only gzip */
+ uint32_t accepted_encodings = 0;
+ GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_NONE); /* always */
+ GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_GZIP);
+
+ GPR_ASSERT(GRPC_COMPRESS_NONE ==
+ grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_NONE,
+ accepted_encodings));
+
+ GPR_ASSERT(GRPC_COMPRESS_GZIP ==
+ grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_LOW,
+ accepted_encodings));
+
+ GPR_ASSERT(GRPC_COMPRESS_GZIP ==
+ grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_MED,
+ accepted_encodings));
+
+ GPR_ASSERT(GRPC_COMPRESS_GZIP ==
+ grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_HIGH,
+ accepted_encodings));
+ }
+
+ {
+ /* accept only deflate */
+ uint32_t accepted_encodings = 0;
+ GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_NONE); /* always */
+ GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_DEFLATE);
+
+ GPR_ASSERT(GRPC_COMPRESS_NONE ==
+ grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_NONE,
+ accepted_encodings));
+
+ GPR_ASSERT(GRPC_COMPRESS_DEFLATE ==
+ grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_LOW,
+ accepted_encodings));
+
+ GPR_ASSERT(GRPC_COMPRESS_DEFLATE ==
+ grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_MED,
+ accepted_encodings));
+
+ GPR_ASSERT(GRPC_COMPRESS_DEFLATE ==
+ grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_HIGH,
+ accepted_encodings));
+ }
+
+ {
+ /* accept gzip and deflate */
+ uint32_t accepted_encodings = 0;
+ GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_NONE); /* always */
+ GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_GZIP);
+ GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_DEFLATE);
+
+ GPR_ASSERT(GRPC_COMPRESS_NONE ==
+ grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_NONE,
+ accepted_encodings));
+
+ GPR_ASSERT(GRPC_COMPRESS_GZIP ==
+ grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_LOW,
+ accepted_encodings));
+
+ GPR_ASSERT(GRPC_COMPRESS_DEFLATE ==
+ grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_MED,
+ accepted_encodings));
+
+ GPR_ASSERT(GRPC_COMPRESS_DEFLATE ==
+ grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_HIGH,
+ accepted_encodings));
}
}