You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by sh...@apache.org on 2018/12/02 10:39:36 UTC

[arrow] branch master updated: ARROW-3912: [Plasma][GLib] Add support for creating and referring objects

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 8f02a1b  ARROW-3912: [Plasma][GLib] Add support for creating and referring objects
8f02a1b is described below

commit 8f02a1b28ac10a2baa7250e00806d8663daaa3d6
Author: Kouhei Sutou <ko...@clear-code.com>
AuthorDate: Sun Dec 2 19:39:18 2018 +0900

    ARROW-3912: [Plasma][GLib] Add support for creating and referring objects
    
    Author: Kouhei Sutou <ko...@clear-code.com>
    
    Closes #3056 from kou/glib-plasma-create-get and squashes the following commits:
    
    e6bc59ff <Kouhei Sutou> Add missing status check for Disconnect()
    623ce411 <Kouhei Sutou> Add missing return on error
    d90d8960 <Kouhei Sutou> Add missing status check for Release()
    1d5bf107 <Kouhei Sutou> Add missing include
    7ac27db6 <Kouhei Sutou> Support old GObject Introspection
    84df1849 <Kouhei Sutou> Support old GObject Introspection
    26b2926e <Kouhei Sutou>  Add support for creating and referring objects
---
 c_glib/arrow-gpu-glib/meson.build                  |  36 +-
 c_glib/configure.ac                                |   4 +
 c_glib/doc/plasma-glib/Makefile.am                 |   7 +
 c_glib/doc/plasma-glib/meson.build                 |   3 +
 c_glib/doc/plasma-glib/plasma-glib-docs.xml        |   8 +-
 c_glib/plasma-glib/Makefile.am                     |  59 ++-
 c_glib/plasma-glib/client.cpp                      | 330 ++++++++++++-
 c_glib/plasma-glib/client.h                        |  36 +-
 c_glib/plasma-glib/client.hpp                      |   8 +-
 c_glib/plasma-glib/meson.build                     |  54 ++-
 c_glib/plasma-glib/object.cpp                      | 538 +++++++++++++++++++++
 c_glib/plasma-glib/object.h                        |  89 ++++
 c_glib/plasma-glib/{client.hpp => object.hpp}      |  22 +-
 c_glib/plasma-glib/plasma-glib.h                   |   1 +
 c_glib/plasma-glib/plasma-glib.hpp                 |   1 +
 c_glib/plasma-glib/plasma-glib.pc.in               |   2 +-
 c_glib/test/plasma/test-plasma-client.rb           |  58 ++-
 ...sma-client.rb => test-plasma-created-object.rb} |  29 +-
 ...ma-client.rb => test-plasma-referred-object.rb} |  24 +-
 19 files changed, 1230 insertions(+), 79 deletions(-)

diff --git a/c_glib/arrow-gpu-glib/meson.build b/c_glib/arrow-gpu-glib/meson.build
index e6b170e..680982e 100644
--- a/c_glib/arrow-gpu-glib/meson.build
+++ b/c_glib/arrow-gpu-glib/meson.build
@@ -57,19 +57,23 @@ pkgconfig.generate(filebase: 'arrow-gpu-glib',
                    requires: ['arrow-glib', 'arrow-gpu'],
                    libraries: [libarrow_gpu_glib])
 
-gnome.generate_gir(libarrow_gpu_glib,
-                   dependencies: declare_dependency(sources: arrow_glib_gir),
-                   sources: sources + c_headers,
-                   namespace: 'ArrowGPU',
-                   nsversion: api_version,
-                   identifier_prefix: 'GArrowGPU',
-                   symbol_prefix: 'garrow_gpu',
-                   export_packages: 'arrow-gpu-glib',
-                   includes: [
-                     'Arrow-1.0',
-                   ],
-                   install: true,
-                   extra_args: [
-                     '--warn-all',
-                     '--include-uninstalled=./arrow-glib/Arrow-1.0.gir',
-                   ])
+gir_dependencies = [
+  declare_dependency(sources: arrow_glib_gir),
+]
+gir_extra_args = [
+  '--warn-all',
+  '--include-uninstalled=./arrow-glib/Arrow-1.0.gir',
+]
+arrow_gpu_glib_gir = gnome.generate_gir(libarrow_gpu_glib,
+                                        dependencies: gir_dependencies,
+                                        sources: sources + c_headers,
+                                        namespace: 'ArrowGPU',
+                                        nsversion: api_version,
+                                        identifier_prefix: 'GArrowGPU',
+                                        symbol_prefix: 'garrow_gpu',
+                                        export_packages: 'arrow-gpu-glib',
+                                        includes: [
+                                          'Arrow-1.0',
+                                        ],
+                                        install: true,
+                                        extra_args: gir_extra_args)
diff --git a/c_glib/configure.ac b/c_glib/configure.ac
index badf9e9..b84e3d3 100644
--- a/c_glib/configure.ac
+++ b/c_glib/configure.ac
@@ -223,8 +223,12 @@ fi
 
 AM_CONDITIONAL([HAVE_ARROW_GPU], [test "$HAVE_ARROW_GPU" = "yes"])
 if test "$HAVE_ARROW_GPU" = "yes"; then
+  ARROW_GPU_GLIB_PACKAGE="arrow-gpu-glib"
   AC_DEFINE(HAVE_ARROW_GPU, [1], [Define to 1 if Apache Arrow supports GPU.])
+else
+  ARROW_GPU_GLIB_PACKAGE=""
 fi
+AC_SUBST(ARROW_GPU_GLIB_PACKAGE)
 
 AM_CONDITIONAL([HAVE_GANDIVA], [test "$HAVE_GANDIVA" = "yes"])
 if test "$HAVE_GANDIVA" = "yes"; then
diff --git a/c_glib/doc/plasma-glib/Makefile.am b/c_glib/doc/plasma-glib/Makefile.am
index 6a25bfb..f4ef9e5 100644
--- a/c_glib/doc/plasma-glib/Makefile.am
+++ b/c_glib/doc/plasma-glib/Makefile.am
@@ -15,6 +15,12 @@
 # specific language governing permissions and limitations
 # under the License.
 
+PLASMA_ARROW_GPU_GTKDOC_LIBS =
+if HAVE_ARROW_GPU
+PLASMA_ARROW_GPU_GTKDOC_LIBS +=					\
+	$(top_builddir)/arrow-gpu-glib/libarrow-gpu-glib.la
+endif
+
 if HAVE_PLASMA
 DOC_MODULE = plasma-glib
 
@@ -50,6 +56,7 @@ AM_CFLAGS =					\
 
 GTKDOC_LIBS =						\
 	$(top_builddir)/arrow-glib/libarrow-glib.la	\
+	$(PLASMA_ARROW_GPU_GTKDOC_LIBS)			\
 	$(top_builddir)/plasma-glib/libplasma-glib.la
 
 include $(top_srcdir)/gtk-doc.make
diff --git a/c_glib/doc/plasma-glib/meson.build b/c_glib/doc/plasma-glib/meson.build
index 2572f0f..95d7db8 100644
--- a/c_glib/doc/plasma-glib/meson.build
+++ b/c_glib/doc/plasma-glib/meson.build
@@ -56,6 +56,9 @@ dependencies = [
   arrow_glib,
   plasma_glib,
 ]
+if arrow_gpu.found()
+  dependencies += [arrow_gpu_glib]
+endif
 ignore_headers = []
 gnome.gtkdoc(project_name,
              main_xml: project_name + '-docs.xml',
diff --git a/c_glib/doc/plasma-glib/plasma-glib-docs.xml b/c_glib/doc/plasma-glib/plasma-glib-docs.xml
index 86e3245..83d3aea 100644
--- a/c_glib/doc/plasma-glib/plasma-glib-docs.xml
+++ b/c_glib/doc/plasma-glib/plasma-glib-docs.xml
@@ -36,12 +36,16 @@
     </releaseinfo>
   </bookinfo>
 
-  <part id="plasma-client">
-    <title>PlasmaClient</title>
+  <part id="client-side">
+    <title>Client side</title>
     <chapter id="client">
       <title>Client</title>
       <xi:include href="xml/client.xml"/>
     </chapter>
+    <chapter id="object">
+      <title>Object</title>
+      <xi:include href="xml/object.xml"/>
+    </chapter>
   </part>
 
   <chapter id="object-tree">
diff --git a/c_glib/plasma-glib/Makefile.am b/c_glib/plasma-glib/Makefile.am
index f797c97..2060472 100644
--- a/c_glib/plasma-glib/Makefile.am
+++ b/c_glib/plasma-glib/Makefile.am
@@ -23,13 +23,42 @@ EXTRA_DIST =					\
 
 AM_CPPFLAGS =					\
 	-I$(top_builddir)			\
-	-I$(top_srcdir)
+	-I$(top_srcdir)				\
+	-DG_LOG_DOMAIN=\"Plasma\"
 
 AM_CFLAGS =					\
 	$(GLIB_CFLAGS)				\
 	$(GARROW_CFLAGS)			\
 	$(GPLASMA_CFLAGS)
 
+PLASMA_ARROW_GPU_LIBS =
+PLASMA_ARROW_GPU_GLIB_PKG_CONFIG_PATH =
+PLASMA_INTROSPECTION_COMPILER_ARROW_GPU_ARGS =
+PLASMA_GIR_ARROW_GPU_PACKAGE =
+PLASMA_GIR_ARROW_GPU_SCANNER_ADD_INCLUDE_PATH =
+PLASMA_GIR_ARROW_GPU_LIBS_MACOS =
+PLASMA_GIR_ARROW_GPU_SCANNER_LIBRARY_PATH_MACOS =
+PLASMA_GIR_ARROW_GPU_LIBS =
+if HAVE_ARROW_GPU
+PLASMA_ARROW_GPU_LIBS +=			\
+	$(ARROW_GPU_LIBS)			\
+	../arrow-gpu-glib/libarrow-gpu-glib.la
+PLASMA_ARROW_GPU_GLIB_PKG_CONFIG_PATH +=	\
+	:${abs_top_builddir}/arrow-gpu-glib
+PLASMA_INTROSPECTION_COMPILER_ARROW_GPU_ARGS +=	\
+	--includedir=$(abs_top_builddir)/arrow-gpu-glib
+PLASMA_GIR_ARROW_GPU_PACKAGE +=			\
+	arrow-gpu-glib
+PLASMA_GIR_ARROW_GPU_SCANNER_ADD_INCLUDE_PATH +=		\
+	--add-include-path=$(abs_top_builddir)/arrow-gpu-glib
+PLASMA_GIR_ARROW_GPU_LIBS_MACOS +=			\
+	arrow-gpu-glib
+PLASMA_GIR_ARROW_GPU_SCANNER_LIBRARY_PATH_MACOS +=		\
+	--library-path=$(abs_top_builddir)/arrow-gpu-glib/.libs
+PLASMA_GIR_ARROW_GPU_LIBS +=					\
+	$(abs_top_builddir)/arrow-gpu-glib/libarrow-gpu-glib.la
+endif
+
 if HAVE_PLASMA
 lib_LTLIBRARIES =				\
 	libplasma-glib.la
@@ -49,18 +78,22 @@ libplasma_glib_la_LIBADD =			\
 	$(GLIB_LIBS)				\
 	$(ARROW_LIBS)				\
 	$(PLASMA_LIBS)				\
-	../arrow-glib/libarrow-glib.la
+	../arrow-glib/libarrow-glib.la		\
+	$(PLASMA_ARROW_GPU_LIBS)
 
 libplasma_glib_la_headers =			\
 	client.h				\
+	object.h				\
 	plasma-glib.h
 
 libplasma_glib_la_sources =			\
 	client.cpp				\
+	object.cpp				\
 	$(libplasma_glib_la_headers)
 
-libplasma_glib_la_cpp_headers =		\
+libplasma_glib_la_cpp_headers =			\
 	client.hpp				\
+	object.hpp				\
 	plasma-glib.hpp
 
 libplasma_glib_la_SOURCES =			\
@@ -68,7 +101,7 @@ libplasma_glib_la_SOURCES =			\
 	$(libplasma_glib_la_cpp_headers)
 
 plasma_glib_includedir = $(includedir)/plasma-glib
-plasma_glib_include_HEADERS =				\
+plasma_glib_include_HEADERS =			\
 	$(libplasma_glib_la_headers)		\
 	$(libplasma_glib_la_cpp_headers)
 
@@ -84,17 +117,19 @@ INTROSPECTION_SCANNER_ARGS =
 INTROSPECTION_SCANNER_ENV =
 if USE_ARROW_BUILD_DIR
 INTROSPECTION_SCANNER_ENV +=			\
-	PKG_CONFIG_PATH=${abs_top_builddir}/arrow-glib:$(ARROW_BUILD_DIR)/src/arrow:$${PKG_CONFIG_PATH}
+	PKG_CONFIG_PATH=${abs_top_builddir}/arrow-glib$(PLASMA_ARROW_GPU_GLIB_PKG_CONFIG_PATH):$(ARROW_BUILD_DIR)/src/arrow:$${PKG_CONFIG_PATH}
 else
 INTROSPECTION_SCANNER_ENV +=			\
-	PKG_CONFIG_PATH=${abs_top_builddir}/arrow-glib:$${PKG_CONFIG_PATH}
+	PKG_CONFIG_PATH=${abs_top_builddir}/arrow-glib$(PLASMA_ARROW_GPU_GLIB_PKG_CONFIG_PATH):$${PKG_CONFIG_PATH}
 endif
-INTROSPECTION_COMPILER_ARGS =				\
-	--includedir=$(abs_top_builddir)/arrow-glib
+INTROSPECTION_COMPILER_ARGS =					\
+	--includedir=$(abs_top_builddir)/arrow-glib		\
+	$(PLASMA_INTROSPECTION_COMPILER_ARROW_GPU_INCLUDEDIR)
 
 Plasma-1.0.gir: libplasma-glib.la
 Plasma_1_0_gir_PACKAGES =			\
-	arrow-glib
+	arrow-glib				\
+	$(PLASMA_GIR_ARROW_GPU_PACKAGE)
 Plasma_1_0_gir_EXPORT_PACKAGES =		\
 	plasma-glib
 Plasma_1_0_gir_INCLUDES =			\
@@ -103,8 +138,9 @@ Plasma_1_0_gir_CFLAGS =			\
 	$(AM_CPPFLAGS)
 Plasma_1_0_gir_LIBS =
 Plasma_1_0_gir_FILES = $(libplasma_glib_la_sources)
-Plasma_1_0_gir_SCANNERFLAGS =						\
+Plasma_1_0_gir_SCANNERFLAGS =					\
 	--add-include-path=$(abs_top_builddir)/arrow-glib	\
+	$(PLASMA_GIR_ARROW_GPU_SCANNER_ADD_INCLUDE_PATH)	\
 	--library-path=$(ARROW_LIB_DIR)				\
 	--warn-all						\
 	--identifier-prefix=GPlasma				\
@@ -112,14 +148,17 @@ Plasma_1_0_gir_SCANNERFLAGS =						\
 if OS_MACOS
 Plasma_1_0_gir_LIBS +=				\
 	arrow-glib				\
+	$(PLASMA_GIR_ARROW_GPU_LIBS_MACOS)	\
 	plasma-glib
 Plasma_1_0_gir_SCANNERFLAGS +=					\
 	--no-libtool						\
 	--library-path=$(abs_top_builddir)/arrow-glib/.libs	\
+	$(PLASMA_GIR_ARROW_GPU_SCANNER_LIBRARY_PATH_MACOS)	\
 	--library-path=$(abs_builddir)/.libs
 else
 Plasma_1_0_gir_LIBS +=					\
 	$(abs_top_builddir)/arrow-glib/libarrow-glib.la	\
+	$(PLASMA_GIR_ARROW_GPU_LIBS)			\
 	libplasma-glib.la
 endif
 INTROSPECTION_GIRS += Plasma-1.0.gir
diff --git a/c_glib/plasma-glib/client.cpp b/c_glib/plasma-glib/client.cpp
index f818c97..6a2629b 100644
--- a/c_glib/plasma-glib/client.cpp
+++ b/c_glib/plasma-glib/client.cpp
@@ -21,47 +21,196 @@
 #  include <config.h>
 #endif
 
+#include <arrow-glib/buffer.hpp>
 #include <arrow-glib/error.hpp>
 
+#ifdef HAVE_ARROW_GPU
+#  include <arrow-gpu-glib/cuda.hpp>
+#endif
+
 #include <plasma-glib/client.hpp>
+#include <plasma-glib/object.hpp>
 
 G_BEGIN_DECLS
 
 /**
  * SECTION: client
- * @title: Client classes
+ * @section_id: client-classes
+ * @title: Client related classes
  * @include: plasma-glib/plasma-glib.h
  *
+ * #GPlasmaClientCreateOptions is a class for customizing object creation.
+ *
  * #GPlasmaClient is a class for an interface with a plasma store
  * and a plasma manager.
  *
  * Since: 0.12.0
  */
 
+typedef struct GPlasmaClientCreateOptionsPrivate_ {
+  guint8 *metadata;
+  gsize metadata_size;
+  gint gpu_device;
+} GPlasmaClientCreateOptionsPrivate;
+
+enum {
+  PROP_GPU_DEVICE = 1
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(GPlasmaClientCreateOptions,
+                           gplasma_client_create_options,
+                           G_TYPE_OBJECT)
+
+#define GPLASMA_CLIENT_CREATE_OPTIONS_GET_PRIVATE(object)         \
+  static_cast<GPlasmaClientCreateOptionsPrivate *>(               \
+    gplasma_client_create_options_get_instance_private(           \
+      GPLASMA_CLIENT_CREATE_OPTIONS(object)))
+
+static void
+gplasma_client_create_options_set_property(GObject *object,
+                                           guint prop_id,
+                                           const GValue *value,
+                                           GParamSpec *pspec)
+{
+  auto priv = GPLASMA_CLIENT_CREATE_OPTIONS_GET_PRIVATE(object);
+
+  switch (prop_id) {
+  case PROP_GPU_DEVICE:
+    priv->gpu_device = g_value_get_int(value);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    break;
+  }
+}
+
+static void
+gplasma_client_create_options_get_property(GObject *object,
+                                           guint prop_id,
+                                           GValue *value,
+                                           GParamSpec *pspec)
+{
+  auto priv = GPLASMA_CLIENT_CREATE_OPTIONS_GET_PRIVATE(object);
+
+  switch (prop_id) {
+  case PROP_GPU_DEVICE:
+    g_value_set_int(value, priv->gpu_device);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    break;
+  }
+}
+
+static void
+gplasma_client_create_options_init(GPlasmaClientCreateOptions *object)
+{
+}
+
+static void
+gplasma_client_create_options_class_init(GPlasmaClientCreateOptionsClass *klass)
+{
+  auto gobject_class = G_OBJECT_CLASS(klass);
+
+  gobject_class->set_property = gplasma_client_create_options_set_property;
+  gobject_class->get_property = gplasma_client_create_options_get_property;
+
+  GParamSpec *spec;
+  spec = g_param_spec_int("gpu-device",
+                          "GPU device",
+                          "The GPU device number. -1 means GPU isn't used.",
+                          -1,
+                          G_MAXINT,
+                          -1,
+                          static_cast<GParamFlags>(G_PARAM_READWRITE |
+                                                   G_PARAM_CONSTRUCT));
+  g_object_class_install_property(gobject_class, PROP_GPU_DEVICE, spec);
+}
+
+/**
+ * gplasma_client_create_options_new:
+ *
+ * Returns: A newly created #GPlasmaClientCreateOptions.
+ *
+ * Since: 0.12.0
+ */
+GPlasmaClientCreateOptions *
+gplasma_client_create_options_new(void)
+{
+  auto options = g_object_new(GPLASMA_TYPE_CLIENT_CREATE_OPTIONS,
+                              NULL);
+  return GPLASMA_CLIENT_CREATE_OPTIONS(options);
+}
+
+/**
+ * gplasma_client_create_options_set_metadata:
+ * @options: A #GPlasmaClientCreateOptions.
+ * @metadata: (nullable) (array length=size): The metadata of a created object.
+ * @size: The number of bytes of the metadata.
+ *
+ * Since: 0.12.0
+ */
+void
+gplasma_client_create_options_set_metadata(GPlasmaClientCreateOptions *options,
+                                           const guint8 *metadata,
+                                           gsize size)
+{
+  auto priv = GPLASMA_CLIENT_CREATE_OPTIONS_GET_PRIVATE(options);
+  if (priv->metadata) {
+    g_free(priv->metadata);
+  }
+  priv->metadata = static_cast<guint8 *>(g_memdup(metadata, size));
+  priv->metadata_size = size;
+}
+
+/**
+ * gplasma_client_create_options_get_metadata:
+ * @options: A #GPlasmaClientCreateOptions.
+ * @size: (nullable) (out): The number of bytes of the metadata.
+ *
+ * Returns: (nullable) (array length=size): The metadata of a created object.
+ *
+ * Since: 0.12.0
+ */
+const guint8 *
+gplasma_client_create_options_get_metadata(GPlasmaClientCreateOptions *options,
+                                           gsize *size)
+{
+  auto priv = GPLASMA_CLIENT_CREATE_OPTIONS_GET_PRIVATE(options);
+  if (size) {
+    *size = priv->metadata_size;
+  }
+  return priv->metadata;
+}
+
 typedef struct GPlasmaClientPrivate_ {
-  std::shared_ptr<plasma::PlasmaClient> client;
+  plasma::PlasmaClient *client;
 } GPlasmaClientPrivate;
 
 enum {
-  PROP_0,
-  PROP_CLIENT
+  PROP_CLIENT = 1
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE(GPlasmaClient,
                            gplasma_client,
                            G_TYPE_OBJECT)
 
-#define GPLASMA_CLIENT_GET_PRIVATE(obj)         \
-  static_cast<GPlasmaClientPrivate *>(          \
-     gplasma_client_get_instance_private(       \
-       GPLASMA_CLIENT(obj)))
+#define GPLASMA_CLIENT_GET_PRIVATE(object)         \
+  static_cast<GPlasmaClientPrivate *>(             \
+    gplasma_client_get_instance_private(           \
+      GPLASMA_CLIENT(object)))
 
 static void
 gplasma_client_finalize(GObject *object)
 {
   auto priv = GPLASMA_CLIENT_GET_PRIVATE(object);
 
-  priv->client = nullptr;
+  auto status = priv->client->Disconnect();
+  if (!status.ok()) {
+    g_warning("[plasma][client][finalize] Failed to disconnect: %s",
+              status.ToString().c_str());
+  }
+  delete priv->client;
 
   G_OBJECT_CLASS(gplasma_client_parent_class)->finalize(object);
 }
@@ -77,7 +226,7 @@ gplasma_client_set_property(GObject *object,
   switch (prop_id) {
   case PROP_CLIENT:
     priv->client =
-      *static_cast<std::shared_ptr<plasma::PlasmaClient> *>(g_value_get_pointer(value));
+      static_cast<plasma::PlasmaClient *>(g_value_get_pointer(value));
     break;
   default:
     G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -102,7 +251,7 @@ gplasma_client_class_init(GPlasmaClientClass *klass)
 
   spec = g_param_spec_pointer("client",
                               "Client",
-                              "The raw std::shared<plasma::PlasmaClient> *",
+                              "The raw plasma::PlasmaClient *",
                               static_cast<GParamFlags>(G_PARAM_WRITABLE |
                                                        G_PARAM_CONSTRUCT_ONLY));
   g_object_class_install_property(gobject_class, PROP_CLIENT, spec);
@@ -122,10 +271,161 @@ GPlasmaClient *
 gplasma_client_new(const gchar *store_socket_name,
                    GError **error)
 {
-  auto plasma_client = std::make_shared<plasma::PlasmaClient>();
+  auto plasma_client = new plasma::PlasmaClient();
   auto status = plasma_client->Connect(store_socket_name, "");
   if (garrow_error_check(error, status, "[plasma][client][new]")) {
-    return gplasma_client_new_raw(&plasma_client);
+    return gplasma_client_new_raw(plasma_client);
+  } else {
+    return NULL;
+  }
+}
+
+/**
+ * gplasma_client_create:
+ * @client: A #GPlasmaClient.
+ * @id: The ID for a newly created object.
+ * @data_size: The number of bytes of data for a newly created object.
+ * @options: (nullable): The option for creating an object.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Returns: (nullable) (transfer full): A newly created #GPlasmaCreatedObject
+ *   on success, %NULL on error.
+ *
+ * Since: 0.12.0
+ */
+GPlasmaCreatedObject *
+gplasma_client_create(GPlasmaClient *client,
+                      GPlasmaObjectID *id,
+                      gsize data_size,
+                      GPlasmaClientCreateOptions *options,
+                      GError **error)
+{
+  const auto context = "[plasma][client][create]";
+  auto plasma_client = gplasma_client_get_raw(client);
+  auto plasma_id = gplasma_object_id_get_raw(id);
+  const uint8_t *raw_metadata = nullptr;
+  int64_t raw_metadata_size = 0;
+  int device_number = 0;
+  if (options) {
+    auto options_priv = GPLASMA_CLIENT_CREATE_OPTIONS_GET_PRIVATE(options);
+    raw_metadata = options_priv->metadata;
+    raw_metadata_size = options_priv->metadata_size;
+    if (options_priv->gpu_device >= 0) {
+#ifndef HAVE_ARROW_GPU
+      g_set_error(error,
+                  GARROW_ERROR,
+                  GARROW_ERROR_INVALID,
+                  "%s Arrow GPU GLib is needed to use GPU",
+                  context);
+      return NULL;
+#endif
+      device_number = options_priv->gpu_device + 1;
+    }
+  }
+  std::shared_ptr<arrow::Buffer> plasma_data;
+  auto status = plasma_client->Create(plasma_id,
+                                      data_size,
+                                      raw_metadata,
+                                      raw_metadata_size,
+                                      &plasma_data,
+                                      device_number);
+  if (garrow_error_check(error, status, context)) {
+    GArrowBuffer *data = nullptr;
+    if (device_number == 0) {
+      auto plasma_mutable_data =
+        std::static_pointer_cast<arrow::MutableBuffer>(plasma_data);
+      data = GARROW_BUFFER(garrow_mutable_buffer_new_raw(&plasma_mutable_data));
+#ifdef HAVE_ARROW_GPU
+    } else {
+      auto plasma_cuda_data =
+        std::static_pointer_cast<arrow::gpu::CudaBuffer>(plasma_data);
+      data = GARROW_BUFFER(garrow_gpu_cuda_buffer_new_raw(&plasma_cuda_data));
+#endif
+    }
+    GArrowBuffer *metadata = nullptr;
+    if (raw_metadata_size > 0) {
+      auto plasma_metadata =
+        std::make_shared<arrow::Buffer>(raw_metadata, raw_metadata_size);
+      metadata = garrow_buffer_new_raw(&plasma_metadata);
+    }
+    return gplasma_created_object_new_raw(client,
+                                          id,
+                                          data,
+                                          metadata,
+                                          device_number - 1);
+  } else {
+    return NULL;
+  }
+}
+
+/**
+ * gplasma_client_refer_object:
+ * @client: A #GPlasmaClient.
+ * @id: The ID of the target object.
+ * @timeout_ms: The timeout in milliseconds. -1 means no timeout.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Returns: (nullable) (transfer full): A found #GPlasmaReferredObject
+ *   on success, %NULL on error.
+ *
+ * Since: 0.12.0
+ */
+GPlasmaReferredObject *
+gplasma_client_refer_object(GPlasmaClient *client,
+                            GPlasmaObjectID *id,
+                            gint64 timeout_ms,
+                            GError **error)
+{
+  const auto context = "[plasma][client][refer-object]";
+  auto plasma_client = gplasma_client_get_raw(client);
+  auto plasma_id = gplasma_object_id_get_raw(id);
+  std::vector<plasma::ObjectID> plasma_ids;
+  plasma_ids.push_back(plasma_id);
+  std::vector<plasma::ObjectBuffer> plasma_object_buffers;
+  auto status = plasma_client->Get(plasma_ids,
+                                   timeout_ms,
+                                   &plasma_object_buffers);
+  if (garrow_error_check(error, status, context)) {
+    auto plasma_object_buffer = plasma_object_buffers[0];
+    auto plasma_data = plasma_object_buffer.data;
+    auto plasma_metadata = plasma_object_buffer.metadata;
+    GArrowBuffer *data = nullptr;
+    GArrowBuffer *metadata = nullptr;
+    if (plasma_object_buffer.device_num > 0) {
+#ifdef HAVE_ARROW_GPU
+      std::shared_ptr<arrow::gpu::CudaBuffer> plasma_cuda_data;
+      status = arrow::gpu::CudaBuffer::FromBuffer(plasma_data,
+                                                  &plasma_cuda_data);
+      if (!garrow_error_check(error, status, context)) {
+        return NULL;
+      }
+      std::shared_ptr<arrow::gpu::CudaBuffer> plasma_cuda_metadata;
+      status = arrow::gpu::CudaBuffer::FromBuffer(plasma_metadata,
+                                                  &plasma_cuda_metadata);
+      if (!garrow_error_check(error, status, context)) {
+        return NULL;
+      }
+
+      data = GARROW_BUFFER(garrow_gpu_cuda_buffer_new_raw(&plasma_cuda_data));
+      metadata =
+        GARROW_BUFFER(garrow_gpu_cuda_buffer_new_raw(&plasma_cuda_metadata));
+#else
+      g_set_error(error,
+                  GARROW_ERROR,
+                  GARROW_ERROR_INVALID,
+                  "%s Arrow GPU GLib is needed to use GPU",
+                  context);
+      return NULL;
+#endif
+    } else {
+      data = garrow_buffer_new_raw(&plasma_data);
+      metadata = garrow_buffer_new_raw(&plasma_metadata);
+    }
+    return gplasma_referred_object_new_raw(client,
+                                           id,
+                                           data,
+                                           metadata,
+                                           plasma_object_buffer.device_num - 1);
   } else {
     return NULL;
   }
@@ -134,7 +434,7 @@ gplasma_client_new(const gchar *store_socket_name,
 G_END_DECLS
 
 GPlasmaClient *
-gplasma_client_new_raw(std::shared_ptr<plasma::PlasmaClient> *plasma_client)
+gplasma_client_new_raw(plasma::PlasmaClient *plasma_client)
 {
   auto client = g_object_new(GPLASMA_TYPE_CLIENT,
                              "client", plasma_client,
@@ -142,7 +442,7 @@ gplasma_client_new_raw(std::shared_ptr<plasma::PlasmaClient> *plasma_client)
   return GPLASMA_CLIENT(client);
 }
 
-std::shared_ptr<plasma::PlasmaClient>
+plasma::PlasmaClient *
 gplasma_client_get_raw(GPlasmaClient *client)
 {
   auto priv = GPLASMA_CLIENT_GET_PRIVATE(client);
diff --git a/c_glib/plasma-glib/client.h b/c_glib/plasma-glib/client.h
index 30c8a81..6f99f46 100644
--- a/c_glib/plasma-glib/client.h
+++ b/c_glib/plasma-glib/client.h
@@ -19,10 +19,33 @@
 
 #pragma once
 
-#include <arrow-glib/gobject-type.h>
+#include <plasma-glib/object.h>
 
 G_BEGIN_DECLS
 
+#define GPLASMA_TYPE_CLIENT_CREATE_OPTIONS      \
+  (gplasma_client_create_options_get_type())
+G_DECLARE_DERIVABLE_TYPE(GPlasmaClientCreateOptions,
+                         gplasma_client_create_options,
+                         GPLASMA,
+                         CLIENT_CREATE_OPTIONS,
+                         GObject)
+
+struct _GPlasmaClientCreateOptionsClass
+{
+  GObjectClass parent_class;
+};
+
+GPlasmaClientCreateOptions *gplasma_client_create_options_new(void);
+void
+gplasma_client_create_options_set_metadata(GPlasmaClientCreateOptions *options,
+                                           const guint8 *metadata,
+                                           gsize size);
+const guint8 *
+gplasma_client_create_options_get_metadata(GPlasmaClientCreateOptions *options,
+                                           gsize *size);
+
+
 #define GPLASMA_TYPE_CLIENT (gplasma_client_get_type())
 G_DECLARE_DERIVABLE_TYPE(GPlasmaClient,
                          gplasma_client,
@@ -37,5 +60,16 @@ struct _GPlasmaClientClass
 
 GPlasmaClient *gplasma_client_new(const gchar *store_socket_name,
                                   GError **error);
+GPlasmaCreatedObject *
+gplasma_client_create(GPlasmaClient *client,
+                      GPlasmaObjectID *id,
+                      gsize data_size,
+                      GPlasmaClientCreateOptions *options,
+                      GError **error);
+GPlasmaReferredObject *
+gplasma_client_refer_object(GPlasmaClient *client,
+                            GPlasmaObjectID *id,
+                            gint64 timeout_ms,
+                            GError **error);
 
 G_END_DECLS
diff --git a/c_glib/plasma-glib/client.hpp b/c_glib/plasma-glib/client.hpp
index 473ea16..d3e2ab2 100644
--- a/c_glib/plasma-glib/client.hpp
+++ b/c_glib/plasma-glib/client.hpp
@@ -19,11 +19,11 @@
 
 #pragma once
 
-#include <memory>
-
 #include <plasma/client.h>
 
 #include <plasma-glib/client.h>
 
-GPlasmaClient *gplasma_client_new_raw(std::shared_ptr<plasma::PlasmaClient> *plasma_client);
-std::shared_ptr<plasma::PlasmaClient> gplasma_client_get_raw(GPlasmaClient *client);
+GPlasmaClient *
+gplasma_client_new_raw(plasma::PlasmaClient *plasma_client);
+plasma::PlasmaClient *
+gplasma_client_get_raw(GPlasmaClient *client);
diff --git a/c_glib/plasma-glib/meson.build b/c_glib/plasma-glib/meson.build
index 40a20e9..60a6978 100644
--- a/c_glib/plasma-glib/meson.build
+++ b/c_glib/plasma-glib/meson.build
@@ -21,15 +21,18 @@ project_name = 'plasma-glib'
 
 sources = files(
   'client.cpp',
+  'object.cpp',
 )
 
 c_headers = files(
   'client.h',
+  'object.h',
   'plasma-glib.h',
 )
 
 cpp_headers = files(
   'client.hpp',
+  'object.hpp',
   'plasma-glib.hpp',
 )
 
@@ -41,13 +44,39 @@ dependencies = [
   plasma,
   arrow_glib,
 ]
+cpp_args = [
+  '-DG_LOG_DOMAIN="Plasma"',
+]
+pkg_config_requires = [
+  'plasma',
+  'arrow-glib',
+]
+gir_dependencies = [
+  declare_dependency(sources: arrow_glib_gir),
+]
+gir_includes = [
+  'Arrow-1.0',
+]
+gir_extra_args = [
+  '--warn-all',
+  '--include-uninstalled=./arrow-glib/Arrow-1.0.gir',
+]
+if arrow_gpu.found()
+  dependencies += [arrow_gpu_glib]
+  cpp_args += ['-DHAVE_ARROW_GPU']
+  pkg_config_requires += ['arrow-gpu-glib']
+  gir_dependencies += [declare_dependency(sources: arrow_gpu_glib_gir)]
+  gir_includes += ['ArrowGPU-1.0']
+  gir_extra_args += ['--include-uninstalled=./arrow-gpu-glib/ArrowGPU-1.0.gir']
+endif
 libplasma_glib = library('plasma-glib',
-                          sources: sources,
-                          install: true,
-                          dependencies: dependencies,
-                          include_directories: base_include_directories,
-                          soversion: so_version,
-                          version: library_version)
+                         sources: sources,
+                         install: true,
+                         dependencies: dependencies,
+                         include_directories: base_include_directories,
+                         cpp_args: cpp_args,
+                         soversion: so_version,
+                         version: library_version)
 plasma_glib = declare_dependency(link_with: libplasma_glib,
                                  include_directories: base_include_directories,
                                  dependencies: dependencies)
@@ -56,22 +85,17 @@ pkgconfig.generate(filebase: project_name,
                    name: 'Apache Arrow Plasma GLib',
                    description: 'C API for Apache Arrow Plasma based on GLib',
                    version: version,
-                   requires: ['plasma', 'arrow-glib'],
+                   requires: pkg_config_requires,
                    libraries: [libplasma_glib])
 
 gnome.generate_gir(libplasma_glib,
-                   dependencies: declare_dependency(sources: arrow_glib_gir),
+                   dependencies: gir_dependencies,
                    sources: sources + c_headers,
                    namespace: 'Plasma',
                    nsversion: api_version,
                    identifier_prefix: 'GPlasma',
                    symbol_prefix: 'gplasma',
                    export_packages: 'plasma-glib',
-                   includes: [
-                     'Arrow-1.0',
-                   ],
+                   includes: gir_includes,
                    install: true,
-                   extra_args: [
-                     '--warn-all',
-                     '--include-uninstalled=./arrow-glib/Arrow-1.0.gir',
-                   ])
+                   extra_args: gir_extra_args)
diff --git a/c_glib/plasma-glib/object.cpp b/c_glib/plasma-glib/object.cpp
new file mode 100644
index 0000000..63dc209
--- /dev/null
+++ b/c_glib/plasma-glib/object.cpp
@@ -0,0 +1,538 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <arrow-glib/error.hpp>
+
+#include <plasma-glib/client.hpp>
+#include <plasma-glib/object.hpp>
+
+G_BEGIN_DECLS
+
+/**
+ * SECTION: object
+ * @section_id: object-classes
+ * @title: Object related classes
+ * @include: plasma-glib/plasma-glib.h
+ *
+ * #GPlasmaObjectID is a class for an object ID.
+ *
+ * #GPlasmaObject is a base class for an object stored in plasma store.
+ *
+ * #GPlasmaCreatedObject is a class for a created object. You can
+ * change data of the object until the object is sealed or aborted.
+ *
+ * #GPlasmaReferredObject is a class for a created object. You can
+ * only refer the data and metadata of the object. You can't change
+ * the data of the object.
+ *
+ * Since: 0.12.0
+ */
+
+typedef struct GPlasmaObjectIDPrivate_ {
+  plasma::ObjectID id;
+} GPlasmaObjectIDPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE(GPlasmaObjectID,
+                           gplasma_object_id,
+                           G_TYPE_OBJECT)
+
+#define GPLASMA_OBJECT_ID_GET_PRIVATE(object)   \
+  static_cast<GPlasmaObjectIDPrivate *>(        \
+    gplasma_object_id_get_instance_private(     \
+      GPLASMA_OBJECT_ID(object)))
+
+static void
+gplasma_object_id_init(GPlasmaObjectID *object)
+{
+}
+
+static void
+gplasma_object_id_class_init(GPlasmaObjectIDClass *klass)
+{
+}
+
+/**
+ * gplasma_object_id_new:
+ * @id: (array length=size): The raw ID bytes.
+ * @size: The number of bytes of the ID. It must be 1..20.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Returns: (nullable): A newly created #GPlasmaObjectID on success,
+ *   %NULL on error.
+ *
+ * Since: 0.12.0
+ */
+GPlasmaObjectID *
+gplasma_object_id_new(const guint8 *id,
+                      gsize size,
+                      GError **error)
+{
+  if (size == 0 || size > plasma::kUniqueIDSize) {
+    g_set_error(error,
+                GARROW_ERROR,
+                GARROW_ERROR_INVALID,
+                "[plasma][object-id][new] "
+                "ID must be 1..20 bytes: <%" G_GSIZE_FORMAT ">",
+                size);
+    return NULL;
+  }
+
+  auto object_id = g_object_new(GPLASMA_TYPE_OBJECT_ID, NULL);
+  auto priv = GPLASMA_OBJECT_ID_GET_PRIVATE(object_id);
+  memcpy(priv->id.mutable_data(), id, size);
+  if (size != plasma::kUniqueIDSize) {
+    memset(priv->id.mutable_data() + size, 0, plasma::kUniqueIDSize - size);
+  }
+  return GPLASMA_OBJECT_ID(object_id);
+}
+
+/**
+ * gplasma_object_id_to_binary:
+ * @id: A #GPlasmaObjectID.
+ * @size: (nullable) (out): The number of bytes of the byte string of
+ *   the object ID. It's always 20. 20 is `plasma::kUniqueIDSize`.
+ *
+ * Returns: (array length=size): The byte string of the object ID.
+ *
+ * Since: 0.12.0
+ */
+const guint8 *
+gplasma_object_id_to_binary(GPlasmaObjectID *id,
+                            gsize *size)
+{
+  auto priv = GPLASMA_OBJECT_ID_GET_PRIVATE(id);
+  if (size) {
+    *size = plasma::kUniqueIDSize;
+  }
+  return priv->id.data();
+}
+
+/**
+ * gplasma_object_id_to_hex:
+ * @id: A #GPlasmaObjectID.
+ *
+ * Returns: The hex representation of the object ID.
+ *
+ *   It should be freed with g_free() when no longer needed.
+ *
+ * Since: 0.12.0
+ */
+gchar *
+gplasma_object_id_to_hex(GPlasmaObjectID *id)
+{
+  auto priv = GPLASMA_OBJECT_ID_GET_PRIVATE(id);
+  return g_strdup(priv->id.hex().c_str());
+}
+
+typedef struct GPlasmaObjectPrivate_ {
+  GPlasmaClient *client;
+  GPlasmaObjectID *id;
+  GArrowBuffer *data;
+  GArrowBuffer *metadata;
+  gint gpu_device;
+} GPlasmaObjectPrivate;
+
+enum {
+  PROP_CLIENT = 1,
+  PROP_ID,
+  PROP_DATA,
+  PROP_METADATA,
+  PROP_GPU_DEVICE
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(GPlasmaObject,
+                           gplasma_object,
+                           G_TYPE_OBJECT)
+
+#define GPLASMA_OBJECT_GET_PRIVATE(object)      \
+  static_cast<GPlasmaObjectPrivate *>(          \
+    gplasma_object_get_instance_private(        \
+      GPLASMA_OBJECT(object)))
+
+static void
+gplasma_object_dispose(GObject *object)
+{
+  auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
+
+  // Properties except priv->id must be disposed in subclass.
+
+  if (priv->id) {
+    g_object_unref(priv->id);
+    priv->id = nullptr;
+  }
+
+  G_OBJECT_CLASS(gplasma_object_parent_class)->dispose(object);
+}
+
+static void
+gplasma_object_set_property(GObject *object,
+                            guint prop_id,
+                            const GValue *value,
+                            GParamSpec *pspec)
+{
+  auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
+
+  switch (prop_id) {
+  case PROP_CLIENT:
+    priv->client = GPLASMA_CLIENT(g_value_dup_object(value));
+    break;
+  case PROP_ID:
+    priv->id = GPLASMA_OBJECT_ID(g_value_dup_object(value));
+    break;
+  case PROP_DATA:
+    priv->data = GARROW_BUFFER(g_value_dup_object(value));
+    break;
+  case PROP_METADATA:
+    priv->metadata = GARROW_BUFFER(g_value_dup_object(value));
+    break;
+  case PROP_GPU_DEVICE:
+    priv->gpu_device = g_value_get_int(value);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    break;
+  }
+}
+
+static void
+gplasma_object_get_property(GObject *object,
+                            guint prop_id,
+                            GValue *value,
+                            GParamSpec *pspec)
+{
+  auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
+
+  switch (prop_id) {
+  case PROP_CLIENT:
+    g_value_set_object(value, priv->client);
+    break;
+  case PROP_ID:
+    g_value_set_object(value, priv->id);
+    break;
+  case PROP_DATA:
+    g_value_set_object(value, priv->data);
+    break;
+  case PROP_METADATA:
+    g_value_set_object(value, priv->metadata);
+    break;
+  case PROP_GPU_DEVICE:
+    g_value_set_int(value, priv->gpu_device);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    break;
+  }
+}
+
+static void
+gplasma_object_init(GPlasmaObject *object)
+{
+}
+
+static void
+gplasma_object_class_init(GPlasmaObjectClass *klass)
+{
+  auto gobject_class = G_OBJECT_CLASS(klass);
+
+  gobject_class->dispose      = gplasma_object_dispose;
+  gobject_class->set_property = gplasma_object_set_property;
+  gobject_class->get_property = gplasma_object_get_property;
+
+  GParamSpec *spec;
+  spec = g_param_spec_object("client",
+                             "Client",
+                             "The client",
+                             GPLASMA_TYPE_CLIENT,
+                             static_cast<GParamFlags>(G_PARAM_READWRITE |
+                                                      G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property(gobject_class, PROP_CLIENT, spec);
+
+  spec = g_param_spec_object("id",
+                             "ID",
+                             "The ID of this object",
+                             GPLASMA_TYPE_OBJECT_ID,
+                             static_cast<GParamFlags>(G_PARAM_READWRITE |
+                                                      G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property(gobject_class, PROP_ID, spec);
+
+  spec = g_param_spec_object("data",
+                             "Data",
+                             "The data of this object",
+                             GARROW_TYPE_BUFFER,
+                             static_cast<GParamFlags>(G_PARAM_READWRITE |
+                                                      G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property(gobject_class, PROP_DATA, spec);
+
+  spec = g_param_spec_object("metadata",
+                             "Metadata",
+                             "The metadata of this object",
+                             GARROW_TYPE_BUFFER,
+                             static_cast<GParamFlags>(G_PARAM_READWRITE |
+                                                      G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property(gobject_class, PROP_METADATA, spec);
+
+  spec = g_param_spec_int("gpu-device",
+                          "GPU device",
+                          "The GPU device number. -1 means GPU isn't used.",
+                          -1,
+                          G_MAXINT,
+                          -1,
+                          static_cast<GParamFlags>(G_PARAM_READWRITE |
+                                                   G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property(gobject_class, PROP_GPU_DEVICE, spec);
+}
+
+static bool
+gplasma_object_check_not_released(GPlasmaObjectPrivate *priv,
+                                  GError **error,
+                                  const gchar *context)
+{
+  if (priv->client) {
+    return true;
+  }
+
+  auto id_priv = GPLASMA_OBJECT_ID_GET_PRIVATE(priv->id);
+  auto id_hex = id_priv->id.hex();
+  g_set_error(error,
+              GARROW_ERROR,
+              GARROW_ERROR_INVALID,
+              "%s: Can't process released object: <%s>",
+              context,
+              id_hex.c_str());
+  return false;
+}
+
+static void
+gplasma_object_release_resources(GPlasmaObjectPrivate *priv)
+{
+  if (priv->client) {
+    g_object_unref(priv->client);
+    priv->client = nullptr;
+  }
+
+  if (priv->data) {
+    g_object_unref(priv->data);
+    priv->data = nullptr;
+  }
+
+  if (priv->metadata) {
+    g_object_unref(priv->metadata);
+    priv->metadata = nullptr;
+  }
+}
+
+G_DEFINE_TYPE(GPlasmaCreatedObject,
+              gplasma_created_object,
+              GPLASMA_TYPE_OBJECT)
+
+static void
+gplasma_created_object_dispose(GObject *object)
+{
+  auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
+
+  if (priv->client) {
+    gplasma_created_object_abort(GPLASMA_CREATED_OBJECT(object), NULL);
+  }
+
+  G_OBJECT_CLASS(gplasma_created_object_parent_class)->dispose(object);
+}
+
+static void
+gplasma_created_object_init(GPlasmaCreatedObject *object)
+{
+}
+
+static void
+gplasma_created_object_class_init(GPlasmaCreatedObjectClass *klass)
+{
+  auto gobject_class = G_OBJECT_CLASS(klass);
+
+  gobject_class->dispose = gplasma_created_object_dispose;
+}
+
+/**
+ * gplasma_created_object_seal:
+ * @object: A #GPlasmaCreatedObject.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Seals the object in the object store. You can't use the sealed
+ * object anymore.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ *
+ * Since: 0.12.0
+ */
+gboolean
+gplasma_created_object_seal(GPlasmaCreatedObject *object,
+                            GError **error)
+{
+  const auto context = "[plasma][created-object][seal]";
+
+  auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
+  if (!gplasma_object_check_not_released(priv, error, context)) {
+    return FALSE;
+  }
+
+  auto plasma_client = gplasma_client_get_raw(priv->client);
+  auto id_priv = GPLASMA_OBJECT_ID_GET_PRIVATE(priv->id);
+  auto status = plasma_client->Seal(id_priv->id);
+  auto success = garrow_error_check(error, status, context);
+  if (success) {
+    status = plasma_client->Release(id_priv->id);
+    success = garrow_error_check(error, status, context);
+    gplasma_object_release_resources(priv);
+  }
+  return success;
+}
+
+/**
+ * gplasma_created_object_abort:
+ * @object: A #GPlasmaCreatedObject.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Aborts the object in the object store. You can't use the aborted
+ * object anymore.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ *
+ * Since: 0.12.0
+ */
+gboolean
+gplasma_created_object_abort(GPlasmaCreatedObject *object,
+                             GError **error)
+{
+  const auto context = "[plasma][created-object][abort]";
+
+  auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
+  if (!gplasma_object_check_not_released(priv, error, context)) {
+    return FALSE;
+  }
+
+  auto plasma_client = gplasma_client_get_raw(priv->client);
+  auto id_priv = GPLASMA_OBJECT_ID_GET_PRIVATE(priv->id);
+  auto status = plasma_client->Release(id_priv->id);
+  auto success = garrow_error_check(error, status, context);
+  if (success) {
+    status = plasma_client->Abort(id_priv->id);
+    success = garrow_error_check(error, status, context);
+    gplasma_object_release_resources(priv);
+  }
+  return success;
+}
+
+
+G_DEFINE_TYPE(GPlasmaReferredObject,
+              gplasma_referred_object,
+              GPLASMA_TYPE_OBJECT)
+
+static void
+gplasma_referred_object_dispose(GObject *object)
+{
+  auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
+
+  gplasma_object_release_resources(priv);
+
+  G_OBJECT_CLASS(gplasma_referred_object_parent_class)->dispose(object);
+}
+
+static void
+gplasma_referred_object_init(GPlasmaReferredObject *object)
+{
+}
+
+static void
+gplasma_referred_object_class_init(GPlasmaReferredObjectClass *klass)
+{
+  auto gobject_class = G_OBJECT_CLASS(klass);
+
+  gobject_class->dispose = gplasma_referred_object_dispose;
+}
+
+/**
+ * gplasma_referred_object_release:
+ * @object: A #GPlasmaReferredObject.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Releases the object explicitly. The object is no longer valid.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ *
+ * Since: 0.12.0
+ */
+gboolean
+gplasma_referred_object_release(GPlasmaReferredObject *object,
+                                GError **error)
+{
+  const auto context = "[plasma][referred-object][release]";
+
+  auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
+  if (!gplasma_object_check_not_released(priv, error, context)) {
+    return FALSE;
+  }
+
+  gplasma_object_release_resources(priv);
+  return TRUE;
+}
+
+G_END_DECLS
+
+plasma::ObjectID
+gplasma_object_id_get_raw(GPlasmaObjectID *id)
+{
+  auto priv = GPLASMA_OBJECT_ID_GET_PRIVATE(id);
+  return priv->id;
+}
+
+GPlasmaCreatedObject *
+gplasma_created_object_new_raw(GPlasmaClient *client,
+                               GPlasmaObjectID *id,
+                               GArrowBuffer *data,
+                               GArrowBuffer *metadata,
+                               gint gpu_device)
+{
+  auto object = g_object_new(GPLASMA_TYPE_CREATED_OBJECT,
+                             "client", client,
+                             "id", id,
+                             "data", data,
+                             "metadata", metadata,
+                             "gpu-device", gpu_device,
+                             NULL);
+  return GPLASMA_CREATED_OBJECT(object);
+}
+
+GPlasmaReferredObject *
+gplasma_referred_object_new_raw(GPlasmaClient *client,
+                                GPlasmaObjectID *id,
+                                GArrowBuffer *data,
+                                GArrowBuffer *metadata,
+                                gint gpu_device)
+{
+  auto object = g_object_new(GPLASMA_TYPE_REFERRED_OBJECT,
+                             "client", client,
+                             "id", id,
+                             "data", data,
+                             "metadata", metadata,
+                             "gpu-device", gpu_device,
+                             NULL);
+  return GPLASMA_REFERRED_OBJECT(object);
+}
diff --git a/c_glib/plasma-glib/object.h b/c_glib/plasma-glib/object.h
new file mode 100644
index 0000000..46547d3
--- /dev/null
+++ b/c_glib/plasma-glib/object.h
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#pragma once
+
+#include <arrow-glib/buffer.h>
+
+G_BEGIN_DECLS
+
+#define GPLASMA_TYPE_OBJECT_ID (gplasma_object_id_get_type())
+G_DECLARE_DERIVABLE_TYPE(GPlasmaObjectID,
+                         gplasma_object_id,
+                         GPLASMA,
+                         OBJECT_ID,
+                         GObject)
+
+struct _GPlasmaObjectIDClass
+{
+  GObjectClass parent_class;
+};
+
+GPlasmaObjectID *gplasma_object_id_new(const guint8 *id,
+                                       gsize size,
+                                       GError **error);
+const guint8 *gplasma_object_id_to_binary(GPlasmaObjectID *id,
+                                          gsize *size);
+gchar *gplasma_object_id_to_hex(GPlasmaObjectID *id);
+
+#define GPLASMA_TYPE_OBJECT (gplasma_object_get_type())
+G_DECLARE_DERIVABLE_TYPE(GPlasmaObject,
+                         gplasma_object,
+                         GPLASMA,
+                         OBJECT,
+                         GObject)
+
+struct _GPlasmaObjectClass
+{
+  GObjectClass parent_class;
+};
+
+#define GPLASMA_TYPE_CREATED_OBJECT (gplasma_created_object_get_type())
+G_DECLARE_DERIVABLE_TYPE(GPlasmaCreatedObject,
+                         gplasma_created_object,
+                         GPLASMA,
+                         CREATED_OBJECT,
+                         GPlasmaObject)
+
+struct _GPlasmaCreatedObjectClass
+{
+  GPlasmaObjectClass parent_class;
+};
+
+gboolean gplasma_created_object_seal(GPlasmaCreatedObject *object,
+                                     GError **error);
+gboolean gplasma_created_object_abort(GPlasmaCreatedObject *object,
+                                      GError **error);
+
+#define GPLASMA_TYPE_REFERRED_OBJECT (gplasma_referred_object_get_type())
+G_DECLARE_DERIVABLE_TYPE(GPlasmaReferredObject,
+                         gplasma_referred_object,
+                         GPLASMA,
+                         REFERRED_OBJECT,
+                         GPlasmaObject)
+
+struct _GPlasmaReferredObjectClass
+{
+  GPlasmaObjectClass parent_class;
+};
+
+gboolean gplasma_referred_object_release(GPlasmaReferredObject *object,
+                                         GError **error);
+
+G_END_DECLS
diff --git a/c_glib/plasma-glib/client.hpp b/c_glib/plasma-glib/object.hpp
similarity index 56%
copy from c_glib/plasma-glib/client.hpp
copy to c_glib/plasma-glib/object.hpp
index 473ea16..9d598b2 100644
--- a/c_glib/plasma-glib/client.hpp
+++ b/c_glib/plasma-glib/object.hpp
@@ -19,11 +19,25 @@
 
 #pragma once
 
-#include <memory>
-
 #include <plasma/client.h>
 
 #include <plasma-glib/client.h>
 
-GPlasmaClient *gplasma_client_new_raw(std::shared_ptr<plasma::PlasmaClient> *plasma_client);
-std::shared_ptr<plasma::PlasmaClient> gplasma_client_get_raw(GPlasmaClient *client);
+#include <plasma-glib/object.hpp>
+
+plasma::ObjectID
+gplasma_object_id_get_raw(GPlasmaObjectID *id);
+
+GPlasmaCreatedObject *
+gplasma_created_object_new_raw(GPlasmaClient *client,
+                               GPlasmaObjectID *id,
+                               GArrowBuffer *data,
+                               GArrowBuffer *metadata,
+                               gint gpu_device);
+
+GPlasmaReferredObject *
+gplasma_referred_object_new_raw(GPlasmaClient *client,
+                                GPlasmaObjectID *id,
+                                GArrowBuffer *data,
+                                GArrowBuffer *metadata,
+                                gint gpu_device);
diff --git a/c_glib/plasma-glib/plasma-glib.h b/c_glib/plasma-glib/plasma-glib.h
index 33eed2c..2a6dd76 100644
--- a/c_glib/plasma-glib/plasma-glib.h
+++ b/c_glib/plasma-glib/plasma-glib.h
@@ -20,3 +20,4 @@
 #pragma once
 
 #include <plasma-glib/client.h>
+#include <plasma-glib/object.h>
diff --git a/c_glib/plasma-glib/plasma-glib.hpp b/c_glib/plasma-glib/plasma-glib.hpp
index b0af489..b2958c2 100644
--- a/c_glib/plasma-glib/plasma-glib.hpp
+++ b/c_glib/plasma-glib/plasma-glib.hpp
@@ -22,3 +22,4 @@
 #include <plasma-glib/plasma-glib.h>
 
 #include <plasma-glib/client.hpp>
+#include <plasma-glib/object.hpp>
diff --git a/c_glib/plasma-glib/plasma-glib.pc.in b/c_glib/plasma-glib/plasma-glib.pc.in
index 21f202c..f3a82c2 100644
--- a/c_glib/plasma-glib/plasma-glib.pc.in
+++ b/c_glib/plasma-glib/plasma-glib.pc.in
@@ -25,4 +25,4 @@ Description: C API for Apache Arrow Plasma based on GLib
 Version: @VERSION@
 Libs: -L${libdir} -lplasma-glib
 Cflags: -I${includedir}
-Requires: plasma arrow-glib
+Requires: plasma arrow-glib @ARROW_GPU_GLIB_PACKAGE@
diff --git a/c_glib/test/plasma/test-plasma-client.rb b/c_glib/test/plasma/test-plasma-client.rb
index aee2d03..4bf9fa9 100644
--- a/c_glib/test/plasma/test-plasma-client.rb
+++ b/c_glib/test/plasma/test-plasma-client.rb
@@ -16,20 +16,72 @@
 # under the License.
 
 class TestPlasmaClient < Test::Unit::TestCase
+  include Helper::Omittable
+
   def setup
     @store = nil
     omit("Plasma is required") unless defined?(::Plasma)
     @store = Helper::PlasmaStore.new
     @store.start
+    @client = Plasma::Client.new(@store.socket_path)
   end
 
   def teardown
     @store.stop if @store
   end
 
-  def test_new
-    assert_nothing_raised do
-      Plasma::Client.new(@store.socket_path)
+  sub_test_case("#create") do
+    def setup
+      super
+
+      @id = Plasma::ObjectID.new("Hello")
+      @data = "World"
+      @metadata = "Metadata"
+      @options = Plasma::ClientCreateOptions.new
+    end
+
+    test("no options") do
+      require_gi(1, 42, 0)
+
+      object = @client.create(@id, @data.bytesize)
+      object.data.set_data(0, @data)
+      object.seal
+
+      object = @client.refer_object(@id, -1)
+      assert_equal(@data, object.data.data.to_s)
+    end
+
+    test("options: metadata") do
+      @options.set_metadata(@metadata)
+      object = @client.create(@id, 1, @options)
+      object.seal
+
+      object = @client.refer_object(@id, -1)
+      assert_equal(@metadata, object.metadata.data.to_s)
+    end
+
+    test("options: GPU device") do
+      omit("Arrow GPU is required") unless defined?(::ArrowGPU)
+
+      gpu_device = 0
+
+      @options.gpu_device = gpu_device
+      @options.metadata = @metadata
+      object = @client.create(@id, @data.bytesize, @options)
+      object.data.copy_from_host(@data)
+      object.seal
+
+      object = @client.refer_object(@id, -1)
+      assert_equal([
+                     gpu_device,
+                     @data,
+                     @metadata,
+                   ],
+                   [
+                     object.gpu_device,
+                     object.data.copy_to_host(0, @data.bytesize).to_s,
+                     object.metadata.copy_to_host(0, @metadata.bytesize).to_s,
+                   ])
     end
   end
 end
diff --git a/c_glib/test/plasma/test-plasma-client.rb b/c_glib/test/plasma/test-plasma-created-object.rb
similarity index 56%
copy from c_glib/test/plasma/test-plasma-client.rb
copy to c_glib/test/plasma/test-plasma-created-object.rb
index aee2d03..54d6774 100644
--- a/c_glib/test/plasma/test-plasma-client.rb
+++ b/c_glib/test/plasma/test-plasma-created-object.rb
@@ -15,21 +15,42 @@
 # specific language governing permissions and limitations
 # under the License.
 
-class TestPlasmaClient < Test::Unit::TestCase
+class TestPlasmaCreatedObject < Test::Unit::TestCase
   def setup
     @store = nil
     omit("Plasma is required") unless defined?(::Plasma)
     @store = Helper::PlasmaStore.new
     @store.start
+    @client = Plasma::Client.new(@store.socket_path)
+
+    @id = Plasma::ObjectID.new("Hello")
+    @data = "World"
+    @metadata = "Metadata"
+    @options = Plasma::ClientCreateOptions.new
+    @options.metadata = @metadata
+    @object = @client.create(@id, @data.bytesize, @options)
   end
 
   def teardown
     @store.stop if @store
   end
 
-  def test_new
-    assert_nothing_raised do
-      Plasma::Client.new(@store.socket_path)
+  test("#seal") do
+    @object.data.set_data(0, @data)
+    @object.seal
+
+    object = @client.refer_object(@id, -1)
+    assert_equal(@data, object.data.data.to_s)
+  end
+
+  test("#abort") do
+    @object.data.set_data(0, @data)
+    assert_raise(Arrow::Error::PlasmaObjectExists) do
+      @client.create(@id, @data.bytesize, @options)
     end
+    @object.abort
+
+    object = @client.create(@id, @data.bytesize, @options)
+    object.abort
   end
 end
diff --git a/c_glib/test/plasma/test-plasma-client.rb b/c_glib/test/plasma/test-plasma-referred-object.rb
similarity index 59%
copy from c_glib/test/plasma/test-plasma-client.rb
copy to c_glib/test/plasma/test-plasma-referred-object.rb
index aee2d03..f55c0b1 100644
--- a/c_glib/test/plasma/test-plasma-client.rb
+++ b/c_glib/test/plasma/test-plasma-referred-object.rb
@@ -15,21 +15,37 @@
 # specific language governing permissions and limitations
 # under the License.
 
-class TestPlasmaClient < Test::Unit::TestCase
+class TestPlasmaReferredObject < Test::Unit::TestCase
   def setup
     @store = nil
     omit("Plasma is required") unless defined?(::Plasma)
     @store = Helper::PlasmaStore.new
     @store.start
+    @client = Plasma::Client.new(@store.socket_path)
+
+    @id = Plasma::ObjectID.new("Hello")
+    @data = "World"
+    @metadata = "Metadata"
+    @options = Plasma::ClientCreateOptions.new
+    @options.metadata = @metadata
+    object = @client.create(@id, @data.bytesize, @options)
+    object.data.set_data(0, @data)
+    object.seal
+    @object = @client.refer_object(@id, -1)
   end
 
   def teardown
     @store.stop if @store
   end
 
-  def test_new
-    assert_nothing_raised do
-      Plasma::Client.new(@store.socket_path)
+  test("#release") do
+    @object.release
+
+    message = "[plasma][referred-object][release]: "
+    message << "Can't process released object: <#{@id.to_hex}>"
+    error = Arrow::Error::Invalid.new(message)
+    assert_raise(error) do
+      @object.release
     end
   end
 end