Kouhei Sutou
null+****@clear*****
Fri Dec 5 16:24:59 JST 2014
Kouhei Sutou 2014-12-05 16:24:59 +0900 (Fri, 05 Dec 2014) New Revision: 5663e46e699002a97bc5153777c5cfea0b4a96e9 https://github.com/groonga/groonga/commit/5663e46e699002a97bc5153777c5cfea0b4a96e9 Message: Add request cancel feature (experimental) You can cancel a request by this feature with the following steps: 1. Add "request_id" parameter to your request. For example: * "select Table --query 'body:@keyword' --request_id ID" * "/d/select?table=Table&query=body:@keyword&request_id=ID" Note that the "request_id" value should be unique in concurrent requests. 2. Call "request_cancel" command with the request ID. For example: * "request_cancel ID" * "/d/request_cancel?id=ID" 3. "request_cancel" returns the following body: { "id": "ID", "canceled": true } * Note that the request ID doesn't exist, "canceled" value is false. * You can call "request_cancel" multiple times with the same request ID. 4. Request that is specified by the request ID will be canceled. The response has -5 (GRN_INTERRUPTED_FUNCTION_CALL) as status code. TODO: * Document me. * Test me. Added files: lib/request_canceler.c test/command/suite/request_cancel/nonexistent.expected test/command/suite/request_cancel/nonexistent.test Copied files: include/groonga/request_canceler.h (from include/groonga.h) lib/grn_request_canceler.h (from include/groonga.h) Modified files: include/groonga.h include/groonga/Makefile.am lib/ctx.c lib/proc.c lib/sources.am Modified: include/groonga.h (+1 -0) =================================================================== --- include/groonga.h 2014-12-05 16:06:42 +0900 (cc8e469) +++ include/groonga.h 2014-12-05 16:24:59 +0900 (115b954) @@ -22,5 +22,6 @@ #include "groonga/ii.h" #include "groonga/expr.h" #include "groonga/util.h" +#include "groonga/request_canceler.h" #endif /* GROONGA_H */ Modified: include/groonga/Makefile.am (+1 -0) =================================================================== --- include/groonga/Makefile.am 2014-12-05 16:06:42 +0900 (cd131fc) +++ include/groonga/Makefile.am 2014-12-05 16:24:59 +0900 (c0a0018) @@ -4,6 +4,7 @@ groonga_include_HEADERS = \ groonga.h \ ii.h \ plugin.h \ + request_canceler.h \ token.h \ tokenizer.h \ token_filter.h \ Copied: include/groonga/request_canceler.h (+20 -7) 52% =================================================================== --- include/groonga.h 2014-12-05 16:06:42 +0900 (cc8e469) +++ include/groonga/request_canceler.h 2014-12-05 16:24:59 +0900 (0032a77) @@ -15,12 +15,25 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef GROONGA_H -#define GROONGA_H -#include "groonga/groonga.h" -#include "groonga/ii.h" -#include "groonga/expr.h" -#include "groonga/util.h" +#ifndef GROONGA_REQUEST_CANCELER_H +#define GROONGA_REQUEST_CANCELER_H -#endif /* GROONGA_H */ +#ifdef __cplusplus +extern "C" { +#endif + +GRN_API void grn_request_canceler_register(grn_ctx *ctx, + const char *request_id, + unsigned int size); +GRN_API void grn_request_canceler_unregister(grn_ctx *ctx, + const char *request_id, + unsigned int size); +GRN_API grn_bool grn_request_canceler_cancel(const char *request_id, + unsigned int size); + +#ifdef __cplusplus +} +#endif + +#endif /* GROONGA_REQUEST_CANCELER_H */ Modified: lib/ctx.c (+47 -0) =================================================================== --- lib/ctx.c 2014-12-05 16:06:42 +0900 (f454ace) +++ lib/ctx.c 2014-12-05 16:24:59 +0900 (4c978df) @@ -18,6 +18,7 @@ #include "grn.h" #include <string.h> +#include "grn_request_canceler.h" #include "grn_tokenizers.h" #include "grn_ctx_impl.h" #include "grn_pat.h" @@ -1293,6 +1294,13 @@ grn_init(void) } */ grn_cache_init(); + if (!grn_request_canceler_init()) { + rc = ctx->rc; + grn_cache_fin(); + GRN_LOG(ctx, GRN_LOG_ALERT, + "failed to initialize request canceler (%d)", rc); + return rc; + } GRN_LOG(ctx, GRN_LOG_NOTICE, "grn_init"); check_overcommit_memory(ctx); check_grn_ja_skip_same_value_put(ctx); @@ -1379,6 +1387,7 @@ grn_fin(void) } } query_logger_fin(ctx); + grn_request_canceler_fin(); grn_cache_fin(); grn_tokenizers_fin(); grn_normalizer_fin(); @@ -1637,9 +1646,11 @@ get_command_version(grn_ctx *ctx, const char *p, const char *pe) #define INDEX_HTML "index.html" #define OUTPUT_TYPE "output_type" #define COMMAND_VERSION "command_version" +#define REQUEST_ID "request_id" #define EXPR_MISSING "expr_missing" #define OUTPUT_TYPE_LEN (sizeof(OUTPUT_TYPE) - 1) #define COMMAND_VERSION_LEN (sizeof(COMMAND_VERSION) - 1) +#define REQUEST_ID_LEN (sizeof(REQUEST_ID) - 1) #define HTTP_QUERY_PAIR_DELIMITER "=" #define HTTP_QUERY_PAIRS_DELIMITERS "&;" @@ -1655,8 +1666,10 @@ grn_obj * grn_ctx_qe_exec_uri(grn_ctx *ctx, const char *path, uint32_t path_len) { grn_obj buf, *expr, *val; + grn_obj request_id; const char *p = path, *e = path + path_len, *v, *key_end, *filename_end; GRN_TEXT_INIT(&buf, 0); + GRN_TEXT_INIT(&request_id, 0); p = grn_text_urldec(ctx, &buf, p, e, '?'); if (!GRN_TEXT_LEN(&buf)) { GRN_TEXT_SETS(ctx, &buf, INDEX_HTML); } v = GRN_TEXT_VALUE(&buf); @@ -1683,6 +1696,12 @@ grn_ctx_qe_exec_uri(grn_ctx *ctx, const char *path, uint32_t path_len) p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIRS_DELIMITERS); get_command_version(ctx, GRN_TEXT_VALUE(&buf), GRN_BULK_CURR(&buf)); if (ctx->rc) { goto exit; } + } else if (l == REQUEST_ID_LEN && + !memcmp(v, REQUEST_ID, REQUEST_ID_LEN)) { + GRN_BULK_REWIND(&request_id); + p = grn_text_cgidec(ctx, &request_id, p, e, + HTTP_QUERY_PAIRS_DELIMITERS); + if (ctx->rc) { goto exit; } } else { if (!(val = grn_expr_get_or_add_var(ctx, expr, v, l))) { val = &buf; @@ -1691,8 +1710,18 @@ grn_ctx_qe_exec_uri(grn_ctx *ctx, const char *path, uint32_t path_len) p = grn_text_cgidec(ctx, val, p, e, HTTP_QUERY_PAIRS_DELIMITERS); } } + if (GRN_TEXT_LEN(&request_id) > 0) { + grn_request_canceler_register(ctx, + GRN_TEXT_VALUE(&request_id), + GRN_TEXT_LEN(&request_id)); + } ctx->impl->curr_expr = expr; grn_expr_exec(ctx, expr, 0); + if (GRN_TEXT_LEN(&request_id) > 0) { + grn_request_canceler_unregister(ctx, + GRN_TEXT_VALUE(&request_id), + GRN_TEXT_LEN(&request_id)); + } } else { ERR(GRN_INVALID_ARGUMENT, "invalid command name: %.*s", command_name_size, command_name); @@ -1717,8 +1746,10 @@ grn_ctx_qe_exec(grn_ctx *ctx, const char *str, uint32_t str_len) char tok_type; int offset = 0; grn_obj buf, *expr = NULL, *val = NULL; + grn_obj request_id; const char *p = str, *e = str + str_len, *v; GRN_TEXT_INIT(&buf, 0); + GRN_TEXT_INIT(&request_id, 0); p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type); expr = grn_ctx_get(ctx, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf)); while (p < e) { @@ -1744,6 +1775,11 @@ grn_ctx_qe_exec(grn_ctx *ctx, const char *str, uint32_t str_len) p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type); get_command_version(ctx, GRN_TEXT_VALUE(&buf), GRN_BULK_CURR(&buf)); if (ctx->rc) { goto exit; } + } else if (l == REQUEST_ID_LEN && + !memcmp(v, REQUEST_ID, REQUEST_ID_LEN)) { + GRN_BULK_REWIND(&request_id); + p = grn_text_unesc_tok(ctx, &request_id, p, e, &tok_type); + if (ctx->rc) { goto exit; } } else if (expr && (val = grn_expr_get_or_add_var(ctx, expr, v, l))) { grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0); p = grn_text_unesc_tok(ctx, val, p, e, &tok_type); @@ -1764,6 +1800,11 @@ grn_ctx_qe_exec(grn_ctx *ctx, const char *str, uint32_t str_len) break; } } + if (GRN_TEXT_LEN(&request_id) > 0) { + grn_request_canceler_register(ctx, + GRN_TEXT_VALUE(&request_id), + GRN_TEXT_LEN(&request_id)); + } ctx->impl->curr_expr = expr; if (expr && command_proc_p(expr)) { grn_expr_exec(ctx, expr, 0); @@ -1775,7 +1816,13 @@ grn_ctx_qe_exec(grn_ctx *ctx, const char *str, uint32_t str_len) (int)GRN_TEXT_LEN(&buf), GRN_TEXT_VALUE(&buf)); } } + if (GRN_TEXT_LEN(&request_id) > 0) { + grn_request_canceler_unregister(ctx, + GRN_TEXT_VALUE(&request_id), + GRN_TEXT_LEN(&request_id)); + } exit : + GRN_OBJ_FIN(ctx, &request_id); GRN_OBJ_FIN(ctx, &buf); return expr; } Copied: lib/grn_request_canceler.h (+14 -9) 65% =================================================================== --- include/groonga.h 2014-12-05 16:06:42 +0900 (cc8e469) +++ lib/grn_request_canceler.h 2014-12-05 16:24:59 +0900 (4c77ea5) @@ -1,10 +1,10 @@ +/* -*- c-basic-offset: 2 -*- */ /* Copyright(C) 2014 Brazil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. + License version 2.1 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -15,12 +15,17 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef GROONGA_H -#define GROONGA_H -#include "groonga/groonga.h" -#include "groonga/ii.h" -#include "groonga/expr.h" -#include "groonga/util.h" +#ifndef GRN_REQUEST_CANCELER_H +#define GRN_REQUEST_CANCELER_H -#endif /* GROONGA_H */ +#include "grn.h" + +grn_bool grn_request_canceler_init(void); +void grn_request_canceler_fin(void); + +#ifdef __cplusplus +} +#endif + +#endif /* GRN_REQUEST_CANCELER_H */ Modified: lib/proc.c (+27 -0) =================================================================== --- lib/proc.c 2014-12-05 16:06:42 +0900 (56d9e30) +++ lib/proc.c 2014-12-05 16:24:59 +0900 (a368a52) @@ -6385,6 +6385,30 @@ exit : return NULL; } +static grn_obj * +proc_request_cancel(grn_ctx *ctx, int nargs, grn_obj **args, + grn_user_data *user_data) +{ + grn_obj *id = VAR(0); + grn_bool canceled; + + if (GRN_TEXT_LEN(id) == 0) { + ERR(GRN_INVALID_ARGUMENT, "[request_cancel] ID is missing"); + return NULL; + } + + canceled = grn_request_canceler_cancel(GRN_TEXT_VALUE(id), GRN_TEXT_LEN(id)); + + GRN_OUTPUT_MAP_OPEN("result", 2); + GRN_OUTPUT_CSTR("id"); + GRN_OUTPUT_STR(GRN_TEXT_VALUE(id), GRN_TEXT_LEN(id)); + GRN_OUTPUT_CSTR("canceled"); + GRN_OUTPUT_BOOL(canceled); + GRN_OUTPUT_MAP_CLOSE(); + + return NULL; +} + #define DEF_VAR(v,name_str) do {\ (v).name = (name_str);\ (v).name_size = GRN_STRLEN(name_str);\ @@ -6642,4 +6666,7 @@ grn_db_init_builtin_query(grn_ctx *ctx) DEF_VAR(vars[8], "filter"); DEF_VAR(vars[9], "output_columns"); DEF_COMMAND("range_filter", proc_range_filter, 10, vars); + + DEF_VAR(vars[0], "id"); + DEF_COMMAND("request_cancel", proc_request_cancel, 1, vars); } Added: lib/request_canceler.c (+117 -0) 100644 =================================================================== --- /dev/null +++ lib/request_canceler.c 2014-12-05 16:24:59 +0900 (42a852d) @@ -0,0 +1,117 @@ +/* -*- c-basic-offset: 2 -*- */ +/* + Copyright(C) 2014 Brazil + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "grn_ctx.h" +#include "grn_request_canceler.h" + +typedef struct _grn_request_canceler grn_request_canceler; +struct _grn_request_canceler { + grn_hash *entries; + grn_mutex mutex; +}; + +typedef struct _grn_request_canceler_entry grn_request_canceler_entry; +struct _grn_request_canceler_entry { + grn_ctx *ctx; +}; + +static grn_request_canceler *grn_the_request_canceler = NULL; + +grn_bool +grn_request_canceler_init(void) +{ + grn_ctx *ctx = &grn_gctx; + + grn_the_request_canceler = GRN_MALLOC(sizeof(grn_request_canceler)); + if (!grn_the_request_canceler) { + ERR(GRN_NO_MEMORY_AVAILABLE, + "[request-canceler] failed to allocate the global request canceler"); + return GRN_FALSE; + } + + grn_the_request_canceler->entries = + grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE, + sizeof(grn_request_canceler_entry), GRN_OBJ_KEY_VAR_SIZE); + if (!grn_the_request_canceler->entries) { + return GRN_FALSE; + } + MUTEX_INIT(grn_the_request_canceler->mutex); + + return GRN_TRUE; +} + +void +grn_request_canceler_register(grn_ctx *ctx, + const char *request_id, unsigned int size) +{ + MUTEX_LOCK(grn_the_request_canceler->mutex); + { + grn_hash *entries = grn_the_request_canceler->entries; + grn_id id; + void *value; + id = grn_hash_add(&grn_gctx, entries, request_id, size, &value, NULL); + if (id) { + grn_request_canceler_entry *entry = value; + entry->ctx = ctx; + } + } + MUTEX_UNLOCK(grn_the_request_canceler->mutex); +} + +void +grn_request_canceler_unregister(grn_ctx *ctx, + const char *request_id, unsigned int size) +{ + MUTEX_LOCK(grn_the_request_canceler->mutex); + { + grn_hash *entries = grn_the_request_canceler->entries; + grn_hash_delete(&grn_gctx, entries, request_id, size, NULL); + } + MUTEX_UNLOCK(grn_the_request_canceler->mutex); +} + +grn_bool +grn_request_canceler_cancel(const char *request_id, unsigned int size) +{ + grn_bool canceled = GRN_FALSE; + MUTEX_LOCK(grn_the_request_canceler->mutex); + { + grn_hash *entries = grn_the_request_canceler->entries; + void *value; + if (grn_hash_get(&grn_gctx, entries, request_id, size, &value)) { + grn_request_canceler_entry *entry = value; + ERRSET(entry->ctx, GRN_LOG_NOTICE, GRN_INTERRUPTED_FUNCTION_CALL, + "[request-canceler] cancel request: <%.*s>", + size, request_id); + canceled = GRN_TRUE; + } + } + MUTEX_UNLOCK(grn_the_request_canceler->mutex); + return canceled; +} + +void +grn_request_canceler_fin(void) +{ + grn_ctx *ctx = &grn_gctx; + + grn_hash_close(ctx, grn_the_request_canceler->entries); + MUTEX_FIN(grn_the_request_canceler->mutex); + GRN_FREE(grn_the_request_canceler); + grn_the_request_canceler = NULL; +} Modified: lib/sources.am (+2 -0) =================================================================== --- lib/sources.am 2014-12-05 16:06:42 +0900 (7ee0a58) +++ lib/sources.am 2014-12-05 16:24:59 +0900 (0be9ded) @@ -37,6 +37,8 @@ libgroonga_la_SOURCES = \ grn_plugin.h \ proc.c \ grn_proc.h \ + request_canceler.c \ + grn_request_canceler.h \ snip.c \ grn_snip.h \ store.c \ Added: test/command/suite/request_cancel/nonexistent.expected (+2 -0) 100644 =================================================================== --- /dev/null +++ test/command/suite/request_cancel/nonexistent.expected 2014-12-05 16:24:59 +0900 (207f98e) @@ -0,0 +1,2 @@ +request_cancel ID +[[0,0.0,0.0],{"id":"ID","canceled":false}] Added: test/command/suite/request_cancel/nonexistent.test (+1 -0) 100644 =================================================================== --- /dev/null +++ test/command/suite/request_cancel/nonexistent.test 2014-12-05 16:24:59 +0900 (9e27aaf) @@ -0,0 +1 @@ +request_cancel ID -------------- next part -------------- HTML����������������������������...Download