Split request matching into a single datastructure

pull/2470/head
Craig Tiller 10 years ago
parent 0804d6b6b2
commit 729b35a59e
  1. 255
      src/core/surface/server.c

@ -51,8 +51,6 @@
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
typedef enum { PENDING_START, CALL_LIST_COUNT } call_list;
typedef struct listener {
void *arg;
void (*start)(grpc_server *server, void *arg, grpc_pollset **pollsets,
@ -94,14 +92,6 @@ typedef struct requested_call {
} data;
} requested_call;
struct registered_method {
char *method;
char *host;
call_data *pending;
requested_call *requests;
registered_method *next;
};
typedef struct channel_registered_method {
registered_method *server_registered_method;
grpc_mdstr *method;
@ -130,44 +120,6 @@ typedef struct shutdown_tag {
grpc_cq_completion completion;
} shutdown_tag;
struct grpc_server {
size_t channel_filter_count;
const grpc_channel_filter **channel_filters;
grpc_channel_args *channel_args;
grpc_completion_queue **cqs;
grpc_pollset **pollsets;
size_t cq_count;
/* The two following mutexes control access to server-state
mu_global controls access to non-call-related state (e.g., channel state)
mu_call controls access to call-related state (e.g., the call lists)
If they are ever required to be nested, you must lock mu_global
before mu_call. This is currently used in shutdown processing
(grpc_server_shutdown_and_notify and maybe_finish_shutdown) */
gpr_mu mu_global; /* mutex for server and channel state */
gpr_mu mu_call; /* mutex for call-specific state */
registered_method *registered_methods;
requested_call *requests;
gpr_uint8 shutdown;
gpr_uint8 shutdown_published;
size_t num_shutdown_tags;
shutdown_tag *shutdown_tags;
call_data *lists[CALL_LIST_COUNT];
channel_data root_channel_data;
listener *listeners;
int listeners_destroyed;
gpr_refcount internal_refcount;
/** when did we print the last shutdown progress message */
gpr_timespec last_shutdown_message_time;
};
typedef enum {
/* waiting for metadata */
NOT_STARTED,
@ -179,6 +131,8 @@ typedef enum {
ZOMBIED
} call_state;
typedef struct request_matcher request_matcher;
struct call_data {
grpc_call *call;
@ -201,8 +155,20 @@ struct call_data {
grpc_iomgr_closure server_on_recv;
grpc_iomgr_closure kill_zombie_closure;
call_data **root[CALL_LIST_COUNT];
call_link links[CALL_LIST_COUNT];
call_data *pending_next;
};
struct request_matcher {
call_data *pending_head;
call_data *pending_tail;
requested_call *requests;
};
struct registered_method {
char *method;
char *host;
request_matcher request_matcher;
registered_method *next;
};
typedef struct {
@ -210,6 +176,43 @@ typedef struct {
size_t num_channels;
} channel_broadcaster;
struct grpc_server {
size_t channel_filter_count;
const grpc_channel_filter **channel_filters;
grpc_channel_args *channel_args;
grpc_completion_queue **cqs;
grpc_pollset **pollsets;
size_t cq_count;
/* The two following mutexes control access to server-state
mu_global controls access to non-call-related state (e.g., channel state)
mu_call controls access to call-related state (e.g., the call lists)
If they are ever required to be nested, you must lock mu_global
before mu_call. This is currently used in shutdown processing
(grpc_server_shutdown_and_notify and maybe_finish_shutdown) */
gpr_mu mu_global; /* mutex for server and channel state */
gpr_mu mu_call; /* mutex for call-specific state */
registered_method *registered_methods;
request_matcher unregistered_request_matcher;
gpr_uint8 shutdown;
gpr_uint8 shutdown_published;
size_t num_shutdown_tags;
shutdown_tag *shutdown_tags;
channel_data root_channel_data;
listener *listeners;
int listeners_destroyed;
gpr_refcount internal_refcount;
/** when did we print the last shutdown progress message */
gpr_timespec last_shutdown_message_time;
};
#define SERVER_FROM_CALL_ELEM(elem) \
(((channel_data *)(elem)->channel_data)->server)
@ -220,7 +223,9 @@ static void fail_call(grpc_server *server, requested_call *rc);
hold mu_call */
static void maybe_finish_shutdown(grpc_server *server);
/* channel broadcaster */
/*
* channel broadcaster
*/
/* assumes server locked */
static void channel_broadcaster_init(grpc_server *s, channel_broadcaster *cb) {
@ -281,55 +286,35 @@ static void channel_broadcaster_shutdown(channel_broadcaster *cb,
gpr_free(cb->channels);
}
/* call list */
/*
* request_matcher
*/
static int call_list_join(call_data **root, call_data *call, call_list list) {
GPR_ASSERT(!call->root[list]);
call->root[list] = root;
if (!*root) {
*root = call;
call->links[list].next = call->links[list].prev = call;
} else {
call->links[list].next = *root;
call->links[list].prev = (*root)->links[list].prev;
call->links[list].next->links[list].prev =
call->links[list].prev->links[list].next = call;
}
return 1;
static void request_matcher_init(request_matcher *request_matcher) {
memset(request_matcher, 0, sizeof(*request_matcher));
}
static call_data *call_list_remove_head(call_data **root, call_list list) {
call_data *out = *root;
if (out) {
out->root[list] = NULL;
if (out->links[list].next == out) {
*root = NULL;
} else {
*root = out->links[list].next;
out->links[list].next->links[list].prev = out->links[list].prev;
out->links[list].prev->links[list].next = out->links[list].next;
}
}
return out;
static void kill_zombie(void *elem, int success) {
grpc_call_destroy(grpc_call_from_top_element(elem));
}
static int call_list_remove(call_data *call, call_list list) {
call_data **root = call->root[list];
if (root == NULL) return 0;
call->root[list] = NULL;
if (*root == call) {
*root = call->links[list].next;
if (*root == call) {
*root = NULL;
return 1;
}
static void request_matcher_zombify_all_pending_calls(
request_matcher *request_matcher) {
while (request_matcher->pending_head) {
call_data *calld = request_matcher->pending_head;
request_matcher->pending_head = calld->pending_next;
calld->state = ZOMBIED;
grpc_iomgr_closure_init(
&calld->kill_zombie_closure, kill_zombie,
grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
grpc_iomgr_add_callback(&calld->kill_zombie_closure);
}
GPR_ASSERT(*root != call);
call->links[list].next->links[list].prev = call->links[list].prev;
call->links[list].prev->links[list].next = call->links[list].next;
return 1;
}
/*
* server proper
*/
static void server_ref(grpc_server *server) {
gpr_ref(&server->internal_refcount);
}
@ -391,20 +376,25 @@ static void destroy_channel(channel_data *chand) {
}
static void finish_start_new_rpc(grpc_server *server, grpc_call_element *elem,
call_data **pending_root,
requested_call **requests) {
request_matcher *request_matcher) {
requested_call *rc;
call_data *calld = elem->call_data;
gpr_mu_lock(&server->mu_call);
rc = *requests;
rc = request_matcher->requests;
if (rc == NULL) {
gpr_mu_lock(&calld->mu_state);
calld->state = PENDING;
gpr_mu_unlock(&calld->mu_state);
call_list_join(pending_root, calld, PENDING_START);
if (request_matcher->pending_head == NULL) {
request_matcher->pending_tail = request_matcher->pending_head = calld;
} else {
request_matcher->pending_tail->pending_next = calld;
request_matcher->pending_tail = calld;
}
calld->pending_next = NULL;
gpr_mu_unlock(&server->mu_call);
} else {
*requests = rc->next;
request_matcher->requests = rc->next;
gpr_mu_lock(&calld->mu_state);
calld->state = ACTIVATED;
gpr_mu_unlock(&calld->mu_state);
@ -431,8 +421,8 @@ static void start_new_rpc(grpc_call_element *elem) {
if (!rm) break;
if (rm->host != calld->host) continue;
if (rm->method != calld->path) continue;
finish_start_new_rpc(server, elem, &rm->server_registered_method->pending,
&rm->server_registered_method->requests);
finish_start_new_rpc(server, elem,
&rm->server_registered_method->request_matcher);
return;
}
/* check for a wildcard method definition (no host set) */
@ -443,17 +433,12 @@ static void start_new_rpc(grpc_call_element *elem) {
if (!rm) break;
if (rm->host != NULL) continue;
if (rm->method != calld->path) continue;
finish_start_new_rpc(server, elem, &rm->server_registered_method->pending,
&rm->server_registered_method->requests);
finish_start_new_rpc(server, elem,
&rm->server_registered_method->request_matcher);
return;
}
}
finish_start_new_rpc(server, elem, &server->lists[PENDING_START],
&server->requests);
}
static void kill_zombie(void *elem, int success) {
grpc_call_destroy(grpc_call_from_top_element(elem));
finish_start_new_rpc(server, elem, &server->unregistered_request_matcher);
}
static int num_listeners(grpc_server *server) {
@ -526,7 +511,6 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
static void server_on_recv(void *ptr, int success) {
grpc_call_element *elem = ptr;
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
if (success && !calld->got_initial_metadata) {
size_t i;
@ -571,11 +555,8 @@ static void server_on_recv(void *ptr, int success) {
} else if (calld->state == PENDING) {
calld->state = ZOMBIED;
gpr_mu_unlock(&calld->mu_state);
gpr_mu_lock(&chand->server->mu_call);
call_list_remove(calld, PENDING_START);
gpr_mu_unlock(&chand->server->mu_call);
grpc_iomgr_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
grpc_iomgr_add_callback(&calld->kill_zombie_closure);
/* zombied call will be destroyed when it's removed from the pending
queue... later */
} else {
gpr_mu_unlock(&calld->mu_state);
}
@ -653,11 +634,7 @@ static void destroy_call_elem(grpc_call_element *elem) {
channel_data *chand = elem->channel_data;
call_data *calld = elem->call_data;
if (calld->state == PENDING) {
gpr_mu_lock(&chand->server->mu_call);
call_list_remove(elem->call_data, PENDING_START);
gpr_mu_unlock(&chand->server->mu_call);
}
GPR_ASSERT(calld->state != PENDING);
if (calld->host) {
GRPC_MDSTR_UNREF(calld->host);
@ -764,6 +741,8 @@ grpc_server *grpc_server_create_from_filters(grpc_channel_filter **filters,
server->root_channel_data.next = server->root_channel_data.prev =
&server->root_channel_data;
request_matcher_init(&server->unregistered_request_matcher);
/* Server filter stack is:
server_surface_filter - for making surface API calls
@ -811,6 +790,7 @@ void *grpc_server_register_method(grpc_server *server, const char *method,
}
m = gpr_malloc(sizeof(registered_method));
memset(m, 0, sizeof(*m));
request_matcher_init(&m->request_matcher);
m->method = gpr_strdup(method);
m->host = gpr_strdup(host);
m->next = server->registered_methods;
@ -954,15 +934,18 @@ void grpc_server_shutdown_and_notify(grpc_server *server,
/* collect all unregistered then registered calls */
gpr_mu_lock(&server->mu_call);
requests = server->requests;
server->requests = NULL;
requests = server->unregistered_request_matcher.requests;
server->unregistered_request_matcher.requests = NULL;
request_matcher_zombify_all_pending_calls(
&server->unregistered_request_matcher);
for (rm = server->registered_methods; rm; rm = rm->next) {
while (rm->requests != NULL) {
requested_call *c = rm->requests;
rm->requests = c->next;
while (rm->request_matcher.requests != NULL) {
requested_call *c = rm->request_matcher.requests;
rm->request_matcher.requests = c->next;
c->next = requests;
requests = c;
}
request_matcher_zombify_all_pending_calls(&rm->request_matcher);
}
gpr_mu_unlock(&server->mu_call);
@ -1037,7 +1020,7 @@ void grpc_server_add_listener(grpc_server *server, void *arg,
static grpc_call_error queue_call_request(grpc_server *server,
requested_call *rc) {
call_data *calld = NULL;
requested_call **requests = NULL;
request_matcher *request_matcher = NULL;
gpr_mu_lock(&server->mu_call);
if (server->shutdown) {
gpr_mu_unlock(&server->mu_call);
@ -1046,27 +1029,35 @@ static grpc_call_error queue_call_request(grpc_server *server,
}
switch (rc->type) {
case BATCH_CALL:
calld =
call_list_remove_head(&server->lists[PENDING_START], PENDING_START);
requests = &server->requests;
request_matcher = &server->unregistered_request_matcher;
break;
case REGISTERED_CALL:
calld = call_list_remove_head(
&rc->data.registered.registered_method->pending, PENDING_START);
requests = &rc->data.registered.registered_method->requests;
request_matcher = &rc->data.registered.registered_method->request_matcher;
break;
}
if (request_matcher->pending_head != NULL) {
calld = request_matcher->pending_head;
request_matcher->pending_head = calld->pending_next;
}
if (calld != NULL) {
gpr_mu_unlock(&server->mu_call);
gpr_mu_lock(&calld->mu_state);
if (calld->state == ZOMBIED) {
gpr_mu_unlock(&calld->mu_state);
grpc_iomgr_closure_init(
&calld->kill_zombie_closure, kill_zombie,
grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
grpc_iomgr_add_callback(&calld->kill_zombie_closure);
return queue_call_request(server, rc); /* retry */
}
GPR_ASSERT(calld->state == PENDING);
calld->state = ACTIVATED;
gpr_mu_unlock(&calld->mu_state);
begin_call(server, calld, rc);
return GRPC_CALL_OK;
} else {
rc->next = *requests;
*requests = rc;
rc->next = request_matcher->requests;
request_matcher->requests = rc;
gpr_mu_unlock(&server->mu_call);
return GRPC_CALL_OK;
}

Loading…
Cancel
Save