[Groonga-commit] groonga/groonga at 99dc6bf [master] groonga-httpd: support streaming dump

Back to archive index

Kouhei Sutou null+****@clear*****
Wed Jan 7 23:39:01 JST 2015


Kouhei Sutou	2015-01-07 23:39:01 +0900 (Wed, 07 Jan 2015)

  New Revision: 99dc6bfb9209e15a6e8982ae98d76f0f82240c55
  https://github.com/groonga/groonga/commit/99dc6bfb9209e15a6e8982ae98d76f0f82240c55

  Message:
    groonga-httpd: support streaming dump

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

  Modified: src/httpd/nginx-module/ngx_http_groonga_module.c (+142 -39)
===================================================================
--- src/httpd/nginx-module/ngx_http_groonga_module.c    2015-01-07 18:54:37 +0900 (1b8d87f)
+++ src/httpd/nginx-module/ngx_http_groonga_module.c    2015-01-07 23:39:01 +0900 (4f51f42)
@@ -1,6 +1,6 @@
 /* -*- c-basic-offset: 2 -*- */
 /*
-  Copyright(C) 2012-2014 Brazil
+  Copyright(C) 2012-2015 Brazil
 
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -63,9 +63,17 @@ typedef struct {
 typedef struct {
   grn_bool initialized;
   grn_ctx context;
-  grn_obj head;
-  grn_obj body;
-  grn_obj foot;
+  struct {
+    grn_bool processed;
+    grn_bool header_sent;
+    ngx_http_request_t *r;
+    ngx_int_t rc;
+  } raw;
+  struct {
+    grn_obj head;
+    grn_obj body;
+    grn_obj foot;
+  } typed;
 } ngx_http_groonga_handler_data_t;
 
 typedef struct {
@@ -358,20 +366,97 @@ ngx_http_groonga_handler_cleanup(void *user_data)
   }
 
   context = &(data->context);
-  GRN_OBJ_FIN(context, &(data->head));
-  GRN_OBJ_FIN(context, &(data->body));
-  GRN_OBJ_FIN(context, &(data->foot));
+  GRN_OBJ_FIN(context, &(data->typed.head));
+  GRN_OBJ_FIN(context, &(data->typed.body));
+  GRN_OBJ_FIN(context, &(data->typed.foot));
   grn_logger_set(context, NULL);
   grn_query_logger_set(context, NULL);
   grn_ctx_fin(context);
 }
 
 static void
-ngx_http_groonga_context_receive_handler(grn_ctx *context,
-                                         int flags,
-                                         void *callback_data)
+ngx_http_groonga_handler_set_content_type(ngx_http_request_t *r,
+                                          const char *content_type)
+{
+  r->headers_out.content_type.len = strlen(content_type);
+  r->headers_out.content_type.data = (u_char *)content_type;
+  r->headers_out.content_type_len = r->headers_out.content_type.len;
+}
+
+static void
+ngx_http_groonga_context_receive_handler_raw(grn_ctx *context,
+                                             int flags,
+                                             ngx_http_groonga_handler_data_t *data)
+{
+  char *chunk = NULL;
+  unsigned int chunk_size = 0;
+  int recv_flags;
+  ngx_http_request_t *r;
+  ngx_log_t *log;
+  grn_bool is_last_chunk;
+
+  grn_ctx_recv(context, &chunk, &chunk_size, &recv_flags);
+  data->raw.processed = GRN_TRUE;
+
+  if (data->raw.rc != NGX_OK) {
+    return;
+  }
+
+  r = data->raw.r;
+  log = r->connection->log;
+  is_last_chunk = (flags & GRN_CTX_TAIL);
+
+  if (!data->raw.header_sent) {
+    ngx_http_groonga_handler_set_content_type(r, grn_ctx_get_mime_type(context));
+    r->headers_out.status = NGX_HTTP_OK;
+    if (is_last_chunk) {
+      r->headers_out.content_length_n = chunk_size;
+    } else {
+      r->headers_out.content_length_n = -1;
+    }
+    if (chunk_size == 0) {
+      r->header_only = 1;
+    }
+    data->raw.rc = ngx_http_send_header(r);
+    data->raw.header_sent = GRN_TRUE;
+
+    if (data->raw.rc != NGX_OK) {
+      return;
+    }
+  }
+
+  if (chunk_size > 0) {
+    ngx_chain_t chain;
+    ngx_buf_t *buffer;
+
+    buffer = ngx_palloc(r->pool, sizeof(ngx_buf_t));
+    if (!buffer) {
+      ngx_log_error(NGX_LOG_ERR, log, 0,
+                    "http_groonga: failed to allocate memory for chunked body");
+      data->raw.rc = NGX_ERROR;
+      return;
+    }
+    buffer->pos = (u_char *)chunk;
+    buffer->last = (u_char *)chunk + chunk_size;
+    buffer->memory = 1;
+    buffer->in_file = 0;
+    if (is_last_chunk) {
+      buffer->last_buf = 1;
+    } else {
+      buffer->last_buf = 0;
+    }
+    chain.buf = buffer;
+    chain.next = NULL;
+
+    data->raw.rc = ngx_http_output_filter(r, &chain);
+  }
+}
+
+static void
+ngx_http_groonga_context_receive_handler_typed(grn_ctx *context,
+                                               int flags,
+                                               ngx_http_groonga_handler_data_t *data)
 {
-  ngx_http_groonga_handler_data_t *data = callback_data;
   char *result = NULL;
   unsigned int result_size = 0;
   int recv_flags;
@@ -402,29 +487,43 @@ ngx_http_groonga_context_receive_handler(grn_ctx *context,
       context->stat |= GRN_CTX_QUIT;
     } else {
       context->rc = GRN_OPERATION_NOT_PERMITTED;
-      GRN_TEXT_PUTS(context, &(data->body), "false");
+      GRN_TEXT_PUTS(context, &(data->typed.body), "false");
       context->stat &= ~GRN_CTX_QUIT;
     }
   }
 #endif
 
   if (result_size > 0 ||
-      GRN_TEXT_LEN(&(data->body)) > 0 ||
+      GRN_TEXT_LEN(&(data->typed.body)) > 0 ||
       context->rc != GRN_SUCCESS) {
     if (result_size > 0) {
-      GRN_TEXT_PUT(context, &(data->body), result, result_size);
+      GRN_TEXT_PUT(context, &(data->typed.body), result, result_size);
     }
 
     grn_output_envelope(context,
                         context->rc,
-                        &(data->head),
-                        &(data->body),
-                        &(data->foot),
+                        &(data->typed.head),
+                        &(data->typed.body),
+                        &(data->typed.foot),
                         NULL,
                         0);
   }
 }
 
+static void
+ngx_http_groonga_context_receive_handler(grn_ctx *context,
+                                         int flags,
+                                         void *callback_data)
+{
+  ngx_http_groonga_handler_data_t *data = callback_data;
+
+  if (grn_ctx_get_output_type(context) == GRN_CONTENT_NONE) {
+    ngx_http_groonga_context_receive_handler_raw(context, flags, data);
+  } else {
+    ngx_http_groonga_context_receive_handler_typed(context, flags, data);
+  }
+}
+
 static ngx_int_t
 ngx_http_groonga_extract_command_path(ngx_http_request_t *r,
                                       ngx_str_t *command_path)
@@ -470,15 +569,6 @@ ngx_http_groonga_extract_command_path(ngx_http_request_t *r,
   return NGX_OK;
 }
 
-static void
-ngx_http_groonga_handler_set_content_type(ngx_http_request_t *r,
-                                          const char *content_type)
-{
-  r->headers_out.content_type.len = strlen(content_type);
-  r->headers_out.content_type.data = (u_char *)content_type;
-  r->headers_out.content_type_len = r->headers_out.content_type.len;
-}
-
 static ngx_int_t
 ngx_http_groonga_handler_create_data(ngx_http_request_t *r,
                                      ngx_http_groonga_handler_data_t **data_return)
@@ -505,10 +595,18 @@ ngx_http_groonga_handler_create_data(ngx_http_request_t *r,
   if (rc != NGX_OK) {
     return rc;
   }
+
   data->initialized = GRN_TRUE;
-  GRN_TEXT_INIT(&(data->head), GRN_NO_FLAGS);
-  GRN_TEXT_INIT(&(data->body), GRN_NO_FLAGS);
-  GRN_TEXT_INIT(&(data->foot), GRN_NO_FLAGS);
+
+  data->raw.processed = GRN_FALSE;
+  data->raw.header_sent = GRN_FALSE;
+  data->raw.r = r;
+  data->raw.rc = NGX_OK;
+
+  GRN_TEXT_INIT(&(data->typed.head), GRN_NO_FLAGS);
+  GRN_TEXT_INIT(&(data->typed.body), GRN_NO_FLAGS);
+  GRN_TEXT_INIT(&(data->typed.foot), GRN_NO_FLAGS);
+
   grn_ctx_use(context, grn_ctx_db(&(location_conf->context)));
   rc = ngx_http_groonga_context_check_error(r->connection->log, context);
   if (rc != NGX_OK) {
@@ -562,9 +660,10 @@ ngx_http_groonga_handler_validate_post_command(ngx_http_request_t *r,
 
   context = &(data->context);
   ngx_http_groonga_handler_set_content_type(r, "text/plain");
-  GRN_TEXT_PUTS(context, &(data->body), "command for POST must be <load>: <");
-  GRN_TEXT_PUT(context, &(data->body), command.data, command.len);
-  GRN_TEXT_PUTS(context, &(data->body), ">");
+  GRN_TEXT_PUTS(context, &(data->typed.body),
+                "command for POST must be <load>: <");
+  GRN_TEXT_PUT(context, &(data->typed.body), command.data, command.len);
+  GRN_TEXT_PUTS(context, &(data->typed.body), ">");
 
   return NGX_HTTP_BAD_REQUEST;
 }
@@ -674,7 +773,7 @@ ngx_http_groonga_handler_process_body(ngx_http_request_t *r,
   body = r->request_body->bufs->buf;
   if (!body) {
     ngx_http_groonga_handler_set_content_type(r, "text/plain");
-    GRN_TEXT_PUTS(context, &(data->body), "must send load data as body");
+    GRN_TEXT_PUTS(context, &(data->typed.body), "must send load data as body");
     return NGX_HTTP_BAD_REQUEST;
   }
 
@@ -753,6 +852,10 @@ ngx_http_groonga_handler_send_response(ngx_http_request_t *r,
   ngx_chain_t head_chain, body_chain, foot_chain;
   ngx_chain_t *output_chain = NULL;
 
+  if (data->raw.processed) {
+    return data->raw.rc;
+  }
+
   context = &(data->context);
 
   /* set the 'Content-type' header */
@@ -762,17 +865,17 @@ ngx_http_groonga_handler_send_response(ngx_http_request_t *r,
   }
 
   /* allocate buffers for a response body */
-  head_buf = ngx_http_groonga_grn_obj_to_ngx_buf(r->pool, &(data->head));
+  head_buf = ngx_http_groonga_grn_obj_to_ngx_buf(r->pool, &(data->typed.head));
   if (!head_buf) {
     return NGX_HTTP_INTERNAL_SERVER_ERROR;
   }
 
-  body_buf = ngx_http_groonga_grn_obj_to_ngx_buf(r->pool, &(data->body));
+  body_buf = ngx_http_groonga_grn_obj_to_ngx_buf(r->pool, &(data->typed.body));
   if (!body_buf) {
     return NGX_HTTP_INTERNAL_SERVER_ERROR;
   }
 
-  foot_buf = ngx_http_groonga_grn_obj_to_ngx_buf(r->pool, &(data->foot));
+  foot_buf = ngx_http_groonga_grn_obj_to_ngx_buf(r->pool, &(data->typed.foot));
   if (!foot_buf) {
     return NGX_HTTP_INTERNAL_SERVER_ERROR;
   }
@@ -787,9 +890,9 @@ ngx_http_groonga_handler_send_response(ngx_http_request_t *r,
 
   /* set the status line */
   r->headers_out.status = NGX_HTTP_OK;
-  r->headers_out.content_length_n = GRN_TEXT_LEN(&(data->head)) +
-                                    GRN_TEXT_LEN(&(data->body)) +
-                                    GRN_TEXT_LEN(&(data->foot));
+  r->headers_out.content_length_n = GRN_TEXT_LEN(&(data->typed.head)) +
+                                    GRN_TEXT_LEN(&(data->typed.body)) +
+                                    GRN_TEXT_LEN(&(data->typed.foot));
   if (r->headers_out.content_length_n == 0) {
     r->header_only = 1;
   }
-------------- next part --------------
HTML����������������������������...
Download 



More information about the Groonga-commit mailing list
Back to archive index