mirror of https://github.com/grpc/grpc.git
commit
594f0c43e0
433 changed files with 36123 additions and 7524 deletions
@ -0,0 +1,91 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_SUPPORT_AVL_H |
||||
#define GRPC_SUPPORT_AVL_H |
||||
|
||||
#include <grpc/support/sync.h> |
||||
|
||||
/** internal node of an AVL tree */ |
||||
typedef struct gpr_avl_node { |
||||
gpr_refcount refs; |
||||
void *key; |
||||
void *value; |
||||
struct gpr_avl_node *left; |
||||
struct gpr_avl_node *right; |
||||
long height; |
||||
} gpr_avl_node; |
||||
|
||||
typedef struct gpr_avl_vtable { |
||||
/** destroy a key */ |
||||
void (*destroy_key)(void *key); |
||||
/** copy a key, returning new value */ |
||||
void *(*copy_key)(void *key); |
||||
/** compare key1, key2; return <0 if key1 < key2,
|
||||
>0 if key1 > key2, 0 if key1 == key2 */ |
||||
long (*compare_keys)(void *key1, void *key2); |
||||
/** destroy a value */ |
||||
void (*destroy_value)(void *value); |
||||
/** copy a value */ |
||||
void *(*copy_value)(void *value); |
||||
} gpr_avl_vtable; |
||||
|
||||
/** "pointer" to an AVL tree - this is a reference
|
||||
counted object - use gpr_avl_ref to add a reference, |
||||
gpr_avl_unref when done with a reference */ |
||||
typedef struct gpr_avl { |
||||
const gpr_avl_vtable *vtable; |
||||
gpr_avl_node *root; |
||||
} gpr_avl; |
||||
|
||||
/** create an immutable AVL tree */ |
||||
gpr_avl gpr_avl_create(const gpr_avl_vtable *vtable); |
||||
/** add a reference to an existing tree - returns
|
||||
the tree as a convenience */ |
||||
gpr_avl gpr_avl_ref(gpr_avl avl); |
||||
/** remove a reference to a tree - destroying it if there
|
||||
are no references left */ |
||||
void gpr_avl_unref(gpr_avl avl); |
||||
/** return a new tree with (key, value) added to avl.
|
||||
implicitly unrefs avl to allow easy chaining. |
||||
if key exists in avl, the new tree's key entry updated |
||||
(i.e. a duplicate is not created) */ |
||||
gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value); |
||||
/** return a new tree with key deleted */ |
||||
gpr_avl gpr_avl_remove(gpr_avl avl, void *key); |
||||
/** lookup key, and return the associated value.
|
||||
does not mutate avl. |
||||
returns NULL if key is not found. */ |
||||
void *gpr_avl_get(gpr_avl avl, void *key); |
||||
|
||||
#endif |
@ -0,0 +1,141 @@ |
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head><title>Interop Test Result</title></head> |
||||
<body> |
||||
|
||||
<%def name="fill_one_test_result(shortname, resultset)"> |
||||
% if shortname in resultset: |
||||
## Because interop tests does not have runs_per_test flag, each test is |
||||
## run once. So there should only be one element for each result. |
||||
<% result = resultset[shortname][0] %> |
||||
% if result.state == 'PASSED': |
||||
<td bgcolor="green">PASS</td> |
||||
% else: |
||||
<% |
||||
tooltip = '' |
||||
if result.returncode > 0 or result.message: |
||||
if result.returncode > 0: |
||||
tooltip = 'returncode: %d ' % result.returncode |
||||
if result.message: |
||||
tooltip = '%smessage: %s' % (tooltip, result.message) |
||||
%> |
||||
% if result.state == 'FAILED': |
||||
<td bgcolor="red"> |
||||
% if tooltip: |
||||
<a href="#" data-toggle="tooltip" data-placement="auto" title="${tooltip | h}">FAIL</a></td> |
||||
% else: |
||||
FAIL</td> |
||||
% endif |
||||
% elif result.state == 'TIMEOUT': |
||||
<td bgcolor="yellow"> |
||||
% if tooltip: |
||||
<a href="#" data-toggle="tooltip" data-placement="auto" title="${tooltip | h}">TIMEOUT</a></td> |
||||
% else: |
||||
TIMEOUT</td> |
||||
% endif |
||||
% endif |
||||
% endif |
||||
% else: |
||||
<td bgcolor="magenta">Not implemented</td> |
||||
% endif |
||||
</%def> |
||||
|
||||
% if num_failures > 1: |
||||
<p><h2><font color="red">${num_failures} tests failed!</font></h2></p> |
||||
% elif num_failures: |
||||
<p><h2><font color="red">${num_failures} test failed!</font></h2></p> |
||||
% else: |
||||
<p><h2><font color="green">All tests passed!</font></h2></p> |
||||
% endif |
||||
|
||||
% if cloud_to_prod: |
||||
## Each column header is the client language. |
||||
<h2>Cloud to Prod</h2> |
||||
<table style="width:100%" border="1"> |
||||
<tr bgcolor="#00BFFF"> |
||||
<th>Client languages ►<br/>Test Cases ▼</th> |
||||
% for client_lang in client_langs: |
||||
<th>${client_lang}</th> |
||||
% endfor |
||||
</tr> |
||||
% for test_case in test_cases + auth_test_cases: |
||||
<tr><td><b>${test_case}</b></td> |
||||
% for client_lang in client_langs: |
||||
<% |
||||
if test_case in auth_test_cases: |
||||
shortname = 'cloud_to_prod_auth:%s:%s' % (client_lang, test_case) |
||||
else: |
||||
shortname = 'cloud_to_prod:%s:%s' % (client_lang, test_case) |
||||
%> |
||||
${fill_one_test_result(shortname, resultset)} |
||||
% endfor |
||||
</tr> |
||||
% endfor |
||||
</table> |
||||
% endif |
||||
|
||||
% if http2_interop: |
||||
## Each column header is the server language. |
||||
<h2>HTTP/2 Interop</h2> |
||||
<table style="width:100%" border="1"> |
||||
<tr bgcolor="#00BFFF"> |
||||
<th>Servers ►<br/>Test Cases ▼</th> |
||||
% for server_lang in server_langs: |
||||
<th>${server_lang}</th> |
||||
% endfor |
||||
% if cloud_to_prod: |
||||
<th>prod</th> |
||||
% endif |
||||
</tr> |
||||
% for test_case in http2_cases: |
||||
<tr><td><b>${test_case}</b></td> |
||||
## Fill up the cells with test result. |
||||
% for server_lang in server_langs: |
||||
<% |
||||
shortname = 'cloud_to_cloud:http2:%s_server:%s' % ( |
||||
server_lang, test_case) |
||||
%> |
||||
${fill_one_test_result(shortname, resultset)} |
||||
% endfor |
||||
% if cloud_to_prod: |
||||
<% shortname = 'cloud_to_prod:http2:%s' % test_case %> |
||||
${fill_one_test_result(shortname, resultset)} |
||||
% endif |
||||
</tr> |
||||
% endfor |
||||
</table> |
||||
% endif |
||||
|
||||
% if server_langs: |
||||
% for test_case in test_cases: |
||||
## Each column header is the client language. |
||||
<h2>${test_case}</h2> |
||||
<table style="width:100%" border="1"> |
||||
<tr bgcolor="#00BFFF"> |
||||
<th>Client languages ►<br/>Server languages ▼</th> |
||||
% for client_lang in client_langs: |
||||
<th>${client_lang}</th> |
||||
% endfor |
||||
</tr> |
||||
## Each row head is the server language. |
||||
% for server_lang in server_langs: |
||||
<tr> |
||||
<td><b>${server_lang}</b></td> |
||||
% for client_lang in client_langs: |
||||
<% |
||||
shortname = 'cloud_to_cloud:%s:%s_server:%s' % ( |
||||
client_lang, server_lang, test_case) |
||||
%> |
||||
${fill_one_test_result(shortname, resultset)} |
||||
% endfor |
||||
</tr> |
||||
% endfor |
||||
</table> |
||||
% endfor |
||||
% endif |
||||
|
||||
<script> |
||||
$(document).ready(function(){$('[data-toggle="tooltip"]').tooltip();}); |
||||
</script> |
||||
</body> |
||||
</html> |
@ -0,0 +1,283 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/channel/subchannel_call_holder.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
|
||||
#include "src/core/profiling/timers.h" |
||||
|
||||
#define GET_CALL(holder) \ |
||||
((grpc_subchannel_call *)(gpr_atm_acq_load(&(holder)->subchannel_call))) |
||||
|
||||
#define CANCELLED_CALL ((grpc_subchannel_call *)1) |
||||
|
||||
static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *holder, |
||||
int success); |
||||
static void call_ready(grpc_exec_ctx *exec_ctx, void *holder, int success); |
||||
static void retry_ops(grpc_exec_ctx *exec_ctx, void *retry_ops_args, |
||||
int success); |
||||
|
||||
static void add_waiting_locked(grpc_subchannel_call_holder *holder, |
||||
grpc_transport_stream_op *op); |
||||
static void fail_locked(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder); |
||||
static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder); |
||||
|
||||
void grpc_subchannel_call_holder_init( |
||||
grpc_subchannel_call_holder *holder, |
||||
grpc_subchannel_call_holder_pick_subchannel pick_subchannel, |
||||
void *pick_subchannel_arg) { |
||||
gpr_atm_rel_store(&holder->subchannel_call, 0); |
||||
holder->pick_subchannel = pick_subchannel; |
||||
holder->pick_subchannel_arg = pick_subchannel_arg; |
||||
gpr_mu_init(&holder->mu); |
||||
holder->subchannel = NULL; |
||||
holder->waiting_ops = NULL; |
||||
holder->waiting_ops_count = 0; |
||||
holder->waiting_ops_capacity = 0; |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; |
||||
} |
||||
|
||||
void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder) { |
||||
grpc_subchannel_call *call = GET_CALL(holder); |
||||
if (call != NULL && call != CANCELLED_CALL) { |
||||
GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "holder"); |
||||
} |
||||
GPR_ASSERT(holder->creation_phase == |
||||
GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING); |
||||
gpr_mu_destroy(&holder->mu); |
||||
GPR_ASSERT(holder->waiting_ops_count == 0); |
||||
gpr_free(holder->waiting_ops); |
||||
} |
||||
|
||||
void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder, |
||||
grpc_transport_stream_op *op) { |
||||
/* try to (atomically) get the call */ |
||||
grpc_subchannel_call *call = GET_CALL(holder); |
||||
GPR_TIMER_BEGIN("grpc_subchannel_call_holder_perform_op", 0); |
||||
if (call == CANCELLED_CALL) { |
||||
grpc_transport_stream_op_finish_with_failure(exec_ctx, op); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
return; |
||||
} |
||||
if (call != NULL) { |
||||
grpc_subchannel_call_process_op(exec_ctx, call, op); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
return; |
||||
} |
||||
/* we failed; lock and figure out what to do */ |
||||
gpr_mu_lock(&holder->mu); |
||||
retry: |
||||
/* need to recheck that another thread hasn't set the call */ |
||||
call = GET_CALL(holder); |
||||
if (call == CANCELLED_CALL) { |
||||
gpr_mu_unlock(&holder->mu); |
||||
grpc_transport_stream_op_finish_with_failure(exec_ctx, op); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
return; |
||||
} |
||||
if (call != NULL) { |
||||
gpr_mu_unlock(&holder->mu); |
||||
grpc_subchannel_call_process_op(exec_ctx, call, op); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
return; |
||||
} |
||||
/* if this is a cancellation, then we can raise our cancelled flag */ |
||||
if (op->cancel_with_status != GRPC_STATUS_OK) { |
||||
if (!gpr_atm_rel_cas(&holder->subchannel_call, 0, 1)) { |
||||
goto retry; |
||||
} else { |
||||
switch (holder->creation_phase) { |
||||
case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING: |
||||
fail_locked(exec_ctx, holder); |
||||
break; |
||||
case GRPC_SUBCHANNEL_CALL_HOLDER_CREATING_CALL: |
||||
grpc_subchannel_cancel_create_call(exec_ctx, holder->subchannel, |
||||
&holder->subchannel_call); |
||||
break; |
||||
case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL: |
||||
holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg, NULL, |
||||
&holder->subchannel, NULL); |
||||
break; |
||||
} |
||||
gpr_mu_unlock(&holder->mu); |
||||
grpc_transport_stream_op_finish_with_failure(exec_ctx, op); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
return; |
||||
} |
||||
} |
||||
/* if we don't have a subchannel, try to get one */ |
||||
if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING && |
||||
holder->subchannel == NULL && op->send_initial_metadata != NULL) { |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL; |
||||
grpc_closure_init(&holder->next_step, subchannel_ready, holder); |
||||
if (holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg, |
||||
op->send_initial_metadata, &holder->subchannel, |
||||
&holder->next_step)) { |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; |
||||
} |
||||
} |
||||
/* if we've got a subchannel, then let's ask it to create a call */ |
||||
if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING && |
||||
holder->subchannel != NULL) { |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_CREATING_CALL; |
||||
grpc_closure_init(&holder->next_step, call_ready, holder); |
||||
if (grpc_subchannel_create_call(exec_ctx, holder->subchannel, |
||||
holder->pollset, &holder->subchannel_call, |
||||
&holder->next_step)) { |
||||
/* got one immediately - continue the op (and any waiting ops) */ |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; |
||||
retry_waiting_locked(exec_ctx, holder); |
||||
goto retry; |
||||
} |
||||
} |
||||
/* nothing to be done but wait */ |
||||
add_waiting_locked(holder, op); |
||||
gpr_mu_unlock(&holder->mu); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
} |
||||
|
||||
static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, int success) { |
||||
grpc_subchannel_call_holder *holder = arg; |
||||
grpc_subchannel_call *call; |
||||
gpr_mu_lock(&holder->mu); |
||||
GPR_ASSERT(holder->creation_phase == |
||||
GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL); |
||||
call = GET_CALL(holder); |
||||
GPR_ASSERT(call == NULL || call == CANCELLED_CALL); |
||||
if (holder->subchannel == NULL) { |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; |
||||
fail_locked(exec_ctx, holder); |
||||
} else { |
||||
grpc_closure_init(&holder->next_step, call_ready, holder); |
||||
if (grpc_subchannel_create_call(exec_ctx, holder->subchannel, |
||||
holder->pollset, &holder->subchannel_call, |
||||
&holder->next_step)) { |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; |
||||
/* got one immediately - continue the op (and any waiting ops) */ |
||||
retry_waiting_locked(exec_ctx, holder); |
||||
} |
||||
} |
||||
gpr_mu_unlock(&holder->mu); |
||||
} |
||||
|
||||
static void call_ready(grpc_exec_ctx *exec_ctx, void *arg, int success) { |
||||
grpc_subchannel_call_holder *holder = arg; |
||||
GPR_TIMER_BEGIN("call_ready", 0); |
||||
gpr_mu_lock(&holder->mu); |
||||
GPR_ASSERT(holder->creation_phase == |
||||
GRPC_SUBCHANNEL_CALL_HOLDER_CREATING_CALL); |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; |
||||
if (GET_CALL(holder) != NULL) { |
||||
retry_waiting_locked(exec_ctx, holder); |
||||
} else { |
||||
fail_locked(exec_ctx, holder); |
||||
} |
||||
gpr_mu_unlock(&holder->mu); |
||||
GPR_TIMER_END("call_ready", 0); |
||||
} |
||||
|
||||
typedef struct { |
||||
grpc_transport_stream_op *ops; |
||||
size_t nops; |
||||
grpc_subchannel_call *call; |
||||
} retry_ops_args; |
||||
|
||||
static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder) { |
||||
retry_ops_args *a = gpr_malloc(sizeof(*a)); |
||||
a->ops = holder->waiting_ops; |
||||
a->nops = holder->waiting_ops_count; |
||||
a->call = GET_CALL(holder); |
||||
if (a->call == CANCELLED_CALL) { |
||||
gpr_free(a); |
||||
fail_locked(exec_ctx, holder); |
||||
return; |
||||
} |
||||
holder->waiting_ops = NULL; |
||||
holder->waiting_ops_count = 0; |
||||
holder->waiting_ops_capacity = 0; |
||||
GRPC_SUBCHANNEL_CALL_REF(a->call, "retry_ops"); |
||||
grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(retry_ops, a), 1); |
||||
} |
||||
|
||||
static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, int success) { |
||||
retry_ops_args *a = args; |
||||
size_t i; |
||||
for (i = 0; i < a->nops; i++) { |
||||
grpc_subchannel_call_process_op(exec_ctx, a->call, &a->ops[i]); |
||||
} |
||||
GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, a->call, "retry_ops"); |
||||
gpr_free(a->ops); |
||||
gpr_free(a); |
||||
} |
||||
|
||||
static void add_waiting_locked(grpc_subchannel_call_holder *holder, |
||||
grpc_transport_stream_op *op) { |
||||
GPR_TIMER_BEGIN("add_waiting_locked", 0); |
||||
if (holder->waiting_ops_count == holder->waiting_ops_capacity) { |
||||
holder->waiting_ops_capacity = GPR_MAX(3, 2 * holder->waiting_ops_capacity); |
||||
holder->waiting_ops = |
||||
gpr_realloc(holder->waiting_ops, holder->waiting_ops_capacity * |
||||
sizeof(*holder->waiting_ops)); |
||||
} |
||||
holder->waiting_ops[holder->waiting_ops_count++] = *op; |
||||
GPR_TIMER_END("add_waiting_locked", 0); |
||||
} |
||||
|
||||
static void fail_locked(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder) { |
||||
size_t i; |
||||
for (i = 0; i < holder->waiting_ops_count; i++) { |
||||
grpc_exec_ctx_enqueue(exec_ctx, holder->waiting_ops[i].on_complete, 0); |
||||
grpc_exec_ctx_enqueue(exec_ctx, holder->waiting_ops[i].recv_message_ready, |
||||
0); |
||||
} |
||||
holder->waiting_ops_count = 0; |
||||
} |
||||
|
||||
char *grpc_subchannel_call_holder_get_peer(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder, |
||||
grpc_channel *master) { |
||||
grpc_subchannel_call *subchannel_call = GET_CALL(holder); |
||||
|
||||
if (subchannel_call) { |
||||
return grpc_subchannel_call_get_peer(exec_ctx, subchannel_call); |
||||
} else { |
||||
return grpc_channel_get_target(master); |
||||
} |
||||
} |
@ -0,0 +1,98 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CHANNEL_SUBCHANNEL_CALL_HOLDER_H |
||||
#define GRPC_INTERNAL_CORE_CHANNEL_SUBCHANNEL_CALL_HOLDER_H |
||||
|
||||
#include "src/core/client_config/subchannel.h" |
||||
|
||||
/** Pick a subchannel for grpc_subchannel_call_holder;
|
||||
Return 1 if subchannel is available immediately (in which case on_ready |
||||
should not be called), or 0 otherwise (in which case on_ready should be |
||||
called when the subchannel is available) */ |
||||
typedef int (*grpc_subchannel_call_holder_pick_subchannel)( |
||||
grpc_exec_ctx *exec_ctx, void *arg, grpc_metadata_batch *initial_metadata, |
||||
grpc_subchannel **subchannel, grpc_closure *on_ready); |
||||
|
||||
typedef enum { |
||||
GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING, |
||||
GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL, |
||||
GRPC_SUBCHANNEL_CALL_HOLDER_CREATING_CALL |
||||
} grpc_subchannel_call_holder_creation_phase; |
||||
|
||||
/** Wrapper for holding a pointer to grpc_subchannel_call, and the
|
||||
associated machinery to create such a pointer. |
||||
Handles queueing of stream ops until a call object is ready, waiting |
||||
for initial metadata before trying to create a call object, |
||||
and handling cancellation gracefully. |
||||
|
||||
Both the channel and uchannel filter use this as their call_data. */ |
||||
typedef struct grpc_subchannel_call_holder { |
||||
/** either 0 for no call, 1 for cancelled, or a pointer to a
|
||||
grpc_subchannel_call */ |
||||
gpr_atm subchannel_call; |
||||
/** Helper function to choose the subchannel on which to create
|
||||
the call object. Channel filter delegates to the load |
||||
balancing policy (once it's ready); uchannel returns |
||||
immediately */ |
||||
grpc_subchannel_call_holder_pick_subchannel pick_subchannel; |
||||
void *pick_subchannel_arg; |
||||
|
||||
gpr_mu mu; |
||||
|
||||
grpc_subchannel_call_holder_creation_phase creation_phase; |
||||
grpc_subchannel *subchannel; |
||||
grpc_pollset *pollset; |
||||
|
||||
grpc_transport_stream_op *waiting_ops; |
||||
size_t waiting_ops_count; |
||||
size_t waiting_ops_capacity; |
||||
|
||||
grpc_closure next_step; |
||||
} grpc_subchannel_call_holder; |
||||
|
||||
void grpc_subchannel_call_holder_init( |
||||
grpc_subchannel_call_holder *holder, |
||||
grpc_subchannel_call_holder_pick_subchannel pick_subchannel, |
||||
void *pick_subchannel_arg); |
||||
void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder); |
||||
|
||||
void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder, |
||||
grpc_transport_stream_op *op); |
||||
char *grpc_subchannel_call_holder_get_peer(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder, |
||||
grpc_channel *master); |
||||
|
||||
#endif |
@ -0,0 +1,39 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/slice.h> |
||||
#include "src/core/iomgr/sockaddr.h" |
||||
|
||||
void grpc_set_default_initial_connect_string(struct sockaddr **addr, |
||||
size_t *addr_len, |
||||
gpr_slice *initial_str) {} |
@ -0,0 +1,50 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H |
||||
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H |
||||
|
||||
#include <grpc/support/slice.h> |
||||
#include "src/core/iomgr/sockaddr.h" |
||||
|
||||
typedef void (*grpc_set_initial_connect_string_func)(struct sockaddr **addr, |
||||
size_t *addr_len, |
||||
gpr_slice *initial_str); |
||||
void grpc_test_set_initial_connect_string_function( |
||||
grpc_set_initial_connect_string_func func); |
||||
|
||||
/** Set a string to be sent once connected. Optionally reset addr. */ |
||||
void grpc_set_initial_connect_string(struct sockaddr **addr, size_t *addr_len, |
||||
gpr_slice *connect_string); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H */ |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,288 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/avl.h> |
||||
|
||||
#include <assert.h> |
||||
#include <stdlib.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/string_util.h> |
||||
#include <grpc/support/useful.h> |
||||
|
||||
gpr_avl gpr_avl_create(const gpr_avl_vtable *vtable) { |
||||
gpr_avl out; |
||||
out.vtable = vtable; |
||||
out.root = NULL; |
||||
return out; |
||||
} |
||||
|
||||
static gpr_avl_node *ref_node(gpr_avl_node *node) { |
||||
if (node) { |
||||
gpr_ref(&node->refs); |
||||
} |
||||
return node; |
||||
} |
||||
|
||||
static void unref_node(const gpr_avl_vtable *vtable, gpr_avl_node *node) { |
||||
if (node == NULL) { |
||||
return; |
||||
} |
||||
if (gpr_unref(&node->refs)) { |
||||
vtable->destroy_key(node->key); |
||||
vtable->destroy_value(node->value); |
||||
unref_node(vtable, node->left); |
||||
unref_node(vtable, node->right); |
||||
gpr_free(node); |
||||
} |
||||
} |
||||
|
||||
static long node_height(gpr_avl_node *node) { |
||||
return node == NULL ? 0 : node->height; |
||||
} |
||||
|
||||
#ifndef NDEBUG |
||||
static long calculate_height(gpr_avl_node *node) { |
||||
return node == NULL ? 0 : 1 + GPR_MAX(calculate_height(node->left), |
||||
calculate_height(node->right)); |
||||
} |
||||
|
||||
static gpr_avl_node *assert_invariants(gpr_avl_node *n) { |
||||
if (n == NULL) return NULL; |
||||
assert_invariants(n->left); |
||||
assert_invariants(n->right); |
||||
assert(calculate_height(n) == n->height); |
||||
assert(labs(node_height(n->left) - node_height(n->right)) <= 1); |
||||
return n; |
||||
} |
||||
#else |
||||
static gpr_avl_node *assert_invariants(gpr_avl_node *n) { return n; } |
||||
#endif |
||||
|
||||
gpr_avl_node *new_node(void *key, void *value, gpr_avl_node *left, |
||||
gpr_avl_node *right) { |
||||
gpr_avl_node *node = gpr_malloc(sizeof(*node)); |
||||
gpr_ref_init(&node->refs, 1); |
||||
node->key = key; |
||||
node->value = value; |
||||
node->left = assert_invariants(left); |
||||
node->right = assert_invariants(right); |
||||
node->height = 1 + GPR_MAX(node_height(left), node_height(right)); |
||||
return node; |
||||
} |
||||
|
||||
static gpr_avl_node *get(const gpr_avl_vtable *vtable, gpr_avl_node *node, |
||||
void *key) { |
||||
long cmp; |
||||
|
||||
if (node == NULL) { |
||||
return NULL; |
||||
} |
||||
|
||||
cmp = vtable->compare_keys(node->key, key); |
||||
if (cmp == 0) { |
||||
return node; |
||||
} else if (cmp > 0) { |
||||
return get(vtable, node->left, key); |
||||
} else { |
||||
return get(vtable, node->right, key); |
||||
} |
||||
} |
||||
|
||||
void *gpr_avl_get(gpr_avl avl, void *key) { |
||||
gpr_avl_node *node = get(avl.vtable, avl.root, key); |
||||
return node ? node->value : NULL; |
||||
} |
||||
|
||||
static gpr_avl_node *rotate_left(const gpr_avl_vtable *vtable, void *key, |
||||
void *value, gpr_avl_node *left, |
||||
gpr_avl_node *right) { |
||||
gpr_avl_node *n = |
||||
new_node(vtable->copy_key(right->key), vtable->copy_value(right->value), |
||||
new_node(key, value, left, ref_node(right->left)), |
||||
ref_node(right->right)); |
||||
unref_node(vtable, right); |
||||
return n; |
||||
} |
||||
|
||||
static gpr_avl_node *rotate_right(const gpr_avl_vtable *vtable, void *key, |
||||
void *value, gpr_avl_node *left, |
||||
gpr_avl_node *right) { |
||||
gpr_avl_node *n = new_node( |
||||
vtable->copy_key(left->key), vtable->copy_value(left->value), |
||||
ref_node(left->left), new_node(key, value, ref_node(left->right), right)); |
||||
unref_node(vtable, left); |
||||
return n; |
||||
} |
||||
|
||||
static gpr_avl_node *rotate_left_right(const gpr_avl_vtable *vtable, void *key, |
||||
void *value, gpr_avl_node *left, |
||||
gpr_avl_node *right) { |
||||
/* rotate_right(..., rotate_left(left), right) */ |
||||
gpr_avl_node *n = new_node( |
||||
vtable->copy_key(left->right->key), |
||||
vtable->copy_value(left->right->value), |
||||
new_node(vtable->copy_key(left->key), vtable->copy_value(left->value), |
||||
ref_node(left->left), ref_node(left->right->left)), |
||||
new_node(key, value, ref_node(left->right->right), right)); |
||||
unref_node(vtable, left); |
||||
return n; |
||||
} |
||||
|
||||
static gpr_avl_node *rotate_right_left(const gpr_avl_vtable *vtable, void *key, |
||||
void *value, gpr_avl_node *left, |
||||
gpr_avl_node *right) { |
||||
/* rotate_left(..., left, rotate_right(right)) */ |
||||
gpr_avl_node *n = new_node( |
||||
vtable->copy_key(right->left->key), |
||||
vtable->copy_value(right->left->value), |
||||
new_node(key, value, left, ref_node(right->left->left)), |
||||
new_node(vtable->copy_key(right->key), vtable->copy_key(right->value), |
||||
ref_node(right->left->right), ref_node(right->right))); |
||||
unref_node(vtable, right); |
||||
return n; |
||||
} |
||||
|
||||
static gpr_avl_node *rebalance(const gpr_avl_vtable *vtable, void *key, |
||||
void *value, gpr_avl_node *left, |
||||
gpr_avl_node *right) { |
||||
switch (node_height(left) - node_height(right)) { |
||||
case 2: |
||||
if (node_height(left->left) - node_height(left->right) == -1) { |
||||
return assert_invariants( |
||||
rotate_left_right(vtable, key, value, left, right)); |
||||
} else { |
||||
return assert_invariants(rotate_right(vtable, key, value, left, right)); |
||||
} |
||||
case -2: |
||||
if (node_height(right->left) - node_height(right->right) == 1) { |
||||
return assert_invariants( |
||||
rotate_right_left(vtable, key, value, left, right)); |
||||
} else { |
||||
return assert_invariants(rotate_left(vtable, key, value, left, right)); |
||||
} |
||||
default: |
||||
return assert_invariants(new_node(key, value, left, right)); |
||||
} |
||||
} |
||||
|
||||
static gpr_avl_node *add(const gpr_avl_vtable *vtable, gpr_avl_node *node, |
||||
void *key, void *value) { |
||||
long cmp; |
||||
if (node == NULL) { |
||||
return new_node(key, value, NULL, NULL); |
||||
} |
||||
cmp = vtable->compare_keys(node->key, key); |
||||
if (cmp == 0) { |
||||
return new_node(key, value, ref_node(node->left), ref_node(node->right)); |
||||
} else if (cmp > 0) { |
||||
return rebalance( |
||||
vtable, vtable->copy_key(node->key), vtable->copy_value(node->value), |
||||
add(vtable, node->left, key, value), ref_node(node->right)); |
||||
} else { |
||||
return rebalance(vtable, vtable->copy_key(node->key), |
||||
vtable->copy_value(node->value), ref_node(node->left), |
||||
add(vtable, node->right, key, value)); |
||||
} |
||||
} |
||||
|
||||
gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value) { |
||||
gpr_avl_node *old_root = avl.root; |
||||
avl.root = add(avl.vtable, avl.root, key, value); |
||||
assert_invariants(avl.root); |
||||
unref_node(avl.vtable, old_root); |
||||
return avl; |
||||
} |
||||
|
||||
static gpr_avl_node *in_order_head(gpr_avl_node *node) { |
||||
while (node->left != NULL) { |
||||
node = node->left; |
||||
} |
||||
return node; |
||||
} |
||||
|
||||
static gpr_avl_node *in_order_tail(gpr_avl_node *node) { |
||||
while (node->right != NULL) { |
||||
node = node->right; |
||||
} |
||||
return node; |
||||
} |
||||
|
||||
static gpr_avl_node *remove(const gpr_avl_vtable *vtable, gpr_avl_node *node, |
||||
void *key) { |
||||
long cmp; |
||||
if (node == NULL) { |
||||
return NULL; |
||||
} |
||||
cmp = vtable->compare_keys(node->key, key); |
||||
if (cmp == 0) { |
||||
if (node->left == NULL) { |
||||
return ref_node(node->right); |
||||
} else if (node->right == NULL) { |
||||
return ref_node(node->left); |
||||
} else if (node->left->height < node->right->height) { |
||||
gpr_avl_node *h = in_order_head(node->right); |
||||
return rebalance(vtable, vtable->copy_key(h->key), |
||||
vtable->copy_value(h->value), ref_node(node->left), |
||||
remove(vtable, node->right, h->key)); |
||||
} else { |
||||
gpr_avl_node *h = in_order_tail(node->left); |
||||
return rebalance( |
||||
vtable, vtable->copy_key(h->key), vtable->copy_value(h->value), |
||||
remove(vtable, node->left, h->key), ref_node(node->right)); |
||||
} |
||||
} else if (cmp > 0) { |
||||
return rebalance(vtable, vtable->copy_key(node->key), |
||||
vtable->copy_value(node->value), |
||||
remove(vtable, node->left, key), ref_node(node->right)); |
||||
} else { |
||||
return rebalance(vtable, vtable->copy_key(node->key), |
||||
vtable->copy_value(node->value), ref_node(node->left), |
||||
remove(vtable, node->right, key)); |
||||
} |
||||
} |
||||
|
||||
gpr_avl gpr_avl_remove(gpr_avl avl, void *key) { |
||||
gpr_avl_node *old_root = avl.root; |
||||
avl.root = remove(avl.vtable, avl.root, key); |
||||
assert_invariants(avl.root); |
||||
unref_node(avl.vtable, old_root); |
||||
return avl; |
||||
} |
||||
|
||||
gpr_avl gpr_avl_ref(gpr_avl avl) { |
||||
ref_node(avl.root); |
||||
return avl; |
||||
} |
||||
|
||||
void gpr_avl_unref(gpr_avl avl) { unref_node(avl.vtable, avl.root); } |
@ -1,97 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/surface/byte_buffer_queue.h" |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/useful.h> |
||||
|
||||
static void bba_destroy(grpc_bbq_array *array, size_t start_pos) { |
||||
size_t i; |
||||
for (i = start_pos; i < array->count; i++) { |
||||
grpc_byte_buffer_destroy(array->data[i]); |
||||
} |
||||
gpr_free(array->data); |
||||
} |
||||
|
||||
/* Append an operation to an array, expanding as needed */ |
||||
static void bba_push(grpc_bbq_array *a, grpc_byte_buffer *buffer) { |
||||
if (a->count == a->capacity) { |
||||
a->capacity = GPR_MAX(a->capacity * 2, 8); |
||||
a->data = gpr_realloc(a->data, sizeof(grpc_byte_buffer *) * a->capacity); |
||||
} |
||||
a->data[a->count++] = buffer; |
||||
} |
||||
|
||||
void grpc_bbq_destroy(grpc_byte_buffer_queue *q) { |
||||
bba_destroy(&q->filling, 0); |
||||
bba_destroy(&q->draining, q->drain_pos); |
||||
} |
||||
|
||||
int grpc_bbq_empty(grpc_byte_buffer_queue *q) { |
||||
return (q->drain_pos == q->draining.count && q->filling.count == 0); |
||||
} |
||||
|
||||
void grpc_bbq_push(grpc_byte_buffer_queue *q, grpc_byte_buffer *buffer) { |
||||
q->bytes += grpc_byte_buffer_length(buffer); |
||||
bba_push(&q->filling, buffer); |
||||
} |
||||
|
||||
void grpc_bbq_flush(grpc_byte_buffer_queue *q) { |
||||
grpc_byte_buffer *bb; |
||||
while ((bb = grpc_bbq_pop(q))) { |
||||
grpc_byte_buffer_destroy(bb); |
||||
} |
||||
} |
||||
|
||||
size_t grpc_bbq_bytes(grpc_byte_buffer_queue *q) { return q->bytes; } |
||||
|
||||
grpc_byte_buffer *grpc_bbq_pop(grpc_byte_buffer_queue *q) { |
||||
grpc_bbq_array temp_array; |
||||
grpc_byte_buffer *out; |
||||
|
||||
if (q->drain_pos == q->draining.count) { |
||||
if (q->filling.count == 0) { |
||||
return NULL; |
||||
} |
||||
q->draining.count = 0; |
||||
q->drain_pos = 0; |
||||
/* swap arrays */ |
||||
temp_array = q->filling; |
||||
q->filling = q->draining; |
||||
q->draining = temp_array; |
||||
} |
||||
|
||||
out = q->draining.data[q->drain_pos++]; |
||||
q->bytes -= grpc_byte_buffer_length(out); |
||||
return out; |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,76 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/transport/byte_stream.h" |
||||
|
||||
#include <stdlib.h> |
||||
|
||||
#include <grpc/support/log.h> |
||||
|
||||
int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx, |
||||
grpc_byte_stream *byte_stream, gpr_slice *slice, |
||||
size_t max_size_hint, grpc_closure *on_complete) { |
||||
return byte_stream->next(exec_ctx, byte_stream, slice, max_size_hint, |
||||
on_complete); |
||||
} |
||||
|
||||
void grpc_byte_stream_destroy(grpc_byte_stream *byte_stream) { |
||||
byte_stream->destroy(byte_stream); |
||||
} |
||||
|
||||
/* slice_buffer_stream */ |
||||
|
||||
static int slice_buffer_stream_next(grpc_exec_ctx *exec_ctx, |
||||
grpc_byte_stream *byte_stream, |
||||
gpr_slice *slice, size_t max_size_hint, |
||||
grpc_closure *on_complete) { |
||||
grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream; |
||||
GPR_ASSERT(stream->cursor < stream->backing_buffer->count); |
||||
*slice = gpr_slice_ref(stream->backing_buffer->slices[stream->cursor]); |
||||
stream->cursor++; |
||||
return 1; |
||||
} |
||||
|
||||
static void slice_buffer_stream_destroy(grpc_byte_stream *byte_stream) {} |
||||
|
||||
void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream, |
||||
gpr_slice_buffer *slice_buffer, |
||||
gpr_uint32 flags) { |
||||
GPR_ASSERT(slice_buffer->length <= GPR_UINT32_MAX); |
||||
stream->base.length = (gpr_uint32)slice_buffer->length; |
||||
stream->base.flags = flags; |
||||
stream->base.next = slice_buffer_stream_next; |
||||
stream->base.destroy = slice_buffer_stream_destroy; |
||||
stream->backing_buffer = slice_buffer; |
||||
stream->cursor = 0; |
||||
} |
@ -0,0 +1,88 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_TRANSPORT_BYTE_STREAM_H |
||||
#define GRPC_INTERNAL_CORE_TRANSPORT_BYTE_STREAM_H |
||||
|
||||
#include "src/core/iomgr/exec_ctx.h" |
||||
#include <grpc/support/slice_buffer.h> |
||||
|
||||
/** Internal bit flag for grpc_begin_message's \a flags signaling the use of
|
||||
* compression for the message */ |
||||
#define GRPC_WRITE_INTERNAL_COMPRESS (0x80000000u) |
||||
/** Mask of all valid internal flags. */ |
||||
#define GRPC_WRITE_INTERNAL_USED_MASK (GRPC_WRITE_INTERNAL_COMPRESS) |
||||
|
||||
struct grpc_byte_stream; |
||||
typedef struct grpc_byte_stream grpc_byte_stream; |
||||
|
||||
struct grpc_byte_stream { |
||||
gpr_uint32 length; |
||||
gpr_uint32 flags; |
||||
int (*next)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream, |
||||
gpr_slice *slice, size_t max_size_hint, |
||||
grpc_closure *on_complete); |
||||
void (*destroy)(grpc_byte_stream *byte_stream); |
||||
}; |
||||
|
||||
/* returns 1 if the bytes are available immediately (in which case
|
||||
* on_complete will not be called), 0 if the bytes will be available |
||||
* asynchronously. |
||||
* |
||||
* on entry, *remaining can be set as a hint as to the maximum number |
||||
* of bytes that would be acceptable to read. |
||||
* |
||||
* fills *buffer, *length, *remaining with the bytes, length of bytes |
||||
* and length of data remaining to be read before either returning 1 |
||||
* or calling on_complete. |
||||
* |
||||
* once a slice is returned into *slice, it is owned by the caller. |
||||
*/ |
||||
int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx, |
||||
grpc_byte_stream *byte_stream, gpr_slice *slice, |
||||
size_t max_size_hint, grpc_closure *on_complete); |
||||
|
||||
void grpc_byte_stream_destroy(grpc_byte_stream *byte_stream); |
||||
|
||||
/* grpc_byte_stream that wraps a slice buffer */ |
||||
typedef struct grpc_slice_buffer_stream { |
||||
grpc_byte_stream base; |
||||
gpr_slice_buffer *backing_buffer; |
||||
size_t cursor; |
||||
} grpc_slice_buffer_stream; |
||||
|
||||
void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream, |
||||
gpr_slice_buffer *slice_buffer, |
||||
gpr_uint32 flags); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_TRANSPORT_BYTE_STREAM_H */ |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue