Kouhei Sutou
null+****@clear*****
Tue Jan 30 12:33:14 JST 2018
Kouhei Sutou 2018-01-30 12:33:14 +0900 (Tue, 30 Jan 2018) New Revision: 34d01e9780fe4eabbb175e9e2efe3624d54d9557 https://github.com/ranguba/rroonga/commit/34d01e9780fe4eabbb175e9e2efe3624d54d9557 Message: array: remove queue support Modified files: ext/groonga/rb-grn-array.c test/test-array.rb Modified: ext/groonga/rb-grn-array.c (+1 -272) =================================================================== --- ext/groonga/rb-grn-array.c 2018-01-29 00:30:25 +0900 (60c105ce) +++ ext/groonga/rb-grn-array.c 2018-01-30 12:33:14 +0900 (ad09537e) @@ -1,6 +1,6 @@ /* -*- coding: utf-8; mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* - Copyright (C) 2009-2013 Kouhei Sutou <kou �� clear-code.com> + Copyright (C) 2009-2018 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 @@ -192,274 +192,6 @@ rb_grn_array_add (int argc, VALUE *argv, VALUE self) } } -typedef struct _YieldRecordCallbackData -{ - VALUE self; - VALUE record; - grn_id id; - int status; -} YieldRecordCallbackData; - -static VALUE -yield_record (VALUE user_data) -{ - YieldRecordCallbackData *data = (YieldRecordCallbackData *)user_data; - volatile VALUE record; - - if (data->id == GRN_ID_NIL) { - record = Qnil; - } else { - record = rb_grn_record_new(data->self, data->id, Qnil); - } - data->record = record; - - return rb_yield(record); -} - -static void -yield_record_callback (grn_ctx *ctx, grn_array *array, - grn_id id, void *user_data) -{ - YieldRecordCallbackData *data = user_data; - - data->id = id; - rb_protect(yield_record, (VALUE)(data), &(data->status)); -} - -/* - * Pushes a record to the array. The record should be filled in the - * given block. The pushed record can be pulled by - * {Groonga::Array#pull}. - * - * @example A program that pushes a job without error handling - * queue = Groonga::Array.create(:name => "CrawlURLQueue") - * queue.define_column("url", "ShortText") - * urls = ["http://groonga.org/", "http://ranguba.org/"] - * urls.each do |url| - * queue.push do |record| - * record.url = url - * end - * end - * - * @example A program that pulls a job without error handling - * queue = Groonga::Array.open(:name => "CrawlURLQueue") - * loop do - * url = nil - * queue.pull do |record| - * url = record.url - * record.delete - * end - * # Crawl URL - * end - * - * The record that is passed to the given block may be nil. You need - * to handle the case. For example, just ignoring it or reports an - * error. - * - * @example A program that pushes a job with error handling - * queue = Groonga::Array.create(:name => "CrawlURLQueue") - * queue.define_column("url", "ShortText") - * urls = ["http://groonga.org/", "http://ranguba.org/"] - * urls.each do |url| - * queue.push do |record| - * record.url = url if record # check record is not nil - * end - * end - * - * If an error is occurred in the given block, the pushed record may - * not be filled completely. You should handle the case in pull side. - * - * @example A program that has an error in push block - * queue = Groonga::Array.create(:name => "CrawlURLQueue") - * queue.define_column("url", "ShortText") - * urls = ["http://groonga.org/", "http://ranguba.org/"] - * urls.each do |url| - * queue.push do |record| - * record.url = uri # Typo! It should be ur*l* not ur*i* - * # record.url isn't set - * end - * end - * - * @example A program that pulls a job with error handling - * queue = Groonga::Array.open(:name => "CrawlURLQueue") - * loop do - * url = nil - * queue.pull do |record| - * url = record.url # record.url is nil! - * record.delete - * end - * next if url.nil? # Ignore an uncompleted added job - * # Crawl URL - * end - * - * @overload push - * @yield [record] Filles columns of a pushed record in the given block. - * @yieldparam record [Groonga::Record or nil] - * A pushed record. It is nil when pushing is failed. - * @return [Groonga::Record or nil] A pushed record that is yielded. - * - */ -static VALUE -rb_grn_array_push (VALUE self) -{ - grn_ctx *context = NULL; - grn_obj *table; - YieldRecordCallbackData data; - - if (!rb_block_given_p()) { - rb_raise(rb_eArgError, - "tried to call Groonga::Array#push without a block"); - } - - table = SELF(self, &context); - - data.self = self; - data.record = Qnil; - data.status = 0; - grn_array_push(context, (grn_array *)table, yield_record_callback, &data); - if (data.status != 0) { - rb_jump_tag(data.status); - } - rb_grn_context_check(context, self); - - return data.record; -} - -/* - * Pulls a record from the array. The required values should be - * retrieved in the given block. - * - * If {Groonga::Array#push} failes to fill values of the pushed - * record, the pulled record may be uncompleted. It should be handled - * by your application. - * - * If you passes @:block? => true@ option, the pull operation blocks - * until a pushed record is pushed. It is the default behavior. - * - * If you passes @:block? => false@ option, the pull operation returns - * immediately, the given block isn't called and returns nil when no - * record exist in the array. - * - * @example A program that pulls with non-block mode - * queue = Groonga::Array.open(:name => "CrawlURLQueue") - * loop do - * url = nil - * # The case for no pushed records in the array. - * pulled_record = queue.pull(:block? => false) do |record| - * # This block isn't called - * url = record.url - * record.delete - * end - * p pulled_record.nil? # => true - * end - * - * Note that your signal handlers can't be ran while a pull - * operation. You need to use {Groonga::Array#unblock} from - * another process to unblock the pull operation. If you call - * {Groonga::Array#unblock}, signal handler can be ran. - * - * @example Signal handler isn't called - * queue = Groonga::Array.open(:name => "CrawlURLQueue") - * trap(:INT) do - * p :not_called! - * end - * queue.pull do |record| - * # Send SIGINT while blocking the pull operation. - * # The signal handler isn't called. - * end - * - * @see Groonga::Array#push Examples exist in the push documentation. - * - * @overload pull(options={}) - * @param [::Hash] options The option parameters. - * @option options [Boolean] :block? (true) - * Whether the pull operation is blocked or not when no record exist - * in the array. - * @yield [record] Gets required values for a pull record in the given block. - * @yieldparam record [Groonga::Record or nil] - * A pulled record. It is nil when no records exist in the array - * and @block?@ parameter is not @true �� . - * @return [Groonga::Record or nil] A pulled record that is yielded. - * - */ -static VALUE -rb_grn_array_pull (int argc, VALUE *argv, VALUE self) -{ - grn_ctx *context = NULL; - grn_obj *table; - VALUE options; - VALUE rb_block_p; - YieldRecordCallbackData data; - - rb_scan_args(argc, argv, "01", &options); - - rb_grn_scan_options(options, - "block?", &rb_block_p, - NULL); - - if (!rb_block_given_p()) { - rb_raise(rb_eArgError, - "tried to call Groonga::Array#pull without a block"); - } - - table = SELF(self, &context); - - if (NIL_P(rb_block_p)) { - rb_block_p = Qtrue; - } - - data.self = self; - data.record = Qnil; - data.status = 0; - grn_array_pull(context, (grn_array *)table, RVAL2CBOOL(rb_block_p), - yield_record_callback, &data); - if (data.status != 0) { - rb_jump_tag(data.status); - } - rb_grn_context_check(context, self); - - return data.record; -} - -/* - * Unblocks all {Groonga::Array#pull} operations for the array. - * - * @example Pull, unblock and signal - * # pull.rb - * queue = Groonga::Array.open(:name => "CrawlURLQueue") - * trap(:INT) do - * p :called! - * end - * queue.pull do |record| - * # 1. Send SIGINT while blocking the pull operation. - * # The signal handler isn't called. - * # 2. Run unblock.rb. - * # The signal handler is called! - * end - * - * # unblock.rb - * queue = Groonga::Array.open(:name => "CrawlURLQueue") - * queue.unblock - * - * @see Groonga::Array#pull - * - * @overload unblock - * @return [void] - * - */ -static VALUE -rb_grn_array_unblock (VALUE self) -{ - grn_ctx *context = NULL; - grn_obj *table; - - table = SELF(self, &context); - - grn_array_unblock(context, (grn_array *)table); - - return Qnil; -} - void rb_grn_init_array (VALUE mGrn) { @@ -469,7 +201,4 @@ rb_grn_init_array (VALUE mGrn) rb_grn_array_s_create, -1); rb_define_method(rb_cGrnArray, "add", rb_grn_array_add, -1); - rb_define_method(rb_cGrnArray, "push", rb_grn_array_push, 0); - rb_define_method(rb_cGrnArray, "pull", rb_grn_array_pull, -1); - rb_define_method(rb_cGrnArray, "unblock", rb_grn_array_unblock, 0); } Modified: test/test-array.rb (+1 -131) =================================================================== --- test/test-array.rb 2018-01-29 00:30:25 +0900 (c8002532) +++ test/test-array.rb 2018-01-30 12:33:14 +0900 (1313be1c) @@ -1,4 +1,4 @@ -# Copyright (C) 2009-2014 Kouhei Sutou <kou �� clear-code.com> +# Copyright (C) 2009-2018 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 @@ -157,134 +157,4 @@ class ArrayTest < Test::Unit::TestCase user_ids = users.each.collect(&:id) assert_equal([1, 2, 3], user_ids) end - - class TestPushPull < self - def setup - @queue = Groonga::Array.create(:name => "Queue") - @queue.define_column("content", "ShortText") - end - - def teardown - @queue = nil - end - - def test_block? - Tempfile.open("output") do |output| - Tempfile.open("blocked_pull.rb") do |pull_rb| - pull_rb.puts(pull_rb_source(":block? => true")) - pull_rb.close - - pid = spawn({}, RbConfig.ruby, pull_rb.path, :out => output.path) - sleep(0.5) - @queue.push do |record| - record.content = "The first record" - end - Process.waitpid(pid) - assert_equal(<<-EXPECTED_OUTPUT, output.read) -start -1, The first record -done -EXPECTED_OUTPUT - end - end - end - - def test_not_block? - Tempfile.open("output") do |output| - Tempfile.open("not_blocked_pull.rb") do |pull_rb| - pull_rb.puts(pull_rb_source(":block? => false")) - pull_rb.close - - pid = spawn({}, RbConfig.ruby, pull_rb.path, :out => output.path) - Process.waitpid(pid) - assert_equal(<<-EXPECTED_OUTPUT, output.read) -start -done -EXPECTED_OUTPUT - - @queue.push do |record| - record.content = "The first record" - end - pid = spawn({}, RbConfig.ruby, pull_rb.path, :out => output.path) - Process.waitpid(pid) - output.rewind - assert_equal(<<-EXPECTED_OUTPUT, output.read) -start -1, The first record -done -EXPECTED_OUTPUT - end - end - end - - def test_unblock - IO.pipe do |read_io, write_io| - Tempfile.open("not_blocked_pull.rb") do |pull_rb| - pull_rb.puts(pull_rb_source(":block? => true")) - pull_rb.close - - pid = spawn({}, RbConfig.ruby, pull_rb.path, :out => write_io) - assert_equal("start", read_io.gets.chomp) - Process.kill(:TERM, pid) - @queue.unblock - assert_equal("SIGTERM", read_io.gets.chomp) - wait_finished(pid) - write_io.close - assert_equal("done", read_io.read.chomp) - end - end - end - - private - def pull_rb_source(options) - base_dir = File.expand_path(File.join(File.dirname(__FILE__), "..")) - <<-CODE -$stdout.sync = true - -base_dir = #{base_dir.dump} - -groonga_command_dir = File.join(base_dir, "..", "groonga-command") -if File.exist?(groonga_command_dir) - $LOAD_PATH.unshift(File.join(groonga_command_dir, "lib")) -end - -groonga_client_dir = File.join(base_dir, "..", "groonga-client") -if File.exist?(groonga_client_dir) - $LOAD_PATH.unshift(File.join(groonga_client_dir, "lib")) -end - -ext_dir = File.join(base_dir, "ext", "groonga") -lib_dir = File.join(base_dir, "lib") - -$LOAD_PATH.unshift(ext_dir) -$LOAD_PATH.unshift(lib_dir) - -require "groonga" - -trap(:TERM) do - puts("SIGTERM") -end - -puts("start") -Groonga::Context.default.open_database(#{@database_path.to_s.dump}) do - queue = Groonga["Queue"] - queue.pull(#{options}) do |record| - puts([record.id, record.content].join(", ")) - end -end -puts("done") -CODE - end - - def wait_finished(pid) - n_retries = 3 - n_retries.times do |i| - @queue.unblock - finished_pid = Process.waitpid(pid, Process::WNOHANG) - return if finished_pid - sleep((2 ** i) * 0.1) - end - Process.waitpid(pid) - end - end end -------------- next part -------------- HTML����������������������������... URL: https://lists.osdn.me/mailman/archives/groonga-commit/attachments/20180130/45c4df09/attachment-0001.htm