[Groonga-commit] groonga/groonga [master] httpd: support per location groonga database

Back to archive index

null+****@clear***** null+****@clear*****
2012年 7月 24日 (火) 16:35:53 JST


Kouhei Sutou	2012-07-24 16:35:53 +0900 (Tue, 24 Jul 2012)

  New Revision: c0b82b7c64f4b11477dd2bc1c8233b6412cb1255
  https://github.com/groonga/groonga/commit/c0b82b7c64f4b11477dd2bc1c8233b6412cb1255

  Log:
    httpd: support per location groonga database
    
    Before this change, "location /d/" only supported.
    After this change, the following configuration is available:
    
      ...
        location /d/ {
          groonga;
          groonga_database ...;
        }
    
        location /database1/ {
          groonga;
          groonga_database ...;
        }
    
        location /database2/ {
          groonga;
          groonga_database ...;
        }
      ...

  Modified files:
    src/nginx-module/ngx_http_groonga_module.c

  Modified: src/nginx-module/ngx_http_groonga_module.c (+141 -56)
===================================================================
--- src/nginx-module/ngx_http_groonga_module.c    2012-07-24 16:16:11 +0900 (6aa8db0)
+++ src/nginx-module/ngx_http_groonga_module.c    2012-07-24 16:35:53 +0900 (d3dfd17)
@@ -25,9 +25,16 @@
 typedef struct {
   ngx_str_t database;
   char *database_cstr;
-  grn_ctx *global_context;
+  grn_ctx context;
 } ngx_http_groonga_loc_conf_t;
 
+typedef struct {
+  ngx_log_t *log;
+  ngx_int_t rc;
+} ngx_http_groonga_database_callback_data_t;
+
+typedef void (*ngx_http_groonga_loc_conf_callback_pt)(ngx_http_groonga_loc_conf_t *conf, void *user_data);
+
 static char *ngx_http_groonga(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 
 static ngx_command_t ngx_http_groonga_commands[] = {
@@ -53,10 +60,9 @@ static char *ngx_http_groonga_merge_loc_conf(ngx_conf_t *cf,
                                              void *parent,
                                              void *child);
 
-static ngx_int_t ngx_http_groonga_pre_configuration(ngx_conf_t *conf);
 
 static ngx_http_module_t ngx_http_groonga_module_ctx = {
-  ngx_http_groonga_pre_configuration, /* preconfiguration */
+  NULL, /* preconfiguration */
   NULL, /* postconfiguration */
 
   NULL, /* create main configuration */
@@ -69,7 +75,8 @@ static ngx_http_module_t ngx_http_groonga_module_ctx = {
   ngx_http_groonga_merge_loc_conf, /* merge location configuration */
 };
 
-static void ngx_http_groonga_exit_master(ngx_cycle_t *cycle);
+static ngx_int_t ngx_http_groonga_init_process(ngx_cycle_t *cycle);
+static void ngx_http_groonga_exit_process(ngx_cycle_t *cycle);
 
 ngx_module_t ngx_http_groonga_module = {
   NGX_MODULE_V1,
@@ -78,11 +85,11 @@ ngx_module_t ngx_http_groonga_module = {
   NGX_HTTP_MODULE, /* module type */
   NULL, /* init master */
   NULL, /* init module */
-  NULL, /* init process */
+  ngx_http_groonga_init_process, /* init process */
   NULL, /* init thread */
   NULL, /* exit thread */
-  NULL, /* exit process */
-  ngx_http_groonga_exit_master, /* exit master */
+  ngx_http_groonga_exit_process, /* exit process */
+  NULL, /* exit master */
   NGX_MODULE_V1_PADDING
 };
 
@@ -188,28 +195,6 @@ ngx_http_groonga_context_receive_handler(grn_ctx *context,
 }
 
 static ngx_int_t
-ngx_http_groonga_open_database(ngx_log_t *log,
-                               ngx_http_groonga_loc_conf_t *loc_conf) {
-  ngx_int_t    rc;
-  grn_ctx *context = malloc(sizeof(grn_ctx));
-
-  grn_ctx_init(context, GRN_NO_FLAGS);
-
-  if (!loc_conf->database_cstr) {
-    loc_conf->database_cstr = ngx_str_null_terminate(&loc_conf->database);
-  }
-
-  grn_db_open(context, loc_conf->database_cstr);
-  rc = ngx_http_groonga_context_check(log, context);
-  if (rc != NGX_OK) {
-    return rc;
-  }
-
-  loc_conf->global_context = context;
-  return NGX_OK;
-}
-
-static ngx_int_t
 ngx_http_groonga_handler(ngx_http_request_t *r)
 {
   ngx_int_t    rc;
@@ -217,22 +202,39 @@ ngx_http_groonga_handler(ngx_http_request_t *r)
   ngx_chain_t  head_chain, body_chain, foot_chain;
 
   grn_ctx *context;
+  grn_obj uri;
+  u_char *unparsed_path;
+  ngx_int_t unparsed_path_length;
 
   ngx_http_groonga_output_t output;
   const char *content_type;
 
-  ngx_http_groonga_loc_conf_t *loc_conf;
-  loc_conf = ngx_http_get_module_loc_conf(r, ngx_http_groonga_module);
+  ngx_http_core_loc_conf_t *http_location_conf;
+  ngx_http_groonga_loc_conf_t *location_conf;
+
+  http_location_conf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+  location_conf = ngx_http_get_module_loc_conf(r, ngx_http_groonga_module);
+
+  unparsed_path = r->unparsed_uri.data + http_location_conf->name.len;
+  unparsed_path_length = r->unparsed_uri.len - http_location_conf->name.len;
+  if (unparsed_path_length > 0 && unparsed_path[0] == '/') {
+    unparsed_path += 1;
+    unparsed_path_length -= 1;
+  }
+  if (unparsed_path_length == 0) {
+    return NGX_HTTP_BAD_REQUEST;
+  }
 
-  context = loc_conf->global_context;
+  context = &(location_conf->context);
 
   grn_ctx_recv_handler_set(context,
                            ngx_http_groonga_context_receive_handler,
                            (void *)&output);
-  grn_ctx_send(context,
-               (char *)r->unparsed_uri.data,
-               r->unparsed_uri.len,
-               GRN_NO_FLAGS);
+  GRN_TEXT_INIT(&uri, 0);
+  GRN_TEXT_PUTS(context, &uri, "/d/");
+  GRN_TEXT_PUT(context, &uri, unparsed_path, unparsed_path_length);
+  grn_ctx_send(context, GRN_TEXT_VALUE(&uri), GRN_TEXT_LEN(&uri), GRN_NO_FLAGS);
+  GRN_OBJ_FIN(context, &uri);
 
   /* we response to 'GET' and 'HEAD' requests only */
   if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
@@ -323,7 +325,6 @@ ngx_http_groonga_create_loc_conf(ngx_conf_t *cf)
   conf->database.data = NULL;
   conf->database.len = 0;
   conf->database_cstr = NULL;
-  conf->global_context = NULL;
 
   return conf;
 }
@@ -331,49 +332,133 @@ ngx_http_groonga_create_loc_conf(ngx_conf_t *cf)
 static char *
 ngx_http_groonga_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
 {
-  ngx_int_t rc;
-  ngx_http_core_loc_conf_t *location_conf;
   ngx_http_groonga_loc_conf_t *prev = parent;
   ngx_http_groonga_loc_conf_t *conf = child;
 
-  ngx_conf_merge_str_value(conf->database, prev->database, NULL);
+  ngx_conf_merge_str_value(prev->database, conf->database, NULL);
 
-  location_conf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
-  if (location_conf->handler == ngx_http_groonga_handler) {
-    if (conf->database.data == NULL) {
-      ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-        "\"groonga_database\" must be specified");
-      return NGX_CONF_ERROR;
-    }
+  return NGX_CONF_OK;
+}
 
-    rc = ngx_http_groonga_open_database(cf->log, conf);
-    if (rc != NGX_OK) {
-      ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-        "failed to open the specified database");
-      return NGX_CONF_ERROR;
-    }
+static void
+ngx_http_groonga_each_loc_conf_in_tree(ngx_http_location_tree_node_t *node,
+                                       ngx_http_groonga_loc_conf_callback_pt callback,
+                                       void *user_data)
+{
+  if (!node) {
+    return;
   }
 
-  return NGX_CONF_OK;
+  if (node->exact && node->exact->handler == ngx_http_groonga_handler) {
+    callback(node->exact->loc_conf[ngx_http_groonga_module.ctx_index],
+             user_data);
+  }
+
+  if (node->inclusive && node->inclusive->handler == ngx_http_groonga_handler) {
+    callback(node->inclusive->loc_conf[ngx_http_groonga_module.ctx_index],
+             user_data);
+  }
+
+  ngx_http_groonga_each_loc_conf_in_tree(node->left, callback, user_data);
+  ngx_http_groonga_each_loc_conf_in_tree(node->right, callback, user_data);
+  ngx_http_groonga_each_loc_conf_in_tree(node->tree, callback, user_data);
+}
+
+static void
+ngx_http_groonga_each_loc_conf(ngx_http_conf_ctx_t *http_conf,
+                               ngx_http_groonga_loc_conf_callback_pt callback,
+                               void *user_data)
+{
+  ngx_http_core_main_conf_t *main_conf;
+  ngx_http_core_srv_conf_t **server_confs;
+  ngx_uint_t i;
+
+  if (!http_conf) {
+    return;
+  }
+
+  main_conf = http_conf->main_conf[ngx_http_core_module.ctx_index];
+  server_confs = main_conf->servers.elts;
+  for (i = 0; i < main_conf->servers.nelts; i++) {
+    ngx_http_core_srv_conf_t *server_conf;
+    ngx_http_core_loc_conf_t *location_conf;
+
+    server_conf = server_confs[i];
+    location_conf = server_conf->ctx->loc_conf[ngx_http_core_module.ctx_index];
+    ngx_http_groonga_each_loc_conf_in_tree(location_conf->static_locations,
+                                           callback,
+                                           user_data);
+  }
+}
+
+static void
+ngx_http_groonga_open_database_callback(ngx_http_groonga_loc_conf_t *location_conf,
+                                        void *user_data)
+{
+  ngx_http_groonga_database_callback_data_t *data = user_data;
+  grn_ctx *context;
+
+  context = &(location_conf->context);
+  grn_ctx_init(context, GRN_NO_FLAGS);
+
+  if (!location_conf->database_cstr) {
+    location_conf->database_cstr = ngx_str_null_terminate(&(location_conf->database));
+  }
+
+  grn_db_open(context, location_conf->database_cstr);
+  data->rc = ngx_http_groonga_context_check(data->log, context);
+}
+
+static void
+ngx_http_groonga_close_database_callback(ngx_http_groonga_loc_conf_t *location_conf,
+                                         void *user_data)
+{
+  ngx_http_groonga_database_callback_data_t *data = user_data;
+  grn_ctx *context;
+
+  context = &(location_conf->context);
+
+  grn_obj_close(context, grn_ctx_db(context));
+  ngx_http_groonga_context_check(data->log, context);
+  grn_ctx_fin(context);
+  ngx_http_groonga_context_check(data->log, context);
 }
 
 static ngx_int_t
-ngx_http_groonga_pre_configuration(ngx_conf_t *conf)
+ngx_http_groonga_init_process(ngx_cycle_t *cycle)
 {
   grn_rc rc;
+  ngx_http_conf_ctx_t *http_conf;
+  ngx_http_groonga_database_callback_data_t data;
 
   rc = grn_init();
   if (rc != GRN_SUCCESS) {
     return NGX_ERROR;
   }
 
+  http_conf =
+    (ngx_http_conf_ctx_t *)ngx_get_conf(cycle->conf_ctx, ngx_http_module);
+  data.log = cycle->log;
+  ngx_http_groonga_each_loc_conf(http_conf,
+                                 ngx_http_groonga_open_database_callback,
+                                 &data);
+
   return NGX_OK;
 }
 
 static void
-ngx_http_groonga_exit_master(ngx_cycle_t *cycle)
+ngx_http_groonga_exit_process(ngx_cycle_t *cycle)
 {
   grn_rc rc;
+  ngx_http_conf_ctx_t *http_conf;
+  ngx_http_groonga_database_callback_data_t data;
+
+  http_conf =
+    (ngx_http_conf_ctx_t *)ngx_get_conf(cycle->conf_ctx, ngx_http_module);
+  data.log = cycle->log;
+  ngx_http_groonga_each_loc_conf(http_conf,
+                                 ngx_http_groonga_close_database_callback,
+                                 &data);
 
   rc = grn_fin();
   if (rc != GRN_SUCCESS) {
-------------- next part --------------
HTML$B$NE:IU%U%!%$%k$rJ]4I$7$^$7$?(B...
下载 



Groonga-commit メーリングリストの案内
Back to archive index