ngx_int_t hustdb_ha_read_handler( ngx_bool_t read_body, ngx_bool_t key_in_body, hustdb_ha_check_parameter_t check_parameter, ngx_str_t * backend_uri, ngx_http_request_t *r) { hustdb_ha_ctx_t * ctx = ngx_http_get_addon_module_ctx(r); if (!ctx) { if (read_body && !(r->method & NGX_HTTP_POST)) { return NGX_HTTP_NOT_ALLOWED; } if (check_parameter && !check_parameter(backend_uri, r)) { return NGX_ERROR; } return read_body ? __post_read(key_in_body, backend_uri, r) : __start_read(backend_uri, r); } if (NGX_HTTP_OK != r->headers_out.status) { ctx->peer = ngx_http_get_next_peer(ctx->peer); return ctx->peer ? ngx_http_run_subrequest( r, &ctx->base, ctx->peer->peer) : hustdb_ha_send_response( NGX_HTTP_NOT_FOUND, NULL, NULL, r); } return hustdb_ha_send_response(NGX_HTTP_OK, ctx->version, &ctx->base.response, r); }
static ngx_int_t __write_sync_data( uint8_t method, ngx_bool_t has_tb, ngx_http_request_t *r, ngx_http_hustdb_ha_write_ctx_t * ctx) { do { time_t now = time(NULL); uint32_t ttl = (0 == ctx->ttl) ? 0 : (uint32_t) (now + ctx->ttl); ngx_buf_t * value = NULL; ngx_buf_t * head = __encode_head(method, ctx->proto, has_tb, ctx->base.version, ctx->base.key, ctx->base.tb, ttl, r->pool); if (r->request_body) { if (!ngx_http_insert_head_to_body(head, r)) { break; } value = ngx_http_get_request_body(r); } else { value = head; } if (!value) { break; } ngx_http_hustdb_ha_main_conf_t * mcf = hustdb_ha_get_module_main_conf(r); ngx_str_t * server = &ctx->error_peer->peer->server; if (!hustdb_ha_write_log(&mcf->zlog_mdc, server, value, r->pool)) { break; } static ngx_str_t SYNC_KEY = ngx_string("Sync"); if (!ngx_http_add_field_to_headers_out(&SYNC_KEY, server, r)) { break; } return hustdb_ha_send_response(NGX_HTTP_OK, ctx->base.version, NULL, r); } while (0); return hustdb_ha_send_response(NGX_HTTP_NOT_FOUND, NULL, NULL, r); }
static ngx_int_t __on_write_master1_complete( uint8_t method, ngx_bool_t has_tb, ngx_http_request_t *r, ngx_http_hustdb_ha_write_ctx_t * ctx) { __update_error(method, r->headers_out.status, ctx); ctx->base.peer = ctx->base.peer->next; ngx_bool_t alive = ngx_http_peer_is_alive(ctx->base.peer->peer); ngx_http_hustdb_ha_main_conf_t * mcf = hustdb_ha_get_module_main_conf(r); if (mcf->debug_sync) { alive = false; } if (alive) // master2 { ctx->state = STATE_WRITE_MASTER2; return ngx_http_run_subrequest(r, &ctx->base.base, ctx->base.peer->peer); } // master2 dead ++ctx->error_count; ctx->error_peer = ctx->base.peer; if (ctx->error_count > 1) // both master1 & master2 fail { return hustdb_ha_send_response(NGX_HTTP_NOT_FOUND, NULL, NULL, r); } return __write_sync_data(method, has_tb, r, ctx); }
static void __post_handler(ngx_http_request_t *r) { --r->main->count; ngx_http_hustdb_ha_write_ctx_t * ctx = ngx_http_get_addon_module_ctx(r); ngx_bool_t rc = true; if (ctx->key_in_body) { if (!__init_write_ctx_by_body(r, ctx)) { rc = false; } } else { if (ctx->check_body_len) { rc = hustdb_ha_check_body(r); } } if (!rc) { hustdb_ha_send_response(NGX_HTTP_NOT_FOUND, NULL, NULL, r); return; } ngx_http_gen_subrequest( ctx->base.base.backend_uri, r, ctx->base.peer->peer, &ctx->base.base, hustdb_ha_on_subrequest_complete); }
// ------------------------------------------------------------- // |skip | 0 | 1 | 2 | 0 | 1 | 2 | 0 | // ------------------------------------------------------------- // |err | 0 | 0 | 0 | 1 | 1 | 0 | 2 | // ------------------------------------------------------------- // |action | 200 | 200 | 404 | 200&log | 404 | 404 | 404 | // ------------------------------------------------------------- static ngx_int_t __send_write_response( uint8_t method, ngx_bool_t has_tb, ngx_http_request_t *r, ngx_http_hustdb_ha_write_ctx_t * ctx) { if (0 == ctx->skip_error_count && 1 == ctx->error_count) { return __write_sync_data(method, has_tb, r, ctx); } if (0 == ctx->skip_error_count && 0 == ctx->error_count) { return hustdb_ha_send_response(NGX_HTTP_OK, &ctx->base.version, NULL, r); } return hustdb_ha_send_response(NGX_HTTP_NOT_FOUND, NULL, NULL, r); }
ngx_int_t hustdb_ha_start_post( ngx_bool_t support_post_only, ngx_bool_t key_in_body, ngx_bool_t has_tb, ngx_bool_t check_body_len, ngx_str_t * backend_uri, ngx_http_request_t *r) { ngx_http_hustdb_ha_write_ctx_t * ctx = __create_write_ctx(r); if (!ctx) { return hustdb_ha_send_response(NGX_HTTP_NOT_FOUND, NULL, NULL, r); } ctx->check_body_len = check_body_len; ctx->base.base.backend_uri = backend_uri; if (support_post_only && !(r->method & NGX_HTTP_POST)) { return NGX_HTTP_NOT_ALLOWED; } if (key_in_body) { ctx->key_in_body = true; ctx->has_tb = has_tb; } else { write_ctx_t tmp; if (!__set_write_context(NULL, has_tb, r, &tmp)) { return hustdb_ha_send_response(NGX_HTTP_NOT_FOUND, NULL, NULL, r); } __copy_data(&tmp, ctx); } ngx_int_t rc = ngx_http_read_client_request_body(r, __post_handler); if ( rc >= NGX_HTTP_SPECIAL_RESPONSE ) { return rc; } return NGX_DONE; }
static ngx_int_t __on_write_master2_complete( uint8_t method, ngx_bool_t has_tb, ngx_http_request_t *r, ngx_http_hustdb_ha_write_ctx_t * ctx) { __update_error(method, r->headers_out.status, ctx); if (ctx->error_count > 1) // both master1 & master2 fail { return hustdb_ha_send_response(NGX_HTTP_NOT_FOUND, NULL, NULL, r); } else if (1 == ctx->error_count) // master1 or master2 fail { return __write_sync_data(method, has_tb, r, ctx); } if (ctx->skip_error_count > 1) // both master1 and master2 return 404 for del { return hustdb_ha_send_response(NGX_HTTP_NOT_FOUND, NULL, NULL, r); } return hustdb_ha_send_response(NGX_HTTP_OK, ctx->base.version, NULL, r); }
static ngx_int_t __start_zwrite(ngx_str_t * backend_uri, ngx_http_request_t *r) { ngx_http_hustdb_ha_write_ctx_t * ctx = __create_zwrite_ctx(r); if (!ctx) { return hustdb_ha_send_response(NGX_HTTP_NOT_FOUND, NULL, NULL, r); } ctx->base.base.backend_uri = backend_uri; write_ctx_t tmp; if (!__parse_args(true, true, r, &tmp)) { return hustdb_ha_send_response(NGX_HTTP_NOT_FOUND, NULL, NULL, r); } __copy_data(&tmp, ctx); ngx_int_t rc = ngx_http_read_client_request_body(r, __post_body_handler); if ( rc >= NGX_HTTP_SPECIAL_RESPONSE ) { return rc; } return NGX_DONE; }
static void __post_body_handler(ngx_http_request_t *r) { --r->main->count; ngx_http_hustdb_ha_write_ctx_t * ctx = ngx_http_get_addon_module_ctx(r); ctx->base.key = hustdb_ha_get_key(r); if (!ctx->base.key) { hustdb_ha_send_response(NGX_HTTP_NOT_FOUND, NULL, NULL, r); return; } ngx_http_gen_subrequest( ctx->base.base.backend_uri, r, ctx->base.peer->peer, &ctx->base.base, hustdb_ha_on_subrequest_complete); }
static void __post_handler(ngx_http_request_t *r) { --r->main->count; hustdb_ha_ctx_t * ctx = ngx_http_get_addon_module_ctx(r); ngx_http_subrequest_peer_t * peer = __get_readable_peer(ctx->key_in_body, r); if (!peer) { hustdb_ha_send_response(NGX_HTTP_NOT_FOUND, NULL, NULL, r); } else { ctx->peer = peer; ngx_http_gen_subrequest( ctx->base.backend_uri, r, peer->peer, &ctx->base, hustdb_ha_on_subrequest_complete); } }
static ngx_bool_t __init_write_ctx_by_body(ngx_http_request_t *r, ngx_http_hustdb_ha_write_ctx_t * ctx) { do { char * key = hustdb_ha_get_key_from_body(r); if (!key) { break; } write_ctx_t tmp; if (!__set_write_context(key, ctx->has_tb, r, &tmp)) { break; } __copy_data(&tmp, ctx); return true; } while (0); hustdb_ha_send_response(NGX_HTTP_NOT_FOUND, NULL, NULL, r); return false; }