[Groonga-commit] groonga/groonga at 5663e46 [master] Add request cancel feature (experimental)

Zurück zum Archiv-Index

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 



More information about the Groonga-commit mailing list
Zurück zum Archiv-Index