[Groonga-commit] droonga/droonga.org at 1e5e09e [gh-pages] Complete tutorial to develop handlers

Back to archive index

YUKI Hiroshi null+****@clear*****
Thu Feb 27 17:33:36 JST 2014


YUKI Hiroshi	2014-02-27 17:33:36 +0900 (Thu, 27 Feb 2014)

  New Revision: 1e5e09e527e1cab000969b429c61e479fafbf9c3
  https://github.com/droonga/droonga.org/commit/1e5e09e527e1cab000969b429c61e479fafbf9c3

  Message:
    Complete tutorial to develop handlers

  Modified files:
    tutorial/plugin-development/adapter/index.md
    tutorial/plugin-development/handler/index.md
    tutorial/plugin-development/index.md

  Modified: tutorial/plugin-development/adapter/index.md (+3 -1)
===================================================================
--- tutorial/plugin-development/adapter/index.md    2014-02-27 17:19:58 +0900 (d106076)
+++ tutorial/plugin-development/adapter/index.md    2014-02-27 17:33:36 +0900 (b566faf)
@@ -63,7 +63,9 @@ require "droonga/plugin"
 module Droonga
   module Plugins
     module SampleLoggerPlugin
-      Plugin.registry.register("sample-logger", self)
+      extend Plugin
+
+      registry.register("sample-logger", self)
 
       class Adapter < Droonga::Adapter
         # You'll put codes to modify messages here.

  Modified: tutorial/plugin-development/handler/index.md (+198 -27)
===================================================================
--- tutorial/plugin-development/handler/index.md    2014-02-27 17:19:58 +0900 (8a7d691)
+++ tutorial/plugin-development/handler/index.md    2014-02-27 17:33:36 +0900 (b02bbd3)
@@ -1,10 +1,8 @@
 ---
-title: "Plugin: Handle requests"
+title: "Plugin: Handle requests on all partitions"
 layout: en
 ---
 
-!!! WORK IN PROGRESS !!!
-
 * TOC
 {:toc}
 
@@ -39,7 +37,11 @@ A class to define operations at the handling phase is called *handler*.
 Put simply, adding of a new handler means adding a new command.
 
 
-## Design a read-only command
+
+
+
+
+## Design a read-only command `countRecords`
 
 Here, in this tutorial, we are going to add a new custom `countRecords` command.
 At first, let's design it.
@@ -184,13 +186,13 @@ Then, we also have to bind a collector to the step, with the configuration `step
 lib/droonga/plugins/count-records.rb:
 
 ~~~ruby
-...
+(snip)
       define_single_step do |step|
         step.name = "countRecords"
         step.handler = :Handler
         step.collector = SumCollector
       end
-...
+(snip)
 ~~~
 
 The `SumCollector` is one of built-in collectors.
@@ -211,7 +213,7 @@ Add `"count-records"` to `"plugins"`.
 (snip)
 ~~~
 
-### Run
+### Run and test
 
 Let's get Droonga started.
 Note that you need to specify ./lib directory in RUBYLIB environment variable in order to make ruby possible to find your plugin.
@@ -219,9 +221,7 @@ Note that you need to specify ./lib directory in RUBYLIB environment variable in
     # kill $(cat fluentd.pid)
     # RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid
 
-### Test
-
-Send a message for the `countRecords` command to the Droonga Engine.
+Then, send a message for the `countRecords` command to the Droonga Engine.
 
 ~~~
 # droonga-request --tag starbucks count-records.json
@@ -238,7 +238,7 @@ Elapsed time: 0.01494
 ]
 ~~~
 
-Then you'll get a response message like above.
+You'll get a response message like above.
 Look at these points:
 
  * The `type` of the response becomes `countRecords.result`.
@@ -250,11 +250,10 @@ There are 3 elements in the array. Why?
  * Remember that we have configured the `Starbucks` dataset to use 3 partitions (and each has 2 replicas) in the `catalog.json` of [the basic tutorial][basic].
  * Because it is a read-only command, an incoming message is distributed only to paritions, not to replicas.
    So there are only 3 results, not 6.
+   (TODO: I have to add a figure to indicate active nodes: [000, 001, 010, 011, 020, 021] => [000, 011, 020])
  * The `SumCollector` collects them.
    Those 3 results are joined to just one array by the collector.
 
-(TODO: I have to add a figure to indicate active nodes: [000, 001, 010, 011, 020, 021] => [000, 011, 020])
-
 As the result, just one array with 3 elements appears in the response message.
 
 ### Read-only access to the storage
@@ -265,7 +264,7 @@ Let's implement codes to count up the number of records from the actual storage.
 lib/droonga/plugins/count-records.rb:
 
 ~~~ruby
-...
+(snip)
       class Handler < Droonga::Handler
         def handle(message)
           table_name = message["body"]["table"]
@@ -274,7 +273,7 @@ lib/droonga/plugins/count-records.rb:
           [count]
         end
       end
-...
+(snip)
 ~~~
 
 The instance variable `@context` is an instance of `Groonga::Context` for the storage of the partition.
@@ -305,33 +304,204 @@ Elapsed time: 0.01494
 Because there are totally 35 records, they are stored evenly like above.
 
 
-## Read-write handler
 
-(TBD)
+
+
+
+
+## Design a read-write command `deleteStores`
+
+Next, let's add another new custom command `deleteStores`.
+
+The command deletes records of the `Store` table, from the storage.
+Because it modifies something in existing storage, it is a *read-write command*.
+
+The request must have the condition to select records to be deleted, like:
+
+~~~json
+{
+  "dataset" : "Starbucks",
+  "type"    : "deleteStores",
+  "body"    : {
+    "keyword": "Broardway"
+  }
+}
+~~~
+
+Any record including the given keyword `"Broadway"` in its `"key"` is deleted from the storage of all partitions.
+
+Create a JSON file `delete-stores-broadway.json` with the content above.
+We'll use it for testing.
+
+The response must have a boolean value to indicate "success" or "fail", like:
+
+~~~json
+{
+  "inReplyTo": "(message id)",
+  "statusCode": 200,
+  "type": "deleteStores.result",
+  "body": true
+}
+~~~
+
+If the request is successfully processed, the `body` becomes `true`. Otherwise `false`.
+The `body` is just one boolean value, because we don't have to receive multiple results from partitions.
+
 
 ### Directory Structure
 
-(TBD)
+Now let's create the `delete-stores` plugin, as the file `delete-stores.rb`. The directory tree will be:
+
+~~~
+lib
+└── droonga
+    └── plugins
+            └── delete-stores.rb
+~~~
+
+Then, create a skelton of a plugin as follows:
+
+lib/droonga/plugins/delete-stores.rb:
+
+~~~ruby
+require "droonga/plugin"
+
+module Droonga
+  module Plugins
+    module DeleteStoresPlugin
+      Plugin.registry.register("delete-stores", self)
+    end
+  end
+end
+~~~
+
+
+### Define a "step" for the command
+
+Define a "step" for the new `deleteStores` command, in your plugin. Like:
+
+lib/droonga/plugins/delete-stores.rb:
+
+~~~ruby
+require "droonga/plugin"
+
+module Droonga
+  module Plugins
+    module DeleteStoresPlugin
+      Plugin.registry.register("delete-stores", self)
+
+      define_single_step do |step|
+        step.name = "deleteStores"
+        step.write = true
+      end
+    end
+  end
+end
+~~~
+
+Look at a new configuration `step.write`.
+Because this command modifies the storage, we must indicate it clearly.
+
+### Define the handling logic
+
+Let's define the handler.
+
+lib/droonga/plugins/delete-stores.rb:
+
+~~~ruby
+require "droonga/plugin"
+
+module Droonga
+  module Plugins
+    module DeleteStoresPlugin
+      Plugin.registry.register("delete-stores", self)
+
+      define_single_step do |step|
+        step.name = "deleteStores"
+        step.write = true
+        step.handler = :Handler
+        step.collector = AndCollector
+      end
+
+      class Handler < Droonga::Handler
+        def handle(message)
+          keyword = message["body"]["keyword"]
+          table = @context["Store"]
+          table.delete do |record|
+            record.key @ keyword
+          end
+          true
+        end
+      end
+    end
+  end
+end
+~~~
+
+The handler finds and deletes existing records which have the given keyword in its "key", by the [API of Rroonga][Groonga::Table_delete].
+
+And, the `AndCollector` is bound to the step by the configuration `step.collector`.
+It is is also one of built-in collectors, and merges boolean values retuned from handler instances for each partition and replica, to one boolean value.
 
-### Create a plugin
 
-(TBD)
 
 ### Activate the plugin with `catalog.json`
 
-(TBD)
+Update catalog.json to activate this plugin.
+Add `"delete-stores"` to `"plugins"`.
+
+~~~
+(snip)
+      "datasets": {
+        "Starbucks": {
+          (snip)
+          "plugins": ["delete-stores", "count-records", "groonga", "crud", "search"],
+(snip)
+~~~
+
+### Run and test
 
-### Run
+Restart the Droonga Engine and send the request.
 
-(TBD)
+~~~
+# kill $(cat fluentd.pid)
+# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid
+# droonga-request --tag starbucks count-records.json
+Elapsed time: 0.01494
+[
+  "droonga.message",
+  1392621168,
+  {
+    "inReplyTo": "1392621168.0119512",
+    "statusCode": 200,
+    "type": "deleteStores.result",
+    "body": true
+  }
+]
+~~~
 
-### Test
+Because results from partitions are unified to just one boolean value, the response's `body` is a `true`.
+As the verification, send the request of `countRecords` command.
+
+~~~
+# droonga-request --tag starbucks count-records.json
+Elapsed time: 0.01494
+[
+  "droonga.message",
+  1392621168,
+  {
+    "inReplyTo": "1392621168.0119512",
+    "statusCode": 200,
+    "type": "countRecords.result",
+    "body": [8, 8, 7]
+  }
+]
+~~~
 
-(TBD)
+Note, the number of records are smaller than the previous result.
+This means that 4 or some records are deleted from each partitions.
 
-### Design input and output
 
-(TBD)
 
 
 ## Conclusion
@@ -342,3 +512,4 @@ We have learned how to create plugins work in handling phrase.
   [adapter]: ../adapter
   [basic]: ../basic
   [Groonga::Context]: http://ranguba.org/rroonga/en/Groonga/Context.html
+  [Groonga::Table_delete]: http://ranguba.org/rroonga/en/Groonga/Table.html#delete-instance_method

  Modified: tutorial/plugin-development/index.md (+3 -2)
===================================================================
--- tutorial/plugin-development/index.md    2014-02-27 17:19:58 +0900 (fcc9f2f)
+++ tutorial/plugin-development/index.md    2014-02-27 17:33:36 +0900 (a466dfb)
@@ -58,8 +58,9 @@ Following this tutorial, you will learn how to write plugins. This will be the f
 For more details, let's read these sub tutorials:
 
  1. [Modify requests and responses][adapter]
- 2. [Handle requests][handler] (under construction)
- 3. Distribute requests and collect responses (under construction)
+ 2. [Handle requests on all partitions][handler]
+ 3. Handle requests only on a specific partition (under construction)
+ 4. Distribute requests and collect responses (under construction)
 
 
   [basic tutorial]: ../basic/
-------------- next part --------------
HTML����������������������������...
下載 



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