Add grpc_json_tree to handle refcounting for channel arg.

pull/8617/head
Mark D. Roth 8 years ago
parent e528993d97
commit 896d92568b
  1. 8
      src/core/ext/client_channel/client_channel.c
  2. 5
      src/core/lib/channel/message_size_filter.c
  3. 59
      src/core/lib/json/json.c
  4. 19
      src/core/lib/json/json.h
  5. 23
      src/core/lib/transport/method_config.c
  6. 2
      src/core/lib/transport/method_config.h
  7. 22
      test/core/end2end/connection_refused_test.c
  8. 23
      test/core/end2end/tests/cancel_after_accept.c
  9. 47
      test/core/end2end/tests/max_message_length.c

@ -104,7 +104,8 @@ static void *method_config_convert_value(const grpc_json *json) {
if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) { if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) {
return NULL; return NULL;
} }
wait_for_ready = field->type == GRPC_JSON_TRUE; wait_for_ready = field->type == GRPC_JSON_TRUE
? WAIT_FOR_READY_TRUE : WAIT_FOR_READY_FALSE;
} else if (strcmp(field->key, "timeout") == 0) { } else if (strcmp(field->key, "timeout") == 0) {
if (timeout.tv_sec > 0 || timeout.tv_nsec > 0) return NULL; // Duplicate. if (timeout.tv_sec > 0 || timeout.tv_nsec > 0) return NULL; // Duplicate.
if (field->type != GRPC_JSON_OBJECT) return NULL; if (field->type != GRPC_JSON_OBJECT) return NULL;
@ -312,9 +313,10 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
grpc_channel_args_find(lb_policy_args.args, GRPC_ARG_SERVICE_CONFIG); grpc_channel_args_find(lb_policy_args.args, GRPC_ARG_SERVICE_CONFIG);
if (channel_arg != NULL) { if (channel_arg != NULL) {
GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
grpc_json_tree* json_tree = channel_arg->value.pointer.p;
method_params_table = grpc_method_config_table_create_from_json( method_params_table = grpc_method_config_table_create_from_json(
(grpc_json *)channel_arg->value.pointer.p, json_tree->root, method_config_convert_value,
method_config_convert_value, &method_parameters_vtable); &method_parameters_vtable);
} }
grpc_channel_args_destroy(chand->resolver_result); grpc_channel_args_destroy(chand->resolver_result);
chand->resolver_result = NULL; chand->resolver_result = NULL;

@ -234,9 +234,10 @@ static void init_channel_elem(grpc_exec_ctx* exec_ctx,
grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG); grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG);
if (channel_arg != NULL) { if (channel_arg != NULL) {
GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
grpc_json_tree* json_tree = channel_arg->value.pointer.p;
chand->method_limit_table = grpc_method_config_table_create_from_json( chand->method_limit_table = grpc_method_config_table_create_from_json(
(grpc_json*)channel_arg->value.pointer.p, json_tree->root, method_config_convert_value,
method_config_convert_value, &message_size_limits_vtable); &message_size_limits_vtable);
} }
} }

@ -34,6 +34,8 @@
#include <string.h> #include <string.h>
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
@ -62,3 +64,60 @@ void grpc_json_destroy(grpc_json *json) {
gpr_free(json); gpr_free(json);
} }
int grpc_json_cmp(const grpc_json* json1, const grpc_json* json2) {
if (json1 == NULL) {
if (json2 != NULL) return 1;
return 0; // Both NULL.
} else {
if (json2 == NULL) return -1;
}
// Compare type.
if (json1->type > json2->type) return 1;
if (json1->type < json2->type) return -1;
// Compare key.
if (json1->key == NULL) {
if (json2->key != NULL) return -1;
} else {
if (json2->key == NULL) return 1;
int retval = strcmp(json1->key, json2->key);
if (retval != 0) return retval;
}
// Compare value.
if (json1->value == NULL) {
if (json2->value != NULL) return -1;
} else {
if (json2->value == NULL) return 1;
int retval = strcmp(json1->value, json2->value);
if (retval != 0) return retval;
}
// Recursively compare the next pointer.
int retval = grpc_json_cmp(json1->next, json2->next);
if (retval != 0) return retval;
// Recursively compare the child pointer.
retval = grpc_json_cmp(json1->child, json2->child);
if (retval != 0) return retval;
// Both are the same.
return 0;
}
grpc_json_tree* grpc_json_tree_create(const char* json_string) {
grpc_json_tree* tree = gpr_malloc(sizeof(*tree));
tree->string = gpr_strdup(json_string);
tree->root = grpc_json_parse_string(tree->string);
gpr_ref_init(&tree->refs, 1);
return tree;
}
grpc_json_tree* grpc_json_tree_ref(grpc_json_tree* tree) {
gpr_ref(&tree->refs);
return tree;
}
void grpc_json_tree_unref(grpc_json_tree* tree) {
if (gpr_unref(&tree->refs)) {
grpc_json_destroy(tree->root);
gpr_free(tree->string);
gpr_free(tree);
}
}

@ -36,6 +36,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <grpc/support/sync.h>
#include "src/core/lib/json/json_common.h" #include "src/core/lib/json/json_common.h"
/* A tree-like structure to hold json values. The key and value pointers /* A tree-like structure to hold json values. The key and value pointers
@ -85,4 +87,21 @@ char *grpc_json_dump_to_string(grpc_json *json, int indent);
grpc_json *grpc_json_create(grpc_json_type type); grpc_json *grpc_json_create(grpc_json_type type);
void grpc_json_destroy(grpc_json *json); void grpc_json_destroy(grpc_json *json);
/* Compares two JSON trees. */
int grpc_json_cmp(const grpc_json* json1, const grpc_json* json2);
/* A wrapper that contains the string used for underlying allocation and
is refcounted. */
typedef struct {
grpc_json* root;
char* string;
gpr_refcount refs;
} grpc_json_tree;
/* Creates a copy of \a json_string. */
grpc_json_tree* grpc_json_tree_create(const char* json_string);
grpc_json_tree* grpc_json_tree_ref(grpc_json_tree* tree);
void grpc_json_tree_unref(grpc_json_tree* tree);
#endif /* GRPC_CORE_LIB_JSON_JSON_H */ #endif /* GRPC_CORE_LIB_JSON_JSON_H */

@ -460,3 +460,26 @@ grpc_mdstr_hash_table* grpc_method_config_table_create_from_json(
} }
return method_config_table; return method_config_table;
} }
static void* copy_json_tree(void* t) { return grpc_json_tree_ref(t); }
static void destroy_json_tree(void* t) { grpc_json_tree_unref(t); }
static int cmp_json_tree(void* t1, void* t2) {
grpc_json_tree* tree1 = t1;
grpc_json_tree* tree2 = t2;
return grpc_json_cmp(tree1->root, tree2->root);
}
static grpc_arg_pointer_vtable service_config_arg_vtable = {
copy_json_tree, destroy_json_tree, cmp_json_tree};
grpc_arg grpc_service_config_create_channel_arg(
grpc_json_tree* service_config) {
grpc_arg arg;
arg.type = GRPC_ARG_POINTER;
arg.key = GRPC_ARG_SERVICE_CONFIG;
arg.value.pointer.p = service_config;
arg.value.pointer.vtable = &service_config_arg_vtable;
return arg;
}

@ -140,4 +140,6 @@ grpc_mdstr_hash_table* grpc_method_config_table_create_from_json(
void* (*create_value)(const grpc_json* method_config_json), void* (*create_value)(const grpc_json* method_config_json),
const grpc_mdstr_hash_table_vtable* vtable); const grpc_mdstr_hash_table_vtable* vtable);
grpc_arg grpc_service_config_create_channel_arg(grpc_json_tree* service_config);
#endif /* GRPC_CORE_LIB_TRANSPORT_METHOD_CONFIG_H */ #endif /* GRPC_CORE_LIB_TRANSPORT_METHOD_CONFIG_H */

@ -76,18 +76,18 @@ static void run_test(bool wait_for_ready, bool use_service_config) {
grpc_channel_args *args = NULL; grpc_channel_args *args = NULL;
if (use_service_config) { if (use_service_config) {
GPR_ASSERT(wait_for_ready); GPR_ASSERT(wait_for_ready);
grpc_method_config_table_entry entry = { grpc_json_tree* service_config_json = grpc_json_tree_create(
grpc_mdstr_from_string("/service/method"), "{\n"
grpc_method_config_create(&wait_for_ready, NULL, NULL, NULL), " \"method_config\": [ {\n"
}; " \"name\": [\n"
grpc_method_config_table *method_config_table = " { \"service\": \"service\", \"method\": \"method\" }\n"
grpc_method_config_table_create(1, &entry); " ],\n"
GRPC_MDSTR_UNREF(entry.method_name); " \"wait_for_ready\": true\n"
grpc_method_config_unref(entry.method_config); " } ]\n"
grpc_arg arg = "}");
grpc_method_config_table_create_channel_arg(method_config_table); grpc_arg arg = grpc_service_config_create_channel_arg(service_config_json);
args = grpc_channel_args_copy_and_add(args, &arg, 1); args = grpc_channel_args_copy_and_add(args, &arg, 1);
grpc_method_config_table_unref(method_config_table); grpc_json_tree_unref(service_config_json);
} }
/* create a call, channel to a port which will refuse connection */ /* create a call, channel to a port which will refuse connection */

@ -132,19 +132,18 @@ static void test_cancel_after_accept(grpc_end2end_test_config config,
grpc_channel_args *args = NULL; grpc_channel_args *args = NULL;
if (use_service_config) { if (use_service_config) {
gpr_timespec timeout = {5, 0, GPR_TIMESPAN}; grpc_json_tree* service_config_json = grpc_json_tree_create(
grpc_method_config_table_entry entry = { "{\n"
grpc_mdstr_from_string("/service/method"), " \"method_config\": [ {\n"
grpc_method_config_create(NULL, &timeout, NULL, NULL), " \"name\": [\n"
}; " { \"service\": \"service\", \"method\": \"method\" }\n"
grpc_method_config_table *method_config_table = " ],\n"
grpc_method_config_table_create(1, &entry); " \"timeout\": { \"seconds\": 5 }\n"
GRPC_MDSTR_UNREF(entry.method_name); " } ]\n"
grpc_method_config_unref(entry.method_config); "}");
grpc_arg arg = grpc_arg arg = grpc_service_config_create_channel_arg(service_config_json);
grpc_method_config_table_create_channel_arg(method_config_table);
args = grpc_channel_args_copy_and_add(args, &arg, 1); args = grpc_channel_args_copy_and_add(args, &arg, 1);
grpc_method_config_table_unref(method_config_table); grpc_json_tree_unref(service_config_json);
} }
grpc_end2end_test_fixture f = grpc_end2end_test_fixture f =

@ -137,19 +137,18 @@ static void test_max_message_length_on_request(grpc_end2end_test_config config,
if (use_service_config) { if (use_service_config) {
// We don't currently support service configs on the server side. // We don't currently support service configs on the server side.
GPR_ASSERT(send_limit); GPR_ASSERT(send_limit);
int32_t max_request_message_bytes = 5; grpc_json_tree* service_config_json = grpc_json_tree_create(
grpc_method_config_table_entry entry = { "{\n"
grpc_mdstr_from_string("/service/method"), " \"method_config\": [ {\n"
grpc_method_config_create(NULL, NULL, &max_request_message_bytes, NULL), " \"name\": [\n"
}; " { \"service\": \"service\", \"method\": \"method\" }\n"
grpc_method_config_table *method_config_table = " ],\n"
grpc_method_config_table_create(1, &entry); " \"max_request_message_bytes\": 5\n"
GRPC_MDSTR_UNREF(entry.method_name); " } ]\n"
grpc_method_config_unref(entry.method_config); "}");
grpc_arg arg = grpc_arg arg = grpc_service_config_create_channel_arg(service_config_json);
grpc_method_config_table_create_channel_arg(method_config_table);
client_args = grpc_channel_args_copy_and_add(NULL, &arg, 1); client_args = grpc_channel_args_copy_and_add(NULL, &arg, 1);
grpc_method_config_table_unref(method_config_table); grpc_json_tree_unref(service_config_json);
} else { } else {
// Set limit via channel args. // Set limit via channel args.
grpc_arg arg; grpc_arg arg;
@ -309,20 +308,18 @@ static void test_max_message_length_on_response(grpc_end2end_test_config config,
if (use_service_config) { if (use_service_config) {
// We don't currently support service configs on the server side. // We don't currently support service configs on the server side.
GPR_ASSERT(!send_limit); GPR_ASSERT(!send_limit);
int32_t max_response_message_bytes = 5; grpc_json_tree* service_config_json = grpc_json_tree_create(
grpc_method_config_table_entry entry = { "{\n"
grpc_mdstr_from_string("/service/method"), " \"method_config\": [ {\n"
grpc_method_config_create(NULL, NULL, NULL, " \"name\": [\n"
&max_response_message_bytes), " { \"service\": \"service\", \"method\": \"method\" }\n"
}; " ],\n"
grpc_method_config_table *method_config_table = " \"max_response_message_bytes\": 5\n"
grpc_method_config_table_create(1, &entry); " } ]\n"
GRPC_MDSTR_UNREF(entry.method_name); "}");
grpc_method_config_unref(entry.method_config); grpc_arg arg = grpc_service_config_create_channel_arg(service_config_json);
grpc_arg arg =
grpc_method_config_table_create_channel_arg(method_config_table);
client_args = grpc_channel_args_copy_and_add(NULL, &arg, 1); client_args = grpc_channel_args_copy_and_add(NULL, &arg, 1);
grpc_method_config_table_unref(method_config_table); grpc_json_tree_unref(service_config_json);
} else { } else {
// Set limit via channel args. // Set limit via channel args.
grpc_arg arg; grpc_arg arg;

Loading…
Cancel
Save