[Groonga-commit] groonga/groonga-query-log at cc1dd4a [master] Add groonga-query-log-verify-server command

Back to archive index

Kouhei Sutou null+****@clear*****
Mon Dec 16 18:44:56 JST 2013


Kouhei Sutou	2013-12-16 18:44:56 +0900 (Mon, 16 Dec 2013)

  New Revision: cc1dd4aa70c4acb49cc9094a0f9248fb85ab28eb
  https://github.com/groonga/groonga-query-log/commit/cc1dd4aa70c4acb49cc9094a0f9248fb85ab28eb

  Message:
    Add groonga-query-log-verify-server command
    
    It verifies that two Groonga servers returns the same response for the
    same request. Request list is created from query log.

  Added files:
    lib/groonga/query-log/command/verify-server.rb
    lib/groonga/query-log/server-verifier.rb
  Copied files:
    bin/groonga-query-log-verify-server
      (from lib/groonga/query-log.rb)
  Modified files:
    lib/groonga/query-log.rb

  Copied: bin/groonga-query-log-verify-server (+6 -6) 76%
  Mode: 100644 -> 100755
===================================================================
--- lib/groonga/query-log.rb    2013-12-16 16:32:05 +0900 (3524c0a)
+++ bin/groonga-query-log-verify-server    2013-12-16 18:44:56 +0900 (89150ae)
@@ -1,6 +1,7 @@
+#!/usr/bin/env ruby
 # -*- coding: utf-8 -*-
 #
-# Copyright (C) 2012  Kouhei Sutou <kou �� clear-code.com>
+# Copyright (C) 2013  Kouhei Sutou <kou �� clear-code.com>
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -16,8 +17,7 @@
 # License along with this library; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
-require "groonga/query-log/version"
-require "groonga/query-log/analyzer"
-require "groonga/query-log/extractor"
-require "groonga/query-log/parser"
-require "groonga/query-log/replayer"
+require "groonga/query-log/command/verify-server"
+
+verify_server_command = Groonga::QueryLog::Command::VerifyServer.new
+verify_server_command.run(*ARGV)

  Modified: lib/groonga/query-log.rb (+1 -0)
===================================================================
--- lib/groonga/query-log.rb    2013-12-16 16:32:05 +0900 (3524c0a)
+++ lib/groonga/query-log.rb    2013-12-16 18:44:56 +0900 (8af3ad4)
@@ -21,3 +21,4 @@ require "groonga/query-log/analyzer"
 require "groonga/query-log/extractor"
 require "groonga/query-log/parser"
 require "groonga/query-log/replayer"
+require "groonga/query-log/server-verifier"

  Added: lib/groonga/query-log/command/verify-server.rb (+131 -0) 100644
===================================================================
--- /dev/null
+++ lib/groonga/query-log/command/verify-server.rb    2013-12-16 18:44:56 +0900 (deaa929)
@@ -0,0 +1,131 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2013  Kouhei Sutou <kou �� clear-code.com>
+#
+# 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.
+#
+# 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
+
+require "optparse"
+
+require "groonga/query-log"
+
+module Groonga
+  module QueryLog
+    module Command
+      class VerifyServer
+        def initialize
+          @options = ServerVerifier::Options.new
+        end
+
+        def run(*command_line)
+          input_paths = create_parser.parse(*command_line)
+          verifier = ServerVerifier.new(@options)
+          input_paths.each do |input_path|
+            File.open(input_path) do |input|
+              verifier.verify(input)
+            end
+          end
+        end
+
+        private
+        def create_parser
+          parser = OptionParser.new
+          parser.version = VERSION
+          parser.banner += " QUERY_LOG1 QUERY_LOG2 ..."
+
+          parser.separator("")
+          parser.separator("Options:")
+
+          available_protocols = [:gqtp, :http]
+          available_protocols_label = "[#{available_protocols.join(', ')}]"
+
+          parser.on("--groonga1-host=HOST",
+                    "Host name or IP address of Groonga server 1",
+                    "[#{@options.groonga1.host}]") do |host|
+            @options.groonga1.host = host
+          end
+
+          parser.on("--groonga1-port=PORT", Integer,
+                    "Port number of Groonga server 1",
+                    "[#{@options.groonga1.port}]") do |port|
+            @options.groonga1.port = port
+          end
+
+          parser.on("--groonga1-protocol=PROTOCOL", available_protocols,
+                    "Protocol of Groonga server 1",
+                    available_protocols_label) do |protocol|
+            @options.groonga1.protocol = protocol
+          end
+
+          parser.on("--groonga2-host=HOST",
+                    "Host name or IP address of Groonga server 2",
+                    "[#{@options.groonga2.host}]") do |host|
+            @options.groonga2.host = host
+          end
+
+          parser.on("--groonga2-port=PORT", Integer,
+                    "Port number of Groonga server 2",
+                    "[#{@options.groonga2.port}]") do |port|
+            @options.groonga2.port = port
+          end
+
+          parser.on("--groonga2-protocol=PROTOCOL", available_protocols,
+                    "Protocol of Groonga server 2",
+                    available_protocols_label) do |protocol|
+            @options.groonga2.protocol = protocol
+          end
+
+          parser.on("--n-clients=N", Integer,
+                    "The max number of concurrency",
+                    "[#{@options.n_clients}]") do |n_clients|
+            @options.n_clients = n_clients
+          end
+
+          parser.on("--request-queue-size=SIZE", Integer,
+                    "The size of request queue",
+                    "[auto]") do |size|
+            @options.request_queue_size = size
+          end
+
+          parser.on("--disable-cache",
+                    "Add 'cache=no' parameter to request",
+                    "[#{@options.disable_cache?}]") do
+            @options.disable_cache = true
+          end
+
+          parser.on("--target-command-name=NAME",
+                    "Add NAME to target command names",
+                    "You can specify this option zero or more times",
+                    "See also --target-command-names") do |name|
+            @options.target_command_names << name
+          end
+
+          target_command_names_label =****@optio*****_command_names.join(", ")
+          parser.on("--target-command-names=NAME1,NAME2,...", Array,
+                    "Replay only NAME1,NAME2,... commands",
+                    "You can use glob to choose command name",
+                    "[#{target_command_names_label}]") do |names|
+            @options.target_command_names = names
+          end
+
+          parser.on("--output=PATH",
+                    "Output results to PATH",
+                    "[stdout]") do |path|
+            @options.output_path = path
+          end
+        end
+      end
+    end
+  end
+end

  Added: lib/groonga/query-log/server-verifier.rb (+188 -0) 100644
===================================================================
--- /dev/null
+++ lib/groonga/query-log/server-verifier.rb    2013-12-16 18:44:56 +0900 (a70e3c0)
@@ -0,0 +1,188 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2013  Kouhei Sutou <kou �� clear-code.com>
+#
+# 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.
+#
+# 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
+
+require "time"
+require "thread"
+
+require "groonga/client"
+
+require "groonga/query-log/parser"
+
+module Groonga
+  module QueryLog
+    class ServerVerifier
+      def initialize(options)
+        @options = options
+        @queue = SizedQueue.new(@options.request_queue_size)
+        @different_results = Queue.new
+      end
+
+      def verify(input)
+        producer = run_producer(input)
+        consumers = run_consumers
+        reporter = run_reporter
+        producer.join
+        consumers.each(&:join)
+        @different_results.push(nil)
+        reporter.join
+      end
+
+      private
+      def run_producer(input)
+        Thread.new do
+          parser = Parser.new
+          parser.parse(input) do |statistic|
+            next unless target_command?(statistic.command)
+            @queue.push(statistic)
+          end
+          @options.n_clients.times do
+            @queue.push(nil)
+          end
+        end
+      end
+
+      def run_consumers
+        @options.n_clients.times.collect do
+          Thread.new do
+            loop do
+              break if run_consumer
+            end
+          end
+        end
+      end
+
+      def run_consumer
+        @options.groonga1.create_client do |groonga1_client|
+          @options.groonga2.create_client do |groonga2_client|
+            loop do
+              statistic =****@queue*****
+              return true if statistic.nil?
+              begin
+                verify_command(groonga1_client, groonga2_client,
+                               statistic.command)
+              rescue Groonga::Client::Connection::Error
+                # TODO: add error log mechanism
+                $stderr.puts(Time.now.iso8601)
+                $stderr.puts(statistic.command.original_source)
+                $stderr.puts($!.raw_error.message)
+                $stderr.puts($!.raw_error.backtrace)
+                return false
+              end
+            end
+          end
+        end
+      end
+
+      def run_reporter
+        Thread.new do
+          @options.create_output do |output|
+            loop do
+              result = @different_results.pop
+              break if result.nil?
+              report_result(output, result)
+            end
+          end
+        end
+      end
+
+      def target_command?(command)
+        @options.target_command_name?(command.name)
+      end
+
+      def verify_command(groonga1_client, groonga2_client, command)
+        command["cache"] = "no" if****@optio*****_cache?
+        response1 = groonga1_client.execute(command)
+        response2 = groonga2_client.execute(command)
+        unless same_response?(response1, response2)
+          @different_results.push([command, response1, response2])
+        end
+      end
+
+      def same_response?(response1, response2)
+        response1.body == response2.body
+      end
+
+      def report_result(output, result)
+        command, response1, response2 = result
+        output.puts("command: #{command.original_format}")
+        output.puts("response1: #{response1.body}")
+        output.puts("response2: #{response2.body}")
+      end
+
+      class Options
+        attr_reader :groonga1
+        attr_reader :groonga2
+        attr_accessor :n_clients
+        attr_writer :request_queue_size
+        attr_accessor :target_command_names
+        attr_accessor :output_path
+        def initialize
+          @groonga1 = GroongaOptions.new
+          @groonga2 = GroongaOptions.new
+          @n_clients = 8
+          @request_queue_size = nil
+          @disable_cache = false
+          @output_path = nil
+          @target_command_names = ["select"]
+        end
+
+        def request_queue_size
+          @request_queue_size || @n_clients * 3
+        end
+
+        def disable_cache?
+          @disable_cache
+        end
+
+        def target_command_name?(name)
+          @target_command_names.any? do |name_pattern|
+            flags = 0
+            flags |= File::FNM_EXTGLOB if File.const_defined?(:FNM_EXTGLOB)
+            File.fnmatch(name_pattern, name, flags)
+          end
+        end
+
+        def create_output(&block)
+          if @output_path
+            File.open(@output_path, "w", &block)
+          else
+            yield($stdout)
+          end
+        end
+      end
+
+      class GroongaOptions
+        attr_accessor :host
+        attr_accessor :port
+        attr_accessor :protocol
+        def initialize
+          @host     = "127.0.0.1"
+          @port     = 10041
+          @protocol = :gqtp
+        end
+
+        def create_client(&block)
+          Groonga::Client.open(:host     => @host,
+                               :port     => @port,
+                               :protocol => @protocol,
+                               &block)
+        end
+      end
+    end
+  end
+end
-------------- next part --------------
HTML����������������������������...
下载 



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