You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by ko...@apache.org on 2023/06/09 02:51:03 UTC

[arrow] branch main updated: GH-35819: [GLib][Ruby] Refer dependency objects of GArrowExecutePlan (#35963)

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 3b32faafd6 GH-35819: [GLib][Ruby] Refer dependency objects of GArrowExecutePlan (#35963)
3b32faafd6 is described below

commit 3b32faafd61b116319eac0899eaae6de9ec25f9d
Author: Sutou Kouhei <ko...@clear-code.com>
AuthorDate: Fri Jun 9 11:50:53 2023 +0900

    GH-35819: [GLib][Ruby] Refer dependency objects of GArrowExecutePlan (#35963)
    
    ### Rationale for this change
    
    If we don't refer them, GC may free them unexpectedly.
    
    Relations:
    
    * `GArrowExecutePlan` -> `GArrowExecuteNode`s
    * `GArrowExecuteNode` -> `GArrowExecuteOptions`
    * `GArrowSourceNodeOptions` -> `GArrowRecordBatchReader` or `GArrowRecordBatch`
    * `GArrowRecordBatchReader` -> `GArrowRecordBatch`s or `GArrowTable`
    
    ### What changes are included in this PR?
    
    Add missing references in GLib and mark dependency container explicitly in Ruby.
    Because we can't mark dependency container automatically in Ruby.
    
    ### Are these changes tested?
    
    Yes.
    
    ### Are there any user-facing changes?
    
    Yes.
    * Closes: #35819
    
    Authored-by: Sutou Kouhei <ko...@clear-code.com>
    Signed-off-by: Sutou Kouhei <ko...@clear-code.com>
---
 c_glib/arrow-glib/compute.cpp             | 132 ++++++++++++++++++++++++++----
 c_glib/arrow-glib/compute.h               |   3 +
 c_glib/arrow-glib/compute.hpp             |   4 +-
 c_glib/arrow-glib/reader.cpp              |  86 +++++++++++++------
 c_glib/arrow-glib/reader.h                |   4 +
 c_glib/arrow-glib/reader.hpp              |  11 ++-
 c_glib/arrow-glib/version.h.in            |  23 ++++++
 c_glib/doc/arrow-glib/arrow-glib-docs.xml |   4 +
 ruby/red-arrow/ext/arrow/arrow.cpp        |  25 ++++++
 ruby/red-arrow/lib/arrow/slicer.rb        |   2 +-
 10 files changed, 246 insertions(+), 48 deletions(-)

diff --git a/c_glib/arrow-glib/compute.cpp b/c_glib/arrow-glib/compute.cpp
index 1a0c7284f6..2cf8501fae 100644
--- a/c_glib/arrow-glib/compute.cpp
+++ b/c_glib/arrow-glib/compute.cpp
@@ -944,6 +944,27 @@ garrow_source_node_options_set_property(GObject *object,
   }
 }
 
+static void
+garrow_source_node_options_get_property(GObject *object,
+                                        guint prop_id,
+                                        GValue *value,
+                                        GParamSpec *pspec)
+{
+  auto priv = GARROW_SOURCE_NODE_OPTIONS_GET_PRIVATE(object);
+
+  switch (prop_id) {
+  case PROP_READER:
+    g_value_set_object(value, priv->reader);
+    break;
+  case PROP_RECORD_BATCH:
+    g_value_set_object(value, priv->record_batch);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    break;
+  }
+}
+
 static void
 garrow_source_node_options_init(GArrowSourceNodeOptions *object)
 {
@@ -955,6 +976,7 @@ garrow_source_node_options_class_init(GArrowSourceNodeOptionsClass *klass)
   auto gobject_class = G_OBJECT_CLASS(klass);
   gobject_class->dispose = garrow_source_node_options_dispose;
   gobject_class->set_property = garrow_source_node_options_set_property;
+  gobject_class->get_property = garrow_source_node_options_get_property;
 
   GParamSpec *spec;
   spec = g_param_spec_object("reader",
@@ -962,7 +984,7 @@ garrow_source_node_options_class_init(GArrowSourceNodeOptionsClass *klass)
                              "The GArrowRecordBatchReader that produces "
                              "record batches",
                              GARROW_TYPE_RECORD_BATCH_READER,
-                             static_cast<GParamFlags>(G_PARAM_WRITABLE |
+                             static_cast<GParamFlags>(G_PARAM_READWRITE |
                                                       G_PARAM_CONSTRUCT_ONLY));
   g_object_class_install_property(gobject_class, PROP_READER, spec);
 
@@ -970,7 +992,7 @@ garrow_source_node_options_class_init(GArrowSourceNodeOptionsClass *klass)
                              "Record batch",
                              "The GArrowRecordBatch to be produced",
                              GARROW_TYPE_RECORD_BATCH,
-                             static_cast<GParamFlags>(G_PARAM_WRITABLE |
+                             static_cast<GParamFlags>(G_PARAM_READWRITE |
                                                       G_PARAM_CONSTRUCT_ONLY));
   g_object_class_install_property(gobject_class, PROP_RECORD_BATCH, spec);
 }
@@ -1524,9 +1546,9 @@ garrow_sink_node_options_get_reader(GArrowSinkNodeOptions *options,
   if (!priv->reader) {
     auto arrow_reader =
       arrow::acero::MakeGeneratorReader(arrow_schema,
-                                          std::move(priv->generator),
-                                          arrow::default_memory_pool());
-    priv->reader = garrow_record_batch_reader_new_raw(&arrow_reader);
+                                        std::move(priv->generator),
+                                        arrow::default_memory_pool());
+    priv->reader = garrow_record_batch_reader_new_raw(&arrow_reader, nullptr);
   }
   g_object_ref(priv->reader);
   return priv->reader;
@@ -1670,12 +1692,14 @@ garrow_hash_join_node_options_set_right_outputs(
 }
 
 
-typedef struct GArrowExecuteNodePrivate_ {
+struct GArrowExecuteNodePrivate {
   arrow::acero::ExecNode *node;
-} GArrowExecuteNodePrivate;
+  GArrowExecuteNodeOptions *options;
+};
 
 enum {
   PROP_NODE = 1,
+  PROP_OPTIONS,
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE(GArrowExecuteNode,
@@ -1683,10 +1707,21 @@ G_DEFINE_TYPE_WITH_PRIVATE(GArrowExecuteNode,
                            G_TYPE_OBJECT)
 
 #define GARROW_EXECUTE_NODE_GET_PRIVATE(object)   \
-  static_cast<GArrowExecuteNodePrivate *>(       \
-    garrow_execute_node_get_instance_private(    \
+  static_cast<GArrowExecuteNodePrivate *>(        \
+    garrow_execute_node_get_instance_private(     \
       GARROW_EXECUTE_NODE(object)))
 
+static void
+garrow_execute_node_dispose(GObject *object)
+{
+  auto priv = GARROW_EXECUTE_NODE_GET_PRIVATE(object);
+  if (priv->options) {
+    g_object_unref(priv->options);
+    priv->options = nullptr;
+  }
+  G_OBJECT_CLASS(garrow_execute_node_parent_class)->dispose(object);
+}
+
 static void
 garrow_execute_node_set_property(GObject *object,
                                  guint prop_id,
@@ -1700,6 +1735,28 @@ garrow_execute_node_set_property(GObject *object,
     priv->node =
       static_cast<arrow::acero::ExecNode *>(g_value_get_pointer(value));
     break;
+  case PROP_OPTIONS:
+    priv->options =
+      static_cast<GArrowExecuteNodeOptions *>(g_value_dup_object(value));
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    break;
+  }
+}
+
+static void
+garrow_execute_node_get_property(GObject *object,
+                                 guint prop_id,
+                                 GValue *value,
+                                 GParamSpec *pspec)
+{
+  auto priv = GARROW_EXECUTE_NODE_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;
@@ -1715,7 +1772,9 @@ static void
 garrow_execute_node_class_init(GArrowExecuteNodeClass *klass)
 {
   auto gobject_class = G_OBJECT_CLASS(klass);
+  gobject_class->dispose = garrow_execute_node_dispose;
   gobject_class->set_property = garrow_execute_node_set_property;
+  gobject_class->get_property = garrow_execute_node_get_property;
 
   GParamSpec *spec;
   spec = g_param_spec_pointer("node",
@@ -1724,6 +1783,14 @@ garrow_execute_node_class_init(GArrowExecuteNodeClass *klass)
                               static_cast<GParamFlags>(G_PARAM_WRITABLE |
                                                        G_PARAM_CONSTRUCT_ONLY));
   g_object_class_install_property(gobject_class, PROP_NODE, spec);
+
+  spec = g_param_spec_object("options",
+                             "Options",
+                             "The options of this node",
+                             GARROW_TYPE_EXECUTE_NODE_OPTIONS,
+                             static_cast<GParamFlags>(G_PARAM_READWRITE |
+                                                      G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property(gobject_class, PROP_OPTIONS, spec);
 }
 
 /**
@@ -1758,9 +1825,10 @@ garrow_execute_node_get_output_schema(GArrowExecuteNode *node)
 }
 
 
-typedef struct GArrowExecutePlanPrivate_ {
+struct GArrowExecutePlanPrivate {
   std::shared_ptr<arrow::acero::ExecPlan> plan;
-} GArrowExecutePlanPrivate;
+  GList *nodes;
+};
 
 enum {
   PROP_PLAN = 1,
@@ -1783,6 +1851,15 @@ garrow_execute_plan_finalize(GObject *object)
   G_OBJECT_CLASS(garrow_execute_plan_parent_class)->finalize(object);
 }
 
+static void
+garrow_execute_plan_dispose(GObject *object)
+{
+  auto priv = GARROW_EXECUTE_PLAN_GET_PRIVATE(object);
+  g_list_free_full(priv->nodes, g_object_unref);
+  priv->nodes = nullptr;
+  G_OBJECT_CLASS(garrow_execute_plan_parent_class)->dispose(object);
+}
+
 static void
 garrow_execute_plan_set_property(GObject *object,
                                  guint prop_id,
@@ -1815,6 +1892,7 @@ garrow_execute_plan_class_init(GArrowExecutePlanClass *klass)
 {
   auto gobject_class = G_OBJECT_CLASS(klass);
   gobject_class->finalize = garrow_execute_plan_finalize;
+  gobject_class->dispose = garrow_execute_plan_dispose;
   gobject_class->set_property = garrow_execute_plan_set_property;
 
   GParamSpec *spec;
@@ -1877,13 +1955,17 @@ garrow_execute_plan_build_node(GArrowExecutePlan *plan,
   }
   auto arrow_options = garrow_execute_node_options_get_raw(options);
   auto arrow_node_result = arrow::acero::MakeExecNode(factory_name,
-                                                        arrow_plan.get(),
-                                                        arrow_inputs,
-                                                        *arrow_options);
+                                                      arrow_plan.get(),
+                                                      arrow_inputs,
+                                                      *arrow_options);
   if (garrow::check(error, arrow_node_result, "[execute-plan][build-node]")) {
     auto arrow_node = *arrow_node_result;
     arrow_node->SetLabel(factory_name);
-    return garrow_execute_node_new_raw(arrow_node);
+    auto node = garrow_execute_node_new_raw(arrow_node, options);
+    g_object_ref(node);
+    auto priv = GARROW_EXECUTE_PLAN_GET_PRIVATE(plan);
+    priv->nodes = g_list_prepend(priv->nodes, node);
+    return node;
   } else {
     return NULL;
   }
@@ -2083,6 +2165,22 @@ garrow_execute_plan_build_hash_join_node(GArrowExecutePlan *plan,
   return node;
 }
 
+/**
+ * garrow_execute_plan_get_nodes:
+ * @plan: A #GArrowExecutePlan.
+ *
+ * Returns: (transfer none) (element-type GArrowExecuteNode): A list of
+ *   #GArrowExecuteNode of this plan.
+ *
+ * Since: 13.0.0
+ */
+GList *
+garrow_execute_plan_get_nodes(GArrowExecutePlan *plan)
+{
+  auto priv = GARROW_EXECUTE_PLAN_GET_PRIVATE(plan);
+  return priv->nodes;
+}
+
 /**
  * garrow_execute_plan_validate:
  * @plan: A #GArrowExecutePlan.
@@ -5931,10 +6029,12 @@ garrow_execute_node_options_get_raw(GArrowExecuteNodeOptions *options)
 
 
 GArrowExecuteNode *
-garrow_execute_node_new_raw(arrow::acero::ExecNode *arrow_node)
+garrow_execute_node_new_raw(arrow::acero::ExecNode *arrow_node,
+                            GArrowExecuteNodeOptions *options)
 {
   return GARROW_EXECUTE_NODE(g_object_new(GARROW_TYPE_EXECUTE_NODE,
                                           "node", arrow_node,
+                                          "options", options,
                                           NULL));
 }
 
diff --git a/c_glib/arrow-glib/compute.h b/c_glib/arrow-glib/compute.h
index 1fe33f5ea3..61aed37236 100644
--- a/c_glib/arrow-glib/compute.h
+++ b/c_glib/arrow-glib/compute.h
@@ -386,6 +386,9 @@ garrow_execute_plan_build_hash_join_node(GArrowExecutePlan *plan,
                                          GArrowExecuteNode *right,
                                          GArrowHashJoinNodeOptions *options,
                                          GError **error);
+GARROW_AVAILABLE_IN_13_0
+GList *
+garrow_execute_plan_get_nodes(GArrowExecutePlan *plan);
 GARROW_AVAILABLE_IN_6_0
 gboolean
 garrow_execute_plan_validate(GArrowExecutePlan *plan,
diff --git a/c_glib/arrow-glib/compute.hpp b/c_glib/arrow-glib/compute.hpp
index 3297adf104..198bb952e1 100644
--- a/c_glib/arrow-glib/compute.hpp
+++ b/c_glib/arrow-glib/compute.hpp
@@ -59,7 +59,9 @@ garrow_execute_node_options_get_raw(GArrowExecuteNodeOptions *options);
 
 
 GArrowExecuteNode *
-garrow_execute_node_new_raw(arrow::acero::ExecNode *arrow_node);
+garrow_execute_node_new_raw(
+  arrow::acero::ExecNode* arrow_node,
+  GArrowExecuteNodeOptions *options);
 arrow::acero::ExecNode *
 garrow_execute_node_get_raw(GArrowExecuteNode *node);
 
diff --git a/c_glib/arrow-glib/reader.cpp b/c_glib/arrow-glib/reader.cpp
index 16532361d3..997b865a64 100644
--- a/c_glib/arrow-glib/reader.cpp
+++ b/c_glib/arrow-glib/reader.cpp
@@ -59,13 +59,14 @@ G_BEGIN_DECLS
  * input.
  */
 
-typedef struct GArrowRecordBatchReaderPrivate_ {
+struct GArrowRecordBatchReaderPrivate {
   std::shared_ptr<arrow::ipc::RecordBatchReader> record_batch_reader;
-} GArrowRecordBatchReaderPrivate;
+  GList *sources;
+};
 
 enum {
-  PROP_0,
-  PROP_RECORD_BATCH_READER
+  PROP_RECORD_BATCH_READER = 1,
+  PROP_SOURCES,
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE(GArrowRecordBatchReader,
@@ -87,6 +88,17 @@ garrow_record_batch_reader_finalize(GObject *object)
   G_OBJECT_CLASS(garrow_record_batch_reader_parent_class)->finalize(object);
 }
 
+static void
+garrow_record_batch_reader_dispose(GObject *object)
+{
+  auto priv = GARROW_RECORD_BATCH_READER_GET_PRIVATE(object);
+
+  g_list_free_full(priv->sources, g_object_unref);
+  priv->sources = nullptr;
+
+  G_OBJECT_CLASS(garrow_record_batch_reader_parent_class)->dispose(object);
+}
+
 static void
 garrow_record_batch_reader_set_property(GObject *object,
                                         guint prop_id,
@@ -100,19 +112,11 @@ garrow_record_batch_reader_set_property(GObject *object,
     priv->record_batch_reader =
       *static_cast<std::shared_ptr<arrow::ipc::RecordBatchReader> *>(g_value_get_pointer(value));
     break;
-  default:
-    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+  case PROP_SOURCES:
+    priv->sources = g_list_copy_deep(static_cast<GList *>(g_value_get_pointer(value)),
+                                     reinterpret_cast<GCopyFunc>(g_object_ref),
+                                     nullptr);
     break;
-  }
-}
-
-static void
-garrow_record_batch_reader_get_property(GObject *object,
-                                        guint prop_id,
-                                        GValue *value,
-                                        GParamSpec *pspec)
-{
-  switch (prop_id) {
   default:
     G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
     break;
@@ -129,21 +133,25 @@ garrow_record_batch_reader_init(GArrowRecordBatchReader *object)
 static void
 garrow_record_batch_reader_class_init(GArrowRecordBatchReaderClass *klass)
 {
-  GObjectClass *gobject_class;
-  GParamSpec *spec;
-
-  gobject_class = G_OBJECT_CLASS(klass);
-
+  auto gobject_class = G_OBJECT_CLASS(klass);
   gobject_class->finalize     = garrow_record_batch_reader_finalize;
+  gobject_class->finalize     = garrow_record_batch_reader_dispose;
   gobject_class->set_property = garrow_record_batch_reader_set_property;
-  gobject_class->get_property = garrow_record_batch_reader_get_property;
 
+  GParamSpec *spec;
   spec = g_param_spec_pointer("record-batch-reader",
                               "arrow::ipc::RecordBatchReader",
                               "The raw std::shared<arrow::ipc::RecordBatchRecordBatchReader> *",
                               static_cast<GParamFlags>(G_PARAM_WRITABLE |
                                                        G_PARAM_CONSTRUCT_ONLY));
   g_object_class_install_property(gobject_class, PROP_RECORD_BATCH_READER, spec);
+
+  spec = g_param_spec_pointer("sources",
+                              "Sources",
+                              "The sources of this reader",
+                              static_cast<GParamFlags>(G_PARAM_WRITABLE |
+                                                       G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property(gobject_class, PROP_SOURCES, spec);
 }
 
 /**
@@ -168,7 +176,7 @@ garrow_record_batch_reader_import(gpointer c_abi_array_stream, GError **error)
   if (garrow::check(error,
                     arrow_reader_result,
                     "[record-batch-reader][import]")) {
-    return garrow_record_batch_reader_new_raw(&(*arrow_reader_result));
+    return garrow_record_batch_reader_new_raw(&(*arrow_reader_result), nullptr);
   } else {
     return NULL;
   }
@@ -204,7 +212,8 @@ garrow_record_batch_reader_new(GList *record_batches,
   if (garrow::check(error,
                     arrow_reader_result,
                     "[record-batch-stream-reader][new]")) {
-    return garrow_record_batch_reader_new_raw(&*arrow_reader_result);
+    return garrow_record_batch_reader_new_raw(&*arrow_reader_result,
+                                              record_batches);
   } else {
     return NULL;
   }
@@ -354,6 +363,22 @@ garrow_record_batch_reader_read_all(GArrowRecordBatchReader *reader,
   }
 }
 
+/**
+ * garrow_record_batch_reader_get_sources:
+ * @reader: A #GArrowRecordBatchReader.
+ *
+ * Returns: (transfer none) (element-type GObject): A list of source
+ *   of this reader.
+ *
+ * Since: 13.0.0
+ */
+GList *
+garrow_record_batch_reader_get_sources(GArrowRecordBatchReader *reader)
+{
+  auto priv = GARROW_RECORD_BATCH_READER_GET_PRIVATE(reader);
+  return priv->sources;
+}
+
 
 G_DEFINE_TYPE(GArrowTableBatchReader,
               garrow_table_batch_reader,
@@ -383,7 +408,7 @@ garrow_table_batch_reader_new(GArrowTable *table)
   auto arrow_table = garrow_table_get_raw(table);
   auto arrow_table_batch_reader =
     std::make_shared<arrow::TableBatchReader>(*arrow_table);
-  return garrow_table_batch_reader_new_raw(&arrow_table_batch_reader);
+  return garrow_table_batch_reader_new_raw(&arrow_table_batch_reader, table);
 }
 
 /**
@@ -2233,11 +2258,13 @@ G_END_DECLS
 
 GArrowRecordBatchReader *
 garrow_record_batch_reader_new_raw(
-  std::shared_ptr<arrow::RecordBatchReader> *arrow_reader)
+  std::shared_ptr<arrow::RecordBatchReader> *arrow_reader,
+  GList *sources)
 {
   return GARROW_RECORD_BATCH_READER(
     g_object_new(GARROW_TYPE_RECORD_BATCH_READER,
                  "record-batch-reader", arrow_reader,
+                 "sources", sources,
                  NULL));
 }
 
@@ -2249,12 +2276,17 @@ garrow_record_batch_reader_get_raw(GArrowRecordBatchReader *reader)
 }
 
 GArrowTableBatchReader *
-garrow_table_batch_reader_new_raw(std::shared_ptr<arrow::TableBatchReader> *arrow_reader)
+garrow_table_batch_reader_new_raw(
+  std::shared_ptr<arrow::TableBatchReader> *arrow_reader,
+  GArrowTable *table)
 {
+  auto sources = g_list_prepend(nullptr, table);
   auto reader =
     GARROW_TABLE_BATCH_READER(g_object_new(GARROW_TYPE_TABLE_BATCH_READER,
                                            "record-batch-reader", arrow_reader,
+                                           "sources", sources,
                                            NULL));
+  g_list_free(sources);
   return reader;
 }
 
diff --git a/c_glib/arrow-glib/reader.h b/c_glib/arrow-glib/reader.h
index 87171913cb..1ae26478cb 100644
--- a/c_glib/arrow-glib/reader.h
+++ b/c_glib/arrow-glib/reader.h
@@ -79,6 +79,10 @@ GArrowTable *
 garrow_record_batch_reader_read_all(GArrowRecordBatchReader *reader,
                                     GError **error);
 
+GARROW_AVAILABLE_IN_13_0
+GList *
+garrow_record_batch_reader_get_sources(GArrowRecordBatchReader *reader);
+
 #define GARROW_TYPE_TABLE_BATCH_READER (garrow_table_batch_reader_get_type())
 G_DECLARE_DERIVABLE_TYPE(GArrowTableBatchReader,
                          garrow_table_batch_reader,
diff --git a/c_glib/arrow-glib/reader.hpp b/c_glib/arrow-glib/reader.hpp
index 8e9a7ea67b..3efb9f9e07 100644
--- a/c_glib/arrow-glib/reader.hpp
+++ b/c_glib/arrow-glib/reader.hpp
@@ -27,12 +27,17 @@
 
 #include <arrow-glib/reader.h>
 
-GArrowRecordBatchReader *garrow_record_batch_reader_new_raw(std::shared_ptr<arrow::ipc::RecordBatchReader> *arrow_reader);
-std::shared_ptr<arrow::ipc::RecordBatchReader> garrow_record_batch_reader_get_raw(GArrowRecordBatchReader *reader);
+GArrowRecordBatchReader *
+garrow_record_batch_reader_new_raw(
+  std::shared_ptr<arrow::ipc::RecordBatchReader> *arrow_reader,
+  GList *sources);
+std::shared_ptr<arrow::ipc::RecordBatchReader>
+garrow_record_batch_reader_get_raw(GArrowRecordBatchReader *reader);
 
 GArrowTableBatchReader *
 garrow_table_batch_reader_new_raw(
-  std::shared_ptr<arrow::TableBatchReader> *arrow_reader);
+  std::shared_ptr<arrow::TableBatchReader> *arrow_reader,
+  GArrowTable *table);
 std::shared_ptr<arrow::TableBatchReader>
 garrow_table_batch_reader_get_raw(GArrowTableBatchReader *reader);
 
diff --git a/c_glib/arrow-glib/version.h.in b/c_glib/arrow-glib/version.h.in
index 7426e614cd..1d43271a8b 100644
--- a/c_glib/arrow-glib/version.h.in
+++ b/c_glib/arrow-glib/version.h.in
@@ -110,6 +110,15 @@
 #  define GARROW_UNAVAILABLE(major, minor) G_UNAVAILABLE(major, minor)
 #endif
 
+/**
+ * GARROW_VERSION_13_0:
+ *
+ * You can use this macro value for compile time API version check.
+ *
+ * Since: 13.0.0
+ */
+#define GARROW_VERSION_13_0 G_ENCODE_VERSION(13, 0)
+
 /**
  * GARROW_VERSION_12_0:
  *
@@ -328,6 +337,20 @@
 
 #define GARROW_AVAILABLE_IN_ALL
 
+#if GARROW_VERSION_MIN_REQUIRED >= GARROW_VERSION_13_0
+#  define GARROW_DEPRECATED_IN_13_0                GARROW_DEPRECATED
+#  define GARROW_DEPRECATED_IN_13_0_FOR(function)  GARROW_DEPRECATED_FOR(function)
+#else
+#  define GARROW_DEPRECATED_IN_13_0
+#  define GARROW_DEPRECATED_IN_13_0_FOR(function)
+#endif
+
+#if GARROW_VERSION_MAX_ALLOWED < GARROW_VERSION_13_0
+#  define GARROW_AVAILABLE_IN_13_0 GARROW_UNAVAILABLE(13, 0)
+#else
+#  define GARROW_AVAILABLE_IN_13_0
+#endif
+
 #if GARROW_VERSION_MIN_REQUIRED >= GARROW_VERSION_12_0
 #  define GARROW_DEPRECATED_IN_12_0                GARROW_DEPRECATED
 #  define GARROW_DEPRECATED_IN_12_0_FOR(function)  GARROW_DEPRECATED_FOR(function)
diff --git a/c_glib/doc/arrow-glib/arrow-glib-docs.xml b/c_glib/doc/arrow-glib/arrow-glib-docs.xml
index 4abb364712..57b4b98701 100644
--- a/c_glib/doc/arrow-glib/arrow-glib-docs.xml
+++ b/c_glib/doc/arrow-glib/arrow-glib-docs.xml
@@ -193,6 +193,10 @@
     <title>Index of deprecated API</title>
     <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
   </index>
+  <index id="api-index-13-0-0" role="13.0.0">
+    <title>Index of new symbols in 13.0.0</title>
+    <xi:include href="xml/api-index-13.0.0.xml"><xi:fallback /></xi:include>
+  </index>
   <index id="api-index-12-0-0" role="12.0.0">
     <title>Index of new symbols in 12.0.0</title>
     <xi:include href="xml/api-index-12.0.0.xml"><xi:fallback /></xi:include>
diff --git a/ruby/red-arrow/ext/arrow/arrow.cpp b/ruby/red-arrow/ext/arrow/arrow.cpp
index 2e46829d8f..8eb3b61009 100644
--- a/ruby/red-arrow/ext/arrow/arrow.cpp
+++ b/ruby/red-arrow/ext/arrow/arrow.cpp
@@ -43,6 +43,26 @@ namespace red_arrow {
     VALUE month;
     VALUE nanosecond;
   }
+
+  void
+  record_batch_reader_mark(gpointer object)
+  {
+    auto reader = GARROW_RECORD_BATCH_READER(object);
+    auto sources = garrow_record_batch_reader_get_sources(reader);
+    for (auto source = sources; sources; sources = g_list_next(sources)) {
+      rbgobj_gc_mark_instance(source->data);
+    }
+  }
+
+  void
+  execute_plan_mark(gpointer object)
+  {
+    auto plan = GARROW_EXECUTE_PLAN(object);
+    auto nodes = garrow_execute_plan_get_nodes(plan);
+    for (auto node = nodes; nodes; nodes = g_list_next(nodes)) {
+      rbgobj_gc_mark_instance(node->data);
+    }
+  }
 }
 
 extern "C" void Init_arrow() {
@@ -93,4 +113,9 @@ extern "C" void Init_arrow() {
   red_arrow::symbols::millisecond = ID2SYM(rb_intern("millisecond"));
   red_arrow::symbols::month = ID2SYM(rb_intern("month"));
   red_arrow::symbols::nanosecond = ID2SYM(rb_intern("nanosecond"));
+
+  rbgobj_register_mark_func(GARROW_TYPE_RECORD_BATCH_READER,
+                            red_arrow::record_batch_reader_mark);
+  rbgobj_register_mark_func(GARROW_TYPE_EXECUTE_PLAN,
+                            red_arrow::execute_plan_mark);
 }
diff --git a/ruby/red-arrow/lib/arrow/slicer.rb b/ruby/red-arrow/lib/arrow/slicer.rb
index 93cef4850f..18958cf3e5 100644
--- a/ruby/red-arrow/lib/arrow/slicer.rb
+++ b/ruby/red-arrow/lib/arrow/slicer.rb
@@ -189,7 +189,7 @@ module Arrow
           message =
              "pattern must be either String or Regexp: #{pattern.inspect}"
           raise ArgumentError, message
-        end 
+        end
       end
 
       def start_with?(substring, ignore_case: false)