This is an automated email from the ASF dual-hosted git repository.

kou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new 463682df3b GH-50302: [GLib][Ruby][FlightRPC] Fix GC related problems 
(#50401)
463682df3b is described below

commit 463682df3b4e6209b92dc8fdd46460e16d0b6fa6
Author: Sutou Kouhei <[email protected]>
AuthorDate: Thu Jul 9 09:38:55 2026 +0900

    GH-50302: [GLib][Ruby][FlightRPC] Fix GC related problems (#50401)
    
    ### Rationale for this change
    
    `gaflight_server_listen()` may use options' auth handler later. So we 
should refer the given options while the server is alive. If we don't refer the 
given options, we may touch freed auth handler later.
    
    The argument of `ArrowFlight::Criteria.new`/`ArrowFlight::Ticket.new` 
should be referred to protect from GC in Ruby.
    
    I could fix some problems by `GC.stress = true` but I couldn't fix some 
problems that are reproduced only on GitHub Actions. I omit tests for them for 
now.
    
    ### What changes are included in this PR?
    
    * Refer options for `gaflight_server_listen()`
    * Refer expression for `ArrowFlight::Criteria.new`
    * Refer data for `ArrowFlight::Ticket.new`
    * Omit Flight related tests that I can't fix...
    
    ### Are these changes tested?
    
    Yes.
    
    ### Are there any user-facing changes?
    
    Yes.
    
    * GitHub Issue: #50302
    
    Authored-by: Sutou Kouhei <[email protected]>
    Signed-off-by: Sutou Kouhei <[email protected]>
---
 c_glib/arrow-flight-glib/server.cpp                | 61 ++++++++++++++++++++++
 c_glib/test/flight/test-client.rb                  |  5 +-
 c_glib/test/flight/test-criteria.rb                |  3 +-
 c_glib/test/flight/test-endpoint.rb                | 12 +++--
 c_glib/test/flight/test-ticket.rb                  | 15 ++++--
 ci/scripts/c_glib_test.sh                          |  6 ++-
 ruby/red-arrow-cuda/Rakefile                       |  4 +-
 ruby/red-arrow-dataset/Rakefile                    |  4 +-
 ruby/red-arrow-flight-sql/Rakefile                 |  4 +-
 ruby/red-arrow-flight-sql/test/test-client.rb      |  2 +-
 ruby/red-arrow-flight/Rakefile                     |  4 +-
 .../lib/arrow-flight/{ticket.rb => criteria.rb}    | 11 +++-
 ruby/red-arrow-flight/lib/arrow-flight/loader.rb   |  1 +
 ruby/red-arrow-flight/lib/arrow-flight/ticket.rb   |  8 +++
 .../ticket.rb => test/test-criteria.rb}            | 19 +++----
 .../test/test-record-batch-reader.rb               |  1 +
 ruby/red-arrow-format/Rakefile                     |  4 +-
 ruby/red-arrow/Rakefile                            |  4 +-
 ruby/red-gandiva/Rakefile                          |  4 +-
 ruby/red-parquet/Rakefile                          |  4 +-
 20 files changed, 140 insertions(+), 36 deletions(-)

diff --git a/c_glib/arrow-flight-glib/server.cpp 
b/c_glib/arrow-flight-glib/server.cpp
index 2feeb853e2..e354c70624 100644
--- a/c_glib/arrow-flight-glib/server.cpp
+++ b/c_glib/arrow-flight-glib/server.cpp
@@ -1166,6 +1166,7 @@ G_BEGIN_DECLS
 struct GAFlightServerPrivate
 {
   gaflight::Server server;
+  GAFlightServerOptions *options;
 };
 
 G_END_DECLS
@@ -1179,6 +1180,10 @@ 
gaflight_server_servable_interface_init(GAFlightServableInterface *iface)
   iface->get_raw = gaflight_server_servable_get_raw;
 }
 
+enum {
+  PROP_OPTIONS = 1,
+};
+
 G_DEFINE_ABSTRACT_TYPE_WITH_CODE(
   GAFlightServer, gaflight_server, G_TYPE_OBJECT, 
G_ADD_PRIVATE(GAFlightServer);
   G_IMPLEMENT_INTERFACE(GAFLIGHT_TYPE_SERVABLE, 
gaflight_server_servable_interface_init))
@@ -1196,6 +1201,19 @@ gaflight_server_servable_get_raw(GAFlightServable 
*servable)
 }
 G_BEGIN_DECLS
 
+static void
+gaflight_server_dispose(GObject *object)
+{
+  auto priv = GAFLIGHT_SERVER_GET_PRIVATE(object);
+
+  if (priv->options) {
+    g_object_unref(priv->options);
+    priv->options = nullptr;
+  }
+
+  G_OBJECT_CLASS(gaflight_server_parent_class)->dispose(object);
+}
+
 static void
 gaflight_server_finalize(GObject *object)
 {
@@ -1205,6 +1223,24 @@ gaflight_server_finalize(GObject *object)
   G_OBJECT_CLASS(gaflight_server_parent_class)->finalize(object);
 }
 
+static void
+gaflight_server_get_property(GObject *object,
+                             guint prop_id,
+                             GValue *value,
+                             GParamSpec *pspec)
+{
+  auto priv = GAFLIGHT_SERVER_GET_PRIVATE(object);
+
+  switch (prop_id) {
+  case PROP_OPTIONS:
+    g_value_set_object(value, priv->options);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    break;
+  }
+}
+
 static void
 gaflight_server_init(GAFlightServer *object)
 {
@@ -1216,7 +1252,24 @@ static void
 gaflight_server_class_init(GAFlightServerClass *klass)
 {
   auto gobject_class = G_OBJECT_CLASS(klass);
+  gobject_class->dispose = gaflight_server_dispose;
   gobject_class->finalize = gaflight_server_finalize;
+  gobject_class->get_property = gaflight_server_get_property;
+
+  GParamSpec *spec;
+  /**
+   * GAFlightServer:options:
+   *
+   * The options used in this server.
+   *
+   * Since: 26.0.0
+   */
+  spec = g_param_spec_object("options",
+                             "Options",
+                             "The options used in this server",
+                             GAFLIGHT_TYPE_SERVER_OPTIONS,
+                             static_cast<GParamFlags>(G_PARAM_READABLE));
+  g_object_class_install_property(gobject_class, PROP_OPTIONS, spec);
 }
 
 /**
@@ -1236,6 +1289,14 @@ gaflight_server_listen(GAFlightServer *server,
 {
   auto flight_server = gaflight_servable_get_raw(GAFLIGHT_SERVABLE(server));
   const auto flight_options = gaflight_server_options_get_raw(options);
+  auto priv = GAFLIGHT_SERVER_GET_PRIVATE(server);
+  if (priv->options != options) {
+    g_object_ref(options);
+    if (priv->options) {
+      g_object_unref(priv->options);
+    }
+    priv->options = options;
+  }
   return garrow::check(error,
                        flight_server->Init(*flight_options),
                        "[flight-server][listen]");
diff --git a/c_glib/test/flight/test-client.rb 
b/c_glib/test/flight/test-client.rb
index fd7bd25a19..f325d05da0 100644
--- a/c_glib/test/flight/test-client.rb
+++ b/c_glib/test/flight/test-client.rb
@@ -22,7 +22,7 @@ class TestFlightClient < Test::Unit::TestCase
     @server = nil
     omit("Arrow Flight is required") unless defined?(ArrowFlight)
     omit("Unstable on Windows") if Gem.win_platform?
-    omit("Unstable on x86_64 macOS") if /x86_64-darwin/.match?(RUBY_PLATFORM)
+    omit("Unstable on macOS") if /darwin/.match?(RUBY_PLATFORM)
     require_gi_bindings(3, 4, 7)
     @server = Helper::FlightServer.new
     host = "127.0.0.1"
@@ -80,8 +80,9 @@ class TestFlightClient < Test::Unit::TestCase
 
     def test_error
       client = ArrowFlight::Client.new(@location)
+      invalid_data = GLib::Bytes.new("invalid")
       assert_raise(Arrow::Error::Invalid) do
-        client.do_get(ArrowFlight::Ticket.new("invalid"))
+        client.do_get(ArrowFlight::Ticket.new(invalid_data))
       end
     end
   end
diff --git a/c_glib/test/flight/test-criteria.rb 
b/c_glib/test/flight/test-criteria.rb
index d5f60a8953..c2e66369d2 100644
--- a/c_glib/test/flight/test-criteria.rb
+++ b/c_glib/test/flight/test-criteria.rb
@@ -22,7 +22,8 @@ class TestFlightCriteria < Test::Unit::TestCase
 
   def test_expression
     expression = "expression"
-    criteria = ArrowFlight::Criteria.new(expression)
+    expression_bytes = GLib::Bytes.new(expression)
+    criteria = ArrowFlight::Criteria.new(expression_bytes)
     assert_equal(expression,
                  criteria.expression.to_s)
   end
diff --git a/c_glib/test/flight/test-endpoint.rb 
b/c_glib/test/flight/test-endpoint.rb
index 06cddf0019..0766cac325 100644
--- a/c_glib/test/flight/test-endpoint.rb
+++ b/c_glib/test/flight/test-endpoint.rb
@@ -21,7 +21,8 @@ class TestFlightEndpoint < Test::Unit::TestCase
   end
 
   def test_ticket
-    ticket = ArrowFlight::Ticket.new("data")
+    data = GLib::Bytes.new("data")
+    ticket = ArrowFlight::Ticket.new(data)
     locations = [
        ArrowFlight::Location.new("grpc://127.0.0.1:2929"),
        ArrowFlight::Location.new("grpc+tcp://127.0.0.1:12929"),
@@ -32,7 +33,8 @@ class TestFlightEndpoint < Test::Unit::TestCase
   end
 
   def test_locations
-    ticket = ArrowFlight::Ticket.new("data")
+    data = GLib::Bytes.new("data")
+    ticket = ArrowFlight::Ticket.new(data)
     locations = [
        ArrowFlight::Location.new("grpc://127.0.0.1:2929"),
        ArrowFlight::Location.new("grpc+tcp://127.0.0.1:12929"),
@@ -44,7 +46,8 @@ class TestFlightEndpoint < Test::Unit::TestCase
 
   sub_test_case("#==") do
     def test_true
-      ticket = ArrowFlight::Ticket.new("data")
+      data = GLib::Bytes.new("data")
+      ticket = ArrowFlight::Ticket.new(data)
       location = ArrowFlight::Location.new("grpc://127.0.0.1:2929")
       endpoint1 = ArrowFlight::Endpoint.new(ticket, [location])
       endpoint2 = ArrowFlight::Endpoint.new(ticket, [location])
@@ -54,7 +57,8 @@ class TestFlightEndpoint < Test::Unit::TestCase
     end
 
     def test_false
-      ticket = ArrowFlight::Ticket.new("data")
+      data = GLib::Bytes.new("data")
+      ticket = ArrowFlight::Ticket.new(data)
       location1 = ArrowFlight::Location.new("grpc://127.0.0.1:2929")
       location2 = ArrowFlight::Location.new("grpc://127.0.0.1:1129")
       endpoint1 = ArrowFlight::Endpoint.new(ticket, [location1])
diff --git a/c_glib/test/flight/test-ticket.rb 
b/c_glib/test/flight/test-ticket.rb
index 976089762f..b1b0c0fb4c 100644
--- a/c_glib/test/flight/test-ticket.rb
+++ b/c_glib/test/flight/test-ticket.rb
@@ -22,23 +22,28 @@ class TestFlightTicket < Test::Unit::TestCase
 
   def test_data
     data = "data"
-    ticket = ArrowFlight::Ticket.new(data)
+    data_bytes = GLib::Bytes.new(data)
+    ticket = ArrowFlight::Ticket.new(data_bytes)
     assert_equal(data,
                  ticket.data.to_s)
   end
 
   sub_test_case("#==") do
     def test_true
-      ticket1 = ArrowFlight::Ticket.new("data")
-      ticket2 = ArrowFlight::Ticket.new("data")
+      data1 = GLib::Bytes.new("data")
+      data2 = GLib::Bytes.new("data")
+      ticket1 = ArrowFlight::Ticket.new(data1)
+      ticket2 = ArrowFlight::Ticket.new(data2)
       assert do
         ticket1 == ticket2
       end
     end
 
     def test_false
-      ticket1 = ArrowFlight::Ticket.new("data1")
-      ticket2 = ArrowFlight::Ticket.new("data2")
+      data1 = GLib::Bytes.new("data1")
+      data2 = GLib::Bytes.new("data2")
+      ticket1 = ArrowFlight::Ticket.new(data1)
+      ticket2 = ArrowFlight::Ticket.new(data2)
       assert do
         not (ticket1 == ticket2)
       end
diff --git a/ci/scripts/c_glib_test.sh b/ci/scripts/c_glib_test.sh
index 19131709e2..dd30ebb2f4 100755
--- a/ci/scripts/c_glib_test.sh
+++ b/ci/scripts/c_glib_test.sh
@@ -36,7 +36,11 @@ fi
 
 pushd "${source_dir}"
 
-ruby test/run-test.rb
+run_test_args=()
+if [ -n "${RUNNER_DEBUG}" ]; then
+  run_test_args+=(-v)
+fi
+ruby test/run-test.rb "${run_test_args[@]}"
 
 if [[ "$(uname -s)" == "Linux" ]]; then
   # TODO(kszucs): on osx it fails to load 'lgi.corelgilua51' despite that lgi
diff --git a/ruby/red-arrow-cuda/Rakefile b/ruby/red-arrow-cuda/Rakefile
index 2bbe6e7619..77c9f81e99 100644
--- a/ruby/red-arrow-cuda/Rakefile
+++ b/ruby/red-arrow-cuda/Rakefile
@@ -34,7 +34,9 @@ task :test do
     cd("dependency-check") do
       ruby("-S", "rake")
     end
-    ruby("test/run-test.rb")
+    args = []
+    args << "-v" if ENV["RUNNER_DEBUG"]
+    ruby("test/run-test.rb", *args)
   end
 end
 
diff --git a/ruby/red-arrow-dataset/Rakefile b/ruby/red-arrow-dataset/Rakefile
index 2bbe6e7619..77c9f81e99 100644
--- a/ruby/red-arrow-dataset/Rakefile
+++ b/ruby/red-arrow-dataset/Rakefile
@@ -34,7 +34,9 @@ task :test do
     cd("dependency-check") do
       ruby("-S", "rake")
     end
-    ruby("test/run-test.rb")
+    args = []
+    args << "-v" if ENV["RUNNER_DEBUG"]
+    ruby("test/run-test.rb", *args)
   end
 end
 
diff --git a/ruby/red-arrow-flight-sql/Rakefile 
b/ruby/red-arrow-flight-sql/Rakefile
index 2bbe6e7619..77c9f81e99 100644
--- a/ruby/red-arrow-flight-sql/Rakefile
+++ b/ruby/red-arrow-flight-sql/Rakefile
@@ -34,7 +34,9 @@ task :test do
     cd("dependency-check") do
       ruby("-S", "rake")
     end
-    ruby("test/run-test.rb")
+    args = []
+    args << "-v" if ENV["RUNNER_DEBUG"]
+    ruby("test/run-test.rb", *args)
   end
 end
 
diff --git a/ruby/red-arrow-flight-sql/test/test-client.rb 
b/ruby/red-arrow-flight-sql/test/test-client.rb
index 1c77e4d98a..a1fc366f05 100644
--- a/ruby/red-arrow-flight-sql/test/test-client.rb
+++ b/ruby/red-arrow-flight-sql/test/test-client.rb
@@ -19,7 +19,7 @@ class TestClient < Test::Unit::TestCase
   def setup
     @server = nil
     omit("Unstable on Windows") if Gem.win_platform?
-    omit("Unstable on x86_64 macOS") if /x86_64-darwin/.match?(RUBY_PLATFORM)
+    omit("Unstable on macOS") if /darwin/.match?(RUBY_PLATFORM)
     @server = Helper::Server.new
     @server.listen("grpc://127.0.0.1:0")
     @location = "grpc://127.0.0.1:#{@server.port}"
diff --git a/ruby/red-arrow-flight/Rakefile b/ruby/red-arrow-flight/Rakefile
index 2bbe6e7619..77c9f81e99 100644
--- a/ruby/red-arrow-flight/Rakefile
+++ b/ruby/red-arrow-flight/Rakefile
@@ -34,7 +34,9 @@ task :test do
     cd("dependency-check") do
       ruby("-S", "rake")
     end
-    ruby("test/run-test.rb")
+    args = []
+    args << "-v" if ENV["RUNNER_DEBUG"]
+    ruby("test/run-test.rb", *args)
   end
 end
 
diff --git a/ruby/red-arrow-flight/lib/arrow-flight/ticket.rb 
b/ruby/red-arrow-flight/lib/arrow-flight/criteria.rb
similarity index 78%
copy from ruby/red-arrow-flight/lib/arrow-flight/ticket.rb
copy to ruby/red-arrow-flight/lib/arrow-flight/criteria.rb
index f65f3d6cfe..268a629424 100644
--- a/ruby/red-arrow-flight/lib/arrow-flight/ticket.rb
+++ b/ruby/red-arrow-flight/lib/arrow-flight/criteria.rb
@@ -16,9 +16,8 @@
 # under the License.
 
 module ArrowFlight
-  class Ticket
+  class Criteria
     class << self
-      # @api private
       def try_convert(value)
         case value
         when String, GLib::Bytes
@@ -28,5 +27,13 @@ module ArrowFlight
         end
       end
     end
+
+    alias_method :initialize_raw, :initialize
+    private :initialize_raw
+    def initialize(expression)
+      expression = GLib::Bytes.new(expression) if expression.is_a?(String)
+      initialize_raw(expression)
+      @expression = expression
+    end
   end
 end
diff --git a/ruby/red-arrow-flight/lib/arrow-flight/loader.rb 
b/ruby/red-arrow-flight/lib/arrow-flight/loader.rb
index e9e9e08f32..ed9fb09c77 100644
--- a/ruby/red-arrow-flight/lib/arrow-flight/loader.rb
+++ b/ruby/red-arrow-flight/lib/arrow-flight/loader.rb
@@ -32,6 +32,7 @@ module ArrowFlight
       require "arrow-flight/call-options"
       require "arrow-flight/client"
       require "arrow-flight/client-options"
+      require "arrow-flight/criteria"
       require "arrow-flight/location"
       require "arrow-flight/record-batch-reader"
       require "arrow-flight/server-call-context"
diff --git a/ruby/red-arrow-flight/lib/arrow-flight/ticket.rb 
b/ruby/red-arrow-flight/lib/arrow-flight/ticket.rb
index f65f3d6cfe..c1c23ca050 100644
--- a/ruby/red-arrow-flight/lib/arrow-flight/ticket.rb
+++ b/ruby/red-arrow-flight/lib/arrow-flight/ticket.rb
@@ -28,5 +28,13 @@ module ArrowFlight
         end
       end
     end
+
+    alias_method :initialize_raw, :initialize
+    private :initialize_raw
+    def initialize(data)
+      data = GLib::Bytes.new(data) if data.is_a?(String)
+      initialize_raw(data)
+      @data = data
+    end
   end
 end
diff --git a/ruby/red-arrow-flight/lib/arrow-flight/ticket.rb 
b/ruby/red-arrow-flight/test/test-criteria.rb
similarity index 75%
copy from ruby/red-arrow-flight/lib/arrow-flight/ticket.rb
copy to ruby/red-arrow-flight/test/test-criteria.rb
index f65f3d6cfe..4775d1723e 100644
--- a/ruby/red-arrow-flight/lib/arrow-flight/ticket.rb
+++ b/ruby/red-arrow-flight/test/test-criteria.rb
@@ -15,18 +15,13 @@
 # specific language governing permissions and limitations
 # under the License.
 
-module ArrowFlight
-  class Ticket
-    class << self
-      # @api private
-      def try_convert(value)
-        case value
-        when String, GLib::Bytes
-          new(value)
-        else
-          nil
-        end
-      end
+class TestCriteria < Test::Unit::TestCase
+  sub_test_case(".try_convert") do
+    def test_string
+      expression = "expression"
+      criteria = ArrowFlight::Criteria.try_convert(expression)
+      assert_equal(expression,
+                   criteria.expression.to_s)
     end
   end
 end
diff --git a/ruby/red-arrow-flight/test/test-record-batch-reader.rb 
b/ruby/red-arrow-flight/test/test-record-batch-reader.rb
index 7f8c64c003..6ecf2ad921 100644
--- a/ruby/red-arrow-flight/test/test-record-batch-reader.rb
+++ b/ruby/red-arrow-flight/test/test-record-batch-reader.rb
@@ -19,6 +19,7 @@ class TestRecordBatchReader < Test::Unit::TestCase
   def setup
     @server = nil
     omit("Unstable on Windows") if Gem.win_platform?
+    omit("Unstable on macOS") if /darwin/.match?(RUBY_PLATFORM)
     @server = Helper::Server.new
     @server.listen("grpc://127.0.0.1:0")
     @location = "grpc://127.0.0.1:#{@server.port}"
diff --git a/ruby/red-arrow-format/Rakefile b/ruby/red-arrow-format/Rakefile
index 3671f35d6e..5187eae19b 100644
--- a/ruby/red-arrow-format/Rakefile
+++ b/ruby/red-arrow-format/Rakefile
@@ -35,7 +35,9 @@ task default: :test
 desc "Run tests"
 task :test do
   cd(base_dir.to_s) do
-    ruby("test/run.rb")
+    args = []
+    args << "-v" if ENV["RUNNER_DEBUG"]
+    ruby("test/run.rb", *args)
   end
 end
 
diff --git a/ruby/red-arrow/Rakefile b/ruby/red-arrow/Rakefile
index dd2c310b6d..0142a12c40 100644
--- a/ruby/red-arrow/Rakefile
+++ b/ruby/red-arrow/Rakefile
@@ -76,7 +76,9 @@ end
 desc "Run tests"
 task :test do
   cd(base_dir) do
-    ruby("test/run-test.rb")
+    args = []
+    args << "-v" if ENV["RUNNER_DEBUG"]
+    ruby("test/run-test.rb", *args)
   end
 end
 
diff --git a/ruby/red-gandiva/Rakefile b/ruby/red-gandiva/Rakefile
index 579b946d4e..6c2057187f 100644
--- a/ruby/red-gandiva/Rakefile
+++ b/ruby/red-gandiva/Rakefile
@@ -34,7 +34,9 @@ task :test do
     cd("dependency-check") do
       ruby("-S", "rake")
     end
-    ruby("test/run-test.rb")
+    args = []
+    args << "-v" if ENV["RUNNER_DEBUG"]
+    ruby("test/run-test.rb", *args)
   end
 end
 
diff --git a/ruby/red-parquet/Rakefile b/ruby/red-parquet/Rakefile
index 579b946d4e..6c2057187f 100644
--- a/ruby/red-parquet/Rakefile
+++ b/ruby/red-parquet/Rakefile
@@ -34,7 +34,9 @@ task :test do
     cd("dependency-check") do
       ruby("-S", "rake")
     end
-    ruby("test/run-test.rb")
+    args = []
+    args << "-v" if ENV["RUNNER_DEBUG"]
+    ruby("test/run-test.rb", *args)
   end
 end
 

Reply via email to