1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #include <arrow-glib/error.hpp>
21 
22 #include <plasma-glib/client.hpp>
23 #include <plasma-glib/object.hpp>
24 
25 G_BEGIN_DECLS
26 
27 /**
28  * SECTION: object
29  * @section_id: object-classes
30  * @title: Object related classes
31  * @include: plasma-glib/plasma-glib.h
32  *
33  * #GPlasmaObjectID is a class for an object ID.
34  *
35  * #GPlasmaObject is a base class for an object stored in plasma store.
36  *
37  * #GPlasmaCreatedObject is a class for a created object. You can
38  * change data of the object until the object is sealed or aborted.
39  *
40  * #GPlasmaReferredObject is a class for a created object. You can
41  * only refer the data and metadata of the object. You can't change
42  * the data of the object.
43  *
44  * Since: 0.12.0
45  */
46 
47 typedef struct GPlasmaObjectIDPrivate_ {
48   plasma::ObjectID id;
49 } GPlasmaObjectIDPrivate;
50 
G_DEFINE_TYPE_WITH_PRIVATE(GPlasmaObjectID,gplasma_object_id,G_TYPE_OBJECT)51 G_DEFINE_TYPE_WITH_PRIVATE(GPlasmaObjectID,
52                            gplasma_object_id,
53                            G_TYPE_OBJECT)
54 
55 #define GPLASMA_OBJECT_ID_GET_PRIVATE(object)   \
56   static_cast<GPlasmaObjectIDPrivate *>(        \
57     gplasma_object_id_get_instance_private(     \
58       GPLASMA_OBJECT_ID(object)))
59 
60 static void
61 gplasma_object_id_init(GPlasmaObjectID *object)
62 {
63 }
64 
65 static void
gplasma_object_id_class_init(GPlasmaObjectIDClass * klass)66 gplasma_object_id_class_init(GPlasmaObjectIDClass *klass)
67 {
68 }
69 
70 /**
71  * gplasma_object_id_new:
72  * @id: (array length=size): The raw ID bytes.
73  * @size: The number of bytes of the ID. It must be 1..20.
74  * @error: (nullable): Return location for a #GError or %NULL.
75  *
76  * Returns: (nullable): A newly created #GPlasmaObjectID on success,
77  *   %NULL on error.
78  *
79  * Since: 0.12.0
80  */
81 GPlasmaObjectID *
gplasma_object_id_new(const guint8 * id,gsize size,GError ** error)82 gplasma_object_id_new(const guint8 *id,
83                       gsize size,
84                       GError **error)
85 {
86   if (size == 0 || size > plasma::kUniqueIDSize) {
87     g_set_error(error,
88                 GARROW_ERROR,
89                 GARROW_ERROR_INVALID,
90                 "[plasma][object-id][new] "
91                 "ID must be 1..20 bytes: <%" G_GSIZE_FORMAT ">",
92                 size);
93     return NULL;
94   }
95 
96   auto object_id = g_object_new(GPLASMA_TYPE_OBJECT_ID, NULL);
97   auto priv = GPLASMA_OBJECT_ID_GET_PRIVATE(object_id);
98   memcpy(priv->id.mutable_data(), id, size);
99   if (size != plasma::kUniqueIDSize) {
100     memset(priv->id.mutable_data() + size, 0, plasma::kUniqueIDSize - size);
101   }
102   return GPLASMA_OBJECT_ID(object_id);
103 }
104 
105 /**
106  * gplasma_object_id_to_binary:
107  * @id: A #GPlasmaObjectID.
108  * @size: (nullable) (out): The number of bytes of the byte string of
109  *   the object ID. It's always 20. 20 is `plasma::kUniqueIDSize`.
110  *
111  * Returns: (array length=size): The byte string of the object ID.
112  *
113  * Since: 0.12.0
114  */
115 const guint8 *
gplasma_object_id_to_binary(GPlasmaObjectID * id,gsize * size)116 gplasma_object_id_to_binary(GPlasmaObjectID *id,
117                             gsize *size)
118 {
119   auto priv = GPLASMA_OBJECT_ID_GET_PRIVATE(id);
120   if (size) {
121     *size = plasma::kUniqueIDSize;
122   }
123   return priv->id.data();
124 }
125 
126 /**
127  * gplasma_object_id_to_hex:
128  * @id: A #GPlasmaObjectID.
129  *
130  * Returns: (transfer full): The hex representation of the object ID.
131  *
132  *   It should be freed with g_free() when no longer needed.
133  *
134  * Since: 0.12.0
135  */
136 gchar *
gplasma_object_id_to_hex(GPlasmaObjectID * id)137 gplasma_object_id_to_hex(GPlasmaObjectID *id)
138 {
139   auto priv = GPLASMA_OBJECT_ID_GET_PRIVATE(id);
140   return g_strdup(priv->id.hex().c_str());
141 }
142 
143 typedef struct GPlasmaObjectPrivate_ {
144   GPlasmaClient *client;
145   GPlasmaObjectID *id;
146   std::shared_ptr<arrow::Buffer> raw_data;
147   GArrowBuffer *data;
148   std::shared_ptr<arrow::Buffer> raw_metadata;
149   GArrowBuffer *metadata;
150   gint gpu_device;
151 } GPlasmaObjectPrivate;
152 
153 enum {
154   PROP_CLIENT = 1,
155   PROP_ID,
156   PROP_RAW_DATA,
157   PROP_DATA,
158   PROP_RAW_METADATA,
159   PROP_METADATA,
160   PROP_GPU_DEVICE
161 };
162 
G_DEFINE_TYPE_WITH_PRIVATE(GPlasmaObject,gplasma_object,G_TYPE_OBJECT)163 G_DEFINE_TYPE_WITH_PRIVATE(GPlasmaObject,
164                            gplasma_object,
165                            G_TYPE_OBJECT)
166 
167 #define GPLASMA_OBJECT_GET_PRIVATE(object)      \
168   static_cast<GPlasmaObjectPrivate *>(          \
169     gplasma_object_get_instance_private(        \
170       GPLASMA_OBJECT(object)))
171 
172 static void
173 gplasma_object_dispose(GObject *object)
174 {
175   auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
176 
177   // Properties except priv->id must be disposed in subclass.
178 
179   if (priv->id) {
180     g_object_unref(priv->id);
181     priv->id = nullptr;
182   }
183 
184   G_OBJECT_CLASS(gplasma_object_parent_class)->dispose(object);
185 }
186 
187 static void
gplasma_object_finalize(GObject * object)188 gplasma_object_finalize(GObject *object)
189 {
190   auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
191 
192   priv->raw_data.~shared_ptr();
193   priv->raw_metadata.~shared_ptr();
194 
195   G_OBJECT_CLASS(gplasma_object_parent_class)->finalize(object);
196 }
197 
198 static void
gplasma_object_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)199 gplasma_object_set_property(GObject *object,
200                             guint prop_id,
201                             const GValue *value,
202                             GParamSpec *pspec)
203 {
204   auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
205 
206   switch (prop_id) {
207   case PROP_CLIENT:
208     priv->client = GPLASMA_CLIENT(g_value_dup_object(value));
209     break;
210   case PROP_ID:
211     priv->id = GPLASMA_OBJECT_ID(g_value_dup_object(value));
212     break;
213   case PROP_RAW_DATA:
214     priv->raw_data =
215       *static_cast<std::shared_ptr<arrow::Buffer> *>(g_value_get_pointer(value));
216     break;
217   case PROP_DATA:
218     priv->data = GARROW_BUFFER(g_value_dup_object(value));
219     break;
220   case PROP_RAW_METADATA:
221     {
222       auto raw_metadata =
223         static_cast<std::shared_ptr<arrow::Buffer> *>(g_value_get_pointer(value));
224       if (raw_metadata) {
225         priv->raw_metadata = *raw_metadata;
226       } else {
227         priv->raw_metadata = nullptr;
228       }
229     }
230     break;
231   case PROP_METADATA:
232     priv->metadata = GARROW_BUFFER(g_value_dup_object(value));
233     break;
234   case PROP_GPU_DEVICE:
235     priv->gpu_device = g_value_get_int(value);
236     break;
237   default:
238     G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
239     break;
240   }
241 }
242 
243 static void
gplasma_object_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)244 gplasma_object_get_property(GObject *object,
245                             guint prop_id,
246                             GValue *value,
247                             GParamSpec *pspec)
248 {
249   auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
250 
251   switch (prop_id) {
252   case PROP_CLIENT:
253     g_value_set_object(value, priv->client);
254     break;
255   case PROP_ID:
256     g_value_set_object(value, priv->id);
257     break;
258   case PROP_DATA:
259     g_value_set_object(value, priv->data);
260     break;
261   case PROP_METADATA:
262     g_value_set_object(value, priv->metadata);
263     break;
264   case PROP_GPU_DEVICE:
265     g_value_set_int(value, priv->gpu_device);
266     break;
267   default:
268     G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
269     break;
270   }
271 }
272 
273 static void
gplasma_object_init(GPlasmaObject * object)274 gplasma_object_init(GPlasmaObject *object)
275 {
276   auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
277   new(&priv->raw_data) std::shared_ptr<arrow::Buffer>;
278   new(&priv->raw_metadata) std::shared_ptr<arrow::Buffer>;
279 }
280 
281 static void
gplasma_object_class_init(GPlasmaObjectClass * klass)282 gplasma_object_class_init(GPlasmaObjectClass *klass)
283 {
284   auto gobject_class = G_OBJECT_CLASS(klass);
285 
286   gobject_class->dispose      = gplasma_object_dispose;
287   gobject_class->finalize     = gplasma_object_finalize;
288   gobject_class->set_property = gplasma_object_set_property;
289   gobject_class->get_property = gplasma_object_get_property;
290 
291   GParamSpec *spec;
292   spec = g_param_spec_object("client",
293                              "Client",
294                              "The client",
295                              GPLASMA_TYPE_CLIENT,
296                              static_cast<GParamFlags>(G_PARAM_READWRITE |
297                                                       G_PARAM_CONSTRUCT_ONLY));
298   g_object_class_install_property(gobject_class, PROP_CLIENT, spec);
299 
300   spec = g_param_spec_object("id",
301                              "ID",
302                              "The ID of this object",
303                              GPLASMA_TYPE_OBJECT_ID,
304                              static_cast<GParamFlags>(G_PARAM_READWRITE |
305                                                       G_PARAM_CONSTRUCT_ONLY));
306   g_object_class_install_property(gobject_class, PROP_ID, spec);
307 
308   spec = g_param_spec_pointer("raw-data",
309                               "Raw data",
310                               "The raw data of this object",
311                               static_cast<GParamFlags>(G_PARAM_WRITABLE |
312                                                        G_PARAM_CONSTRUCT_ONLY));
313   g_object_class_install_property(gobject_class, PROP_RAW_DATA, spec);
314 
315   spec = g_param_spec_object("data",
316                              "Data",
317                              "The data of this object",
318                              GARROW_TYPE_BUFFER,
319                              static_cast<GParamFlags>(G_PARAM_READWRITE |
320                                                       G_PARAM_CONSTRUCT_ONLY));
321   g_object_class_install_property(gobject_class, PROP_DATA, spec);
322 
323   spec = g_param_spec_pointer("raw-metadata",
324                               "Raw metadata",
325                               "The raw metadata of this object",
326                               static_cast<GParamFlags>(G_PARAM_WRITABLE |
327                                                        G_PARAM_CONSTRUCT_ONLY));
328   g_object_class_install_property(gobject_class, PROP_RAW_METADATA, spec);
329 
330   spec = g_param_spec_object("metadata",
331                              "Metadata",
332                              "The metadata of this object",
333                              GARROW_TYPE_BUFFER,
334                              static_cast<GParamFlags>(G_PARAM_READWRITE |
335                                                       G_PARAM_CONSTRUCT_ONLY));
336   g_object_class_install_property(gobject_class, PROP_METADATA, spec);
337 
338   spec = g_param_spec_int("gpu-device",
339                           "GPU device",
340                           "The GPU device number. -1 means GPU isn't used.",
341                           -1,
342                           G_MAXINT,
343                           -1,
344                           static_cast<GParamFlags>(G_PARAM_READWRITE |
345                                                    G_PARAM_CONSTRUCT_ONLY));
346   g_object_class_install_property(gobject_class, PROP_GPU_DEVICE, spec);
347 }
348 
349 static bool
gplasma_object_check_not_released(GPlasmaObjectPrivate * priv,GError ** error,const gchar * context)350 gplasma_object_check_not_released(GPlasmaObjectPrivate *priv,
351                                   GError **error,
352                                   const gchar *context)
353 {
354   if (priv->client) {
355     return true;
356   }
357 
358   auto id_priv = GPLASMA_OBJECT_ID_GET_PRIVATE(priv->id);
359   auto id_hex = id_priv->id.hex();
360   g_set_error(error,
361               GARROW_ERROR,
362               GARROW_ERROR_INVALID,
363               "%s: Can't process released object: <%s>",
364               context,
365               id_hex.c_str());
366   return false;
367 }
368 
369 static void
gplasma_object_release_resources(GPlasmaObjectPrivate * priv)370 gplasma_object_release_resources(GPlasmaObjectPrivate *priv)
371 {
372   if (priv->client) {
373     g_object_unref(priv->client);
374     priv->client = nullptr;
375   }
376 
377   if (priv->data) {
378     g_object_unref(priv->data);
379     priv->data = nullptr;
380   }
381 
382   if (priv->metadata) {
383     g_object_unref(priv->metadata);
384     priv->metadata = nullptr;
385   }
386 }
387 
G_DEFINE_TYPE(GPlasmaCreatedObject,gplasma_created_object,GPLASMA_TYPE_OBJECT)388 G_DEFINE_TYPE(GPlasmaCreatedObject,
389               gplasma_created_object,
390               GPLASMA_TYPE_OBJECT)
391 
392 static void
393 gplasma_created_object_dispose(GObject *object)
394 {
395   auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
396 
397   if (priv->client) {
398     gplasma_created_object_abort(GPLASMA_CREATED_OBJECT(object), NULL);
399   }
400 
401   G_OBJECT_CLASS(gplasma_created_object_parent_class)->dispose(object);
402 }
403 
404 static void
gplasma_created_object_init(GPlasmaCreatedObject * object)405 gplasma_created_object_init(GPlasmaCreatedObject *object)
406 {
407 }
408 
409 static void
gplasma_created_object_class_init(GPlasmaCreatedObjectClass * klass)410 gplasma_created_object_class_init(GPlasmaCreatedObjectClass *klass)
411 {
412   auto gobject_class = G_OBJECT_CLASS(klass);
413 
414   gobject_class->dispose = gplasma_created_object_dispose;
415 }
416 
417 /**
418  * gplasma_created_object_seal:
419  * @object: A #GPlasmaCreatedObject.
420  * @error: (nullable): Return location for a #GError or %NULL.
421  *
422  * Seals the object in the object store. You can't use the sealed
423  * object anymore.
424  *
425  * Returns: %TRUE on success, %FALSE on error.
426  *
427  * Since: 0.12.0
428  */
429 gboolean
gplasma_created_object_seal(GPlasmaCreatedObject * object,GError ** error)430 gplasma_created_object_seal(GPlasmaCreatedObject *object,
431                             GError **error)
432 {
433   const auto context = "[plasma][created-object][seal]";
434 
435   auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
436   if (!gplasma_object_check_not_released(priv, error, context)) {
437     return FALSE;
438   }
439 
440   auto plasma_client = gplasma_client_get_raw(priv->client);
441   auto id_priv = GPLASMA_OBJECT_ID_GET_PRIVATE(priv->id);
442   auto status = plasma_client->Seal(id_priv->id);
443   auto success = garrow_error_check(error, status, context);
444   if (success) {
445     status = plasma_client->Release(id_priv->id);
446     success = garrow_error_check(error, status, context);
447     gplasma_object_release_resources(priv);
448   }
449   return success;
450 }
451 
452 /**
453  * gplasma_created_object_abort:
454  * @object: A #GPlasmaCreatedObject.
455  * @error: (nullable): Return location for a #GError or %NULL.
456  *
457  * Aborts the object in the object store. You can't use the aborted
458  * object anymore.
459  *
460  * Returns: %TRUE on success, %FALSE on error.
461  *
462  * Since: 0.12.0
463  */
464 gboolean
gplasma_created_object_abort(GPlasmaCreatedObject * object,GError ** error)465 gplasma_created_object_abort(GPlasmaCreatedObject *object,
466                              GError **error)
467 {
468   const auto context = "[plasma][created-object][abort]";
469 
470   auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
471   if (!gplasma_object_check_not_released(priv, error, context)) {
472     return FALSE;
473   }
474 
475   auto plasma_client = gplasma_client_get_raw(priv->client);
476   auto id_priv = GPLASMA_OBJECT_ID_GET_PRIVATE(priv->id);
477   auto status = plasma_client->Release(id_priv->id);
478   auto success = garrow_error_check(error, status, context);
479   if (success) {
480     status = plasma_client->Abort(id_priv->id);
481     success = garrow_error_check(error, status, context);
482     gplasma_object_release_resources(priv);
483   }
484   return success;
485 }
486 
487 
G_DEFINE_TYPE(GPlasmaReferredObject,gplasma_referred_object,GPLASMA_TYPE_OBJECT)488 G_DEFINE_TYPE(GPlasmaReferredObject,
489               gplasma_referred_object,
490               GPLASMA_TYPE_OBJECT)
491 
492 static void
493 gplasma_referred_object_dispose(GObject *object)
494 {
495   auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
496 
497   gplasma_object_release_resources(priv);
498 
499   G_OBJECT_CLASS(gplasma_referred_object_parent_class)->dispose(object);
500 }
501 
502 static void
gplasma_referred_object_init(GPlasmaReferredObject * object)503 gplasma_referred_object_init(GPlasmaReferredObject *object)
504 {
505 }
506 
507 static void
gplasma_referred_object_class_init(GPlasmaReferredObjectClass * klass)508 gplasma_referred_object_class_init(GPlasmaReferredObjectClass *klass)
509 {
510   auto gobject_class = G_OBJECT_CLASS(klass);
511 
512   gobject_class->dispose = gplasma_referred_object_dispose;
513 }
514 
515 /**
516  * gplasma_referred_object_release:
517  * @object: A #GPlasmaReferredObject.
518  * @error: (nullable): Return location for a #GError or %NULL.
519  *
520  * Releases the object explicitly. The object is no longer valid.
521  *
522  * Returns: %TRUE on success, %FALSE on error.
523  *
524  * Since: 0.12.0
525  */
526 gboolean
gplasma_referred_object_release(GPlasmaReferredObject * object,GError ** error)527 gplasma_referred_object_release(GPlasmaReferredObject *object,
528                                 GError **error)
529 {
530   const auto context = "[plasma][referred-object][release]";
531 
532   auto priv = GPLASMA_OBJECT_GET_PRIVATE(object);
533   if (!gplasma_object_check_not_released(priv, error, context)) {
534     return FALSE;
535   }
536 
537   gplasma_object_release_resources(priv);
538   return TRUE;
539 }
540 
541 G_END_DECLS
542 
543 plasma::ObjectID
gplasma_object_id_get_raw(GPlasmaObjectID * id)544 gplasma_object_id_get_raw(GPlasmaObjectID *id)
545 {
546   auto priv = GPLASMA_OBJECT_ID_GET_PRIVATE(id);
547   return priv->id;
548 }
549 
550 GPlasmaCreatedObject *
gplasma_created_object_new_raw(GPlasmaClient * client,GPlasmaObjectID * id,std::shared_ptr<arrow::Buffer> * raw_data,GArrowBuffer * data,std::shared_ptr<arrow::Buffer> * raw_metadata,GArrowBuffer * metadata,gint gpu_device)551 gplasma_created_object_new_raw(GPlasmaClient *client,
552                                GPlasmaObjectID *id,
553                                std::shared_ptr<arrow::Buffer> *raw_data,
554                                GArrowBuffer *data,
555                                std::shared_ptr<arrow::Buffer> *raw_metadata,
556                                GArrowBuffer *metadata,
557                                gint gpu_device)
558 {
559   auto object = g_object_new(GPLASMA_TYPE_CREATED_OBJECT,
560                              "client", client,
561                              "id", id,
562                              "raw-data", raw_data,
563                              "data", data,
564                              "raw-metadata", raw_metadata,
565                              "metadata", metadata,
566                              "gpu-device", gpu_device,
567                              NULL);
568   return GPLASMA_CREATED_OBJECT(object);
569 }
570 
571 GPlasmaReferredObject *
gplasma_referred_object_new_raw(GPlasmaClient * client,GPlasmaObjectID * id,std::shared_ptr<arrow::Buffer> * raw_data,GArrowBuffer * data,std::shared_ptr<arrow::Buffer> * raw_metadata,GArrowBuffer * metadata,gint gpu_device)572 gplasma_referred_object_new_raw(GPlasmaClient *client,
573                                 GPlasmaObjectID *id,
574                                 std::shared_ptr<arrow::Buffer> *raw_data,
575                                 GArrowBuffer *data,
576                                 std::shared_ptr<arrow::Buffer> *raw_metadata,
577                                 GArrowBuffer *metadata,
578                                 gint gpu_device)
579 {
580   auto object = g_object_new(GPLASMA_TYPE_REFERRED_OBJECT,
581                              "client", client,
582                              "id", id,
583                              "raw-data", raw_data,
584                              "data", data,
585                              "raw-metadata", raw_metadata,
586                              "metadata", metadata,
587                              "gpu-device", gpu_device,
588                              NULL);
589   return GPLASMA_REFERRED_OBJECT(object);
590 }
591