[Groonga-commit] groonga/groonga at cc91e75 [master] groonga memcached: support accessing existing column

Back to archive index

Kouhei Sutou null+****@clear*****
Sun Feb 21 17:48:05 JST 2016


Kouhei Sutou	2016-02-21 17:48:05 +0900 (Sun, 21 Feb 2016)

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

  Message:
    groonga memcached: support accessing existing column
    
    For example, you can get/set Users.name column value via memcached
    binary protocol with the following command line:
    
        % groonga --protocol memcached --memcached-column Users.name -s DB

  Modified files:
    src/groonga.c

  Modified: src/groonga.c (+202 -38)
===================================================================
--- src/groonga.c    2016-02-21 14:58:11 +0900 (25998da)
+++ src/groonga.c    2016-02-21 17:48:05 +0900 (b158676)
@@ -1,6 +1,6 @@
 /* -*- c-basic-offset: 2 -*- */
 /*
-  Copyright(C) 2009-2015 Brazil
+  Copyright(C) 2009-2016 Brazil
 
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -98,6 +98,8 @@ static const char *pid_file_path = NULL;
 static const char *input_path = NULL;
 static grn_file_reader *input_reader = NULL;
 static FILE *output = NULL;
+static grn_bool is_memcached_mode = GRN_FALSE;
+static const char *memcached_column_name = NULL;
 
 static int ready_notify_pipe[2];
 #define PIPE_READ  0
@@ -729,6 +731,8 @@ run_server(grn_ctx *ctx, grn_obj *db, grn_com_event *ev,
   return exit_code;
 }
 
+static grn_bool memcached_init(grn_ctx *ctx);
+
 static int
 start_service(grn_ctx *ctx, const char *db_path,
               grn_edge_dispatcher_func dispatcher, grn_handler_func handler)
@@ -749,7 +753,17 @@ start_service(grn_ctx *ctx, const char *db_path,
     grn_obj *db;
     db = (newdb || !db_path) ? grn_db_create(ctx, db_path, NULL) : grn_db_open(ctx, db_path);
     if (db) {
-      exit_code = run_server(ctx, db, &ev, dispatcher, handler);
+      if (is_memcached_mode) {
+        if (!memcached_init(ctx)) {
+          fprintf(stderr, "failed to initialize memcached mode: %s\n",
+                  ctx->errbuf);
+          exit_code = EXIT_FAILURE;
+          send_ready_notify();
+        }
+      }
+      if (exit_code == EXIT_SUCCESS) {
+        exit_code = run_server(ctx, db, &ev, dispatcher, handler);
+      }
       grn_obj_close(ctx, db);
     } else {
       fprintf(stderr, "db open failed (%s): %s\n", db_path, ctx->errbuf);
@@ -1414,7 +1428,6 @@ enum {
   MBCMD_PREPENDQ = 0x1a
 };
 
-static grn_critical_section cache_lock;
 static grn_obj *cache_table = NULL;
 static grn_obj *cache_value = NULL;
 static grn_obj *cache_flags = NULL;
@@ -1423,39 +1436,189 @@ static grn_obj *cache_cas = NULL;
 
 #define CTX_GET(name) (grn_ctx_get(ctx, (name), strlen(name)))
 
-static grn_obj *
-cache_init(grn_ctx *ctx)
+static grn_bool
+memcached_setup_flags_column(grn_ctx *ctx, const char *name)
+{
+  cache_flags = grn_obj_column(ctx, cache_table, name, strlen(name));
+  if (cache_flags) {
+    return GRN_TRUE;
+  }
+
+  cache_flags = grn_column_create(ctx, cache_table, name, strlen(name), NULL,
+                                  GRN_OBJ_COLUMN_SCALAR|GRN_OBJ_PERSISTENT,
+                                  grn_ctx_at(ctx, GRN_DB_UINT32));
+  if (!cache_flags) {
+    return GRN_FALSE;
+  }
+
+  return GRN_TRUE;
+}
+
+static grn_bool
+memcached_setup_expire_column(grn_ctx *ctx, const char *name)
+{
+  cache_expire = grn_obj_column(ctx, cache_table, name, strlen(name));
+  if (cache_expire) {
+    return GRN_TRUE;
+  }
+
+  cache_expire = grn_column_create(ctx, cache_table, name, strlen(name), NULL,
+                                   GRN_OBJ_COLUMN_SCALAR|GRN_OBJ_PERSISTENT,
+                                   grn_ctx_at(ctx, GRN_DB_UINT32));
+  if (!cache_expire) {
+    return GRN_FALSE;
+  }
+
+  return GRN_TRUE;
+}
+
+static grn_bool
+memcached_setup_cas_column(grn_ctx *ctx, const char *name)
 {
-  if (cache_cas) { return cache_cas; }
-  CRITICAL_SECTION_ENTER(cache_lock);
+  cache_cas = grn_obj_column(ctx, cache_table, name, strlen(name));
+  if (cache_cas) {
+    return GRN_TRUE;
+  }
+
+  cache_cas = grn_column_create(ctx, cache_table, name, strlen(name), NULL,
+                                GRN_OBJ_COLUMN_SCALAR|GRN_OBJ_PERSISTENT,
+                                grn_ctx_at(ctx, GRN_DB_UINT64));
   if (!cache_cas) {
-    if ((cache_table = CTX_GET("Memcache"))) {
-      cache_value = CTX_GET("Memcache.value");
-      cache_flags = CTX_GET("Memcache.flags");
-      cache_expire = CTX_GET("Memcache.expire");
-      cache_cas = CTX_GET("Memcache.cas");
-    } else {
+    return GRN_FALSE;
+  }
+
+  return GRN_TRUE;
+}
+
+static grn_bool
+memcached_init(grn_ctx *ctx)
+{
+  if (memcached_column_name) {
+    cache_value = CTX_GET(memcached_column_name);
+    if (!cache_value) {
+      ERR(GRN_INVALID_ARGUMENT,
+          "memcached column doesn't exist: <%s>",
+          memcached_column_name);
+      return GRN_FALSE;
+    }
+    if (!(grn_obj_is_column(ctx, cache_value) &&
+          ((cache_value->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) ==
+           GRN_OBJ_COLUMN_SCALAR))) {
+      grn_obj inspected;
+      GRN_TEXT_INIT(&inspected, 0);
+      grn_inspect(ctx, &inspected, cache_value);
+      ERR(GRN_INVALID_ARGUMENT,
+          "memcached column must be scalar column: <%.*s>",
+          (int)GRN_TEXT_LEN(&inspected),
+          GRN_TEXT_VALUE(&inspected));
+      GRN_OBJ_FIN(ctx, &inspected);
+      return GRN_FALSE;
+    }
+    if (!(GRN_DB_SHORT_TEXT <= grn_obj_get_range(ctx, cache_value) &&
+          grn_obj_get_range(ctx, cache_value) <= GRN_DB_LONG_TEXT)) {
+      grn_obj inspected;
+      GRN_TEXT_INIT(&inspected, 0);
+      grn_inspect(ctx, &inspected, cache_value);
+      ERR(GRN_INVALID_ARGUMENT,
+          "memcached column must be text column: <%.*s>",
+          (int)GRN_TEXT_LEN(&inspected),
+          GRN_TEXT_VALUE(&inspected));
+      GRN_OBJ_FIN(ctx, &inspected);
+      return GRN_FALSE;
+    }
+
+    cache_table = grn_ctx_at(ctx, cache_value->header.domain);
+    if (cache_table->header.type == GRN_TABLE_NO_KEY) {
+      grn_obj inspected;
+      GRN_TEXT_INIT(&inspected, 0);
+      grn_inspect(ctx, &inspected, cache_table);
+      ERR(GRN_INVALID_ARGUMENT,
+          "memcached column's table must be HASH_KEY, PAT_KEY or DAT_KEY table: "
+          "<%.*s>",
+          (int)GRN_TEXT_LEN(&inspected),
+          GRN_TEXT_VALUE(&inspected));
+      GRN_OBJ_FIN(ctx, &inspected);
+      return GRN_FALSE;
+    }
+
+    {
+      char column_name[GRN_TABLE_MAX_KEY_SIZE];
+      char value_column_name[GRN_TABLE_MAX_KEY_SIZE];
+      int value_column_name_size;
+
+      value_column_name_size = grn_column_name(ctx, cache_value,
+                                               value_column_name,
+                                               GRN_TABLE_MAX_KEY_SIZE);
+      grn_snprintf(column_name,
+                   GRN_TABLE_MAX_KEY_SIZE,
+                   GRN_TABLE_MAX_KEY_SIZE,
+                   "%.*s_memcached_flags",
+                   value_column_name_size,
+                   value_column_name);
+      if (!memcached_setup_flags_column(ctx, column_name)) {
+        return GRN_FALSE;
+      }
+      grn_snprintf(column_name,
+                   GRN_TABLE_MAX_KEY_SIZE,
+                   GRN_TABLE_MAX_KEY_SIZE,
+                   "%.*s_memcached_expire",
+                   value_column_name_size,
+                   value_column_name);
+      if (!memcached_setup_expire_column(ctx, column_name)) {
+        return GRN_FALSE;
+      }
+      grn_snprintf(column_name,
+                   GRN_TABLE_MAX_KEY_SIZE,
+                   GRN_TABLE_MAX_KEY_SIZE,
+                   "%.*s_memcached_cas",
+                   value_column_name_size,
+                   value_column_name);
+      if (!memcached_setup_cas_column(ctx, column_name)) {
+        return GRN_FALSE;
+      }
+    }
+  } else {
+    const char *table_name = "Memcache";
+    const char *value_column_name = "value";
+
+    cache_table = CTX_GET(table_name);
+    if (!cache_table) {
+      cache_table = grn_table_create(ctx, table_name, strlen(table_name), NULL,
+                                     GRN_OBJ_TABLE_PAT_KEY|GRN_OBJ_PERSISTENT,
+                                     grn_ctx_at(ctx, GRN_DB_SHORT_TEXT),
+                                     NULL);
       if (!cache_table) {
-        grn_obj *uint32_type = grn_ctx_at(ctx, GRN_DB_UINT32);
-        grn_obj *uint64_type = grn_ctx_at(ctx, GRN_DB_UINT64);
-        grn_obj *shorttext_type = grn_ctx_at(ctx, GRN_DB_SHORT_TEXT);
-        if ((cache_table = grn_table_create(ctx, "Memcache", 8, NULL,
-                                            GRN_OBJ_TABLE_PAT_KEY|GRN_OBJ_PERSISTENT,
-                                            shorttext_type, NULL))) {
-          cache_value = grn_column_create(ctx, cache_table, "value", 5, NULL,
-                                          GRN_OBJ_PERSISTENT, shorttext_type);
-          cache_flags = grn_column_create(ctx, cache_table, "flags", 5, NULL,
-                                          GRN_OBJ_PERSISTENT, uint32_type);
-          cache_expire = grn_column_create(ctx, cache_table, "expire", 6, NULL,
-                                           GRN_OBJ_PERSISTENT, uint32_type);
-          cache_cas = grn_column_create(ctx, cache_table, "cas", 3, NULL,
-                                        GRN_OBJ_PERSISTENT, uint64_type);
-        }
+        return GRN_FALSE;
       }
     }
+
+    cache_value = grn_obj_column(ctx, cache_table,
+                                 value_column_name,
+                                 strlen(value_column_name));
+    if (!cache_value) {
+      cache_value = grn_column_create(ctx, cache_table,
+                                      value_column_name,
+                                      strlen(value_column_name),
+                                      NULL,
+                                      GRN_OBJ_COLUMN_SCALAR|GRN_OBJ_PERSISTENT,
+                                      grn_ctx_at(ctx, GRN_DB_SHORT_TEXT));
+      if (!cache_value) {
+        return GRN_FALSE;
+      }
+    }
+
+    if (!memcached_setup_flags_column(ctx, "flags")) {
+      return GRN_FALSE;
+    }
+    if (!memcached_setup_expire_column(ctx, "expire")) {
+      return GRN_FALSE;
+    }
+    if (!memcached_setup_cas_column(ctx, "cas")) {
+      return GRN_FALSE;
+    }
   }
-  CRITICAL_SECTION_LEAVE(cache_lock);
-  return cache_cas;
+
+  return GRN_TRUE;
 }
 
 #define RELATIVE_TIME_THRESH 1000000000
@@ -1498,7 +1661,6 @@ do_mbreq(grn_ctx *ctx, grn_edge *edge)
       grn_id rid;
       uint16_t keylen = ntohs(header->keylen);
       char *key = GRN_BULK_HEAD((grn_obj *)msg);
-      cache_init(ctx);
       rid = grn_table_get(ctx, cache_table, key, keylen);
       if (!rid) {
         GRN_MSG_MBRES({
@@ -1558,7 +1720,6 @@ do_mbreq(grn_ctx *ctx, grn_edge *edge)
       int f = (header->qtype == MBCMD_REPLACE ||
                header->qtype == MBCMD_REPLACEQ) ? 0 : GRN_TABLE_ADD;
       GRN_ASSERT(extralen == 8);
-      cache_init(ctx);
       if (header->qtype == MBCMD_REPLACE || header->qtype == MBCMD_REPLACEQ) {
         rid = grn_table_get(ctx, cache_table, key, keylen);
       } else {
@@ -1682,7 +1843,6 @@ do_mbreq(grn_ctx *ctx, grn_edge *edge)
       grn_id rid;
       uint16_t keylen = ntohs(header->keylen);
       char *key = GRN_BULK_HEAD((grn_obj *)msg);
-      cache_init(ctx);
       rid = grn_table_get(ctx, cache_table, key, keylen);
       if (!rid) {
         /* GRN_LOG(ctx, GRN_LOG_NOTICE, "GET k=%d not found", keylen); */
@@ -1714,7 +1874,6 @@ do_mbreq(grn_ctx *ctx, grn_edge *edge)
       grn_ntoh(&delta, body, 8);
       grn_ntoh(&init, body + 8, 8);
       GRN_ASSERT(header->level == 20); /* extralen */
-      cache_init(ctx);
       if (expire == 0xffffffff) {
         rid = grn_table_get(ctx, cache_table, key, keylen);
       } else {
@@ -1836,7 +1995,6 @@ do_mbreq(grn_ctx *ctx, grn_edge *edge)
       grn_id rid;
       uint16_t keylen = ntohs(header->keylen);
       char *key = GRN_BULK_HEAD((grn_obj *)msg);
-      cache_init(ctx);
       rid = grn_table_get(ctx, cache_table, key, keylen);
       if (!rid) {
         GRN_MSG_MBRES({
@@ -1883,7 +2041,6 @@ do_mbreq(grn_ctx *ctx, grn_edge *edge)
       char *key = GRN_BULK_HEAD((grn_obj *)msg);
       char *value = key + keylen;
       uint32_t valuelen = size - keylen;
-      cache_init(ctx);
       rid = grn_table_add(ctx, cache_table, key, keylen, NULL);
       if (!rid) {
         GRN_MSG_MBRES({
@@ -2681,6 +2838,12 @@ show_usage(FILE *output)
           "      --pid-path <path>:        specify file to write process ID to\n"
           "                                (daemon mode only)\n"
           "\n"
+          "Memcached options:\n"
+          "      --memcached-column <column>:\n"
+          "                                specify column to access by memcached protocol\n"
+          "                                The column must be text type column and\n"
+          "                                its table must be not NO_KEY table\n"
+          "\n"
           "Logging options:\n"
           "  -l, --log-level <log level>:\n"
           "                           specify log level\n"
@@ -2799,6 +2962,7 @@ main(int argc, char **argv)
     {'\0', "working-directory", NULL, 0, GETOPT_OP_NONE},
     {'\0', "use-windows-event-log", NULL,
      FLAG_USE_WINDOWS_EVENT_LOG, GETOPT_OP_ON},
+    {'\0', "memcached-column", NULL, 0, GETOPT_OP_NONE},
     {'\0', NULL, NULL, 0, 0}
   };
   opts[0].arg = &port_arg;
@@ -2822,6 +2986,7 @@ main(int argc, char **argv)
   opts[25].arg = &input_fd_arg;
   opts[26].arg = &output_fd_arg;
   opts[27].arg = &working_directory_arg;
+  opts[29].arg = &memcached_column_name;
 
   reset_ready_notify_pipe();
 
@@ -2958,6 +3123,7 @@ main(int argc, char **argv)
       break;
     case 'm' :
     case 'M' :
+      is_memcached_mode = GRN_TRUE;
       do_client = g_client;
       do_server = g_server;
       break;
@@ -3191,7 +3357,6 @@ main(int argc, char **argv)
 
   MUTEX_INIT(q_mutex);
   COND_INIT(q_cond);
-  CRITICAL_SECTION_INIT(cache_lock);
 
   if (input_path) {
     input_reader = grn_file_reader_open(&grn_gctx, input_path);
@@ -3256,7 +3421,6 @@ main(int argc, char **argv)
     exit_code = do_alone(argc - i, argv + i);
   }
 
-  CRITICAL_SECTION_FIN(cache_lock);
   COND_FIN(q_cond);
   MUTEX_FIN(q_mutex);
 
-------------- next part --------------
HTML����������������������������...
Download 



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