1 /**
2  * @file   status.h
3  *
4  * @section LICENSE
5  *
6  * The BSD License
7  *
8  * @copyright Copyright (c) 2017-2021 TileDB, Inc.
9  *            Copyright (c) 2011 The LevelDB Authors. All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions are met:
13 
14  * Redistributions of source code must retain the above copyright notice, this
15  * list of conditions and the following disclaimer.
16  *
17  * Redistributions in binary form must reproduce the above copyright notice,
18  * this list of conditions and the following disclaimer in the documentation
19  * and/or other materials provided with the distribution.
20  *
21  * Neither the name of Google Inc. nor the names of its contributors may be used
22  * to endorse or promote products derived from this software without specific
23  * prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  *
37  * @section DESCRIPTION
38  *
39  * A Status object encapsulates the result of an operation.  It may indicate
40  * success, or it may indicate an error with an associated error message.
41  *
42  * Multiple threads can invoke const methods on a Status without
43  * external synchronization, but if any of the threads may call a
44  * non-const method, all threads accessing the same Status must use
45  * external synchronization.
46  *
47  * This code has been adopted from the LevelDB project
48  * (https://github.com/google/leveldb).
49  */
50 
51 #ifndef TILEDB_STATUS_H
52 #define TILEDB_STATUS_H
53 
54 #include <cstdint>
55 #include <cstring>
56 #include <optional>
57 #include <string>
58 #include <tuple>
59 using std::tuple, std::optional, std::nullopt;
60 
61 #include "tiledb/common/heap_memory.h"
62 
63 namespace tiledb {
64 namespace common {
65 
66 #define RETURN_NOT_OK(s) \
67   do {                   \
68     Status _s = (s);     \
69     if (!_s.ok()) {      \
70       return _s;         \
71     }                    \
72   } while (false)
73 
74 #define RETURN_NOT_OK_ELSE(s, else_) \
75   do {                               \
76     Status _s = (s);                 \
77     if (!_s.ok()) {                  \
78       else_;                         \
79       return _s;                     \
80     }                                \
81   } while (false)
82 
83 #define RETURN_NOT_OK_TUPLE(s)   \
84   do {                           \
85     Status _s = (s);             \
86     if (!_s.ok()) {              \
87       return {_s, std::nullopt}; \
88     }                            \
89   } while (false)
90 
91 enum class StatusCode : char {
92   Ok,
93   Error,
94   StorageManager,
95   FragmentMetadata,
96   ArraySchema,
97   ArraySchemaEvolution,
98   Metadata,
99   IO,
100   Mem,
101   GZip,
102   Compression,
103   Tile,
104   TileIO,
105   Buffer,
106   Query,
107   ValidityVector,
108   VFS,
109   ConstBuffer,
110   Dimension,
111   Domain,
112   Consolidator,
113   LRUCache,
114   KV,
115   KVItem,
116   KVIter,
117   Config,
118   Utils,
119   FS_S3,
120   FS_AZURE,
121   FS_GCS,
122   FS_HDFS,
123   FS_MEM,
124   Attribute,
125   WriteCellSlabIter,
126   SparseGlobalOrderReaderError,
127   SparseUnorderedWithDupsReaderError,
128   DenseReaderError,
129   Reader,
130   Writer,
131   PreallocatedBuffer,
132   Filter,
133   Encryption,
134   Array,
135   VFSFileHandleError,
136   ContextError,
137   SubarrayError,
138   SubarrayPartitionerError,
139   RTreeError,
140   CellSlabIterError,
141   RestError,
142   SerializationError,
143   ChecksumError,
144   ThreadPoolError,
145   FragmentInfoError,
146   DenseTilerError,
147   QueryConditionError
148 };
149 
150 class Status {
151  public:
152   /* ********************************* */
153   /*     CONSTRUCTORS & DESTRUCTORS    */
154   /* ********************************* */
155 
156   /** Constructor with success status (empty state). */
Status()157   Status()
158       : state_(nullptr) {
159   }
160 
161   /**
162    * General constructor for arbitrary status
163    */
164   Status(StatusCode code, const std::string& msg);
165 
166   /** Destructor. */
~Status()167   ~Status() {
168     tdb_delete_array(state_);
169   }
170 
171   /** Copy the specified status. */
172   Status(const Status& s);
173 
174   /** Assign status. */
175   void operator=(const Status& s);
176 
177   /**  Return a success status **/
Ok()178   static Status Ok() {
179     return Status();
180   }
181 
182   /**  Return a generic Error class Status **/
Error(const std::string & msg)183   static Status Error(const std::string& msg) {
184     return Status(StatusCode::Error, msg);
185   }
186 
187   /** Return a StorageManager error class Status with a given message **/
StorageManagerError(const std::string & msg)188   static Status StorageManagerError(const std::string& msg) {
189     return Status(StatusCode::StorageManager, msg);
190   }
191 
192   /** Return a FragmentMetadata error class Status with a given message **/
FragmentMetadataError(const std::string & msg)193   static Status FragmentMetadataError(const std::string& msg) {
194     return Status(StatusCode::FragmentMetadata, msg);
195   }
196 
197   /** Return a ArraySchema error class Status with a given message **/
ArraySchemaError(const std::string & msg)198   static Status ArraySchemaError(const std::string& msg) {
199     return Status(StatusCode::ArraySchema, msg);
200   }
201 
202   /** Return a ArraySchemaEvolution error class Status with a given message **/
ArraySchemaEvolutionError(const std::string & msg)203   static Status ArraySchemaEvolutionError(const std::string& msg) {
204     return Status(StatusCode::ArraySchemaEvolution, msg);
205   }
206 
207   /** Return a Metadata error class Status with a given message **/
MetadataError(const std::string & msg)208   static Status MetadataError(const std::string& msg) {
209     return Status(StatusCode::Metadata, msg);
210   }
211 
212   /** Return a IO error class Status with a given message **/
IOError(const std::string & msg)213   static Status IOError(const std::string& msg) {
214     return Status(StatusCode::IO, msg);
215   }
216 
217   /** Return a Memory error class Status with a given message **/
MemError(const std::string & msg)218   static Status MemError(const std::string& msg) {
219     return Status(StatusCode::Mem, msg);
220   }
221 
222   /** Return a ArrayError error class Status with a given message **/
GZipError(const std::string & msg)223   static Status GZipError(const std::string& msg) {
224     return Status(StatusCode::GZip, msg);
225   }
226 
227   /** Return a ArrayError error class Status with a given message **/
ChecksumError(const std::string & msg)228   static Status ChecksumError(const std::string& msg) {
229     return Status(StatusCode::ChecksumError, msg);
230   }
231 
232   /** Return a ArrayError error class Status with a given message **/
CompressionError(const std::string & msg)233   static Status CompressionError(const std::string& msg) {
234     return Status(StatusCode::Compression, msg);
235   }
236 
237   /** Return a TileError error class Status with a given message **/
TileError(const std::string & msg)238   static Status TileError(const std::string& msg) {
239     return Status(StatusCode::Tile, msg);
240   }
241 
242   /** Return a TileIOError error class Status with a given message **/
TileIOError(const std::string & msg)243   static Status TileIOError(const std::string& msg) {
244     return Status(StatusCode::TileIO, msg);
245   }
246 
247   /** Return a BufferError error class Status with a given message **/
BufferError(const std::string & msg)248   static Status BufferError(const std::string& msg) {
249     return Status(StatusCode::Buffer, msg);
250   }
251 
252   /** Return a QueryError error class Status with a given message **/
QueryError(const std::string & msg)253   static Status QueryError(const std::string& msg) {
254     return Status(StatusCode::Query, msg);
255   }
256 
257   /** Return a ValidityVectorError error class Status with a given message **/
ValidityVectorError(const std::string & msg)258   static Status ValidityVectorError(const std::string& msg) {
259     return Status(StatusCode::ValidityVector, msg);
260   }
261 
262   /** Return a VFSError error class Status with a given message **/
VFSError(const std::string & msg)263   static Status VFSError(const std::string& msg) {
264     return Status(StatusCode::VFS, msg);
265   }
266 
267   /** Return a ConstBufferError error class Status with a given message **/
ConstBufferError(const std::string & msg)268   static Status ConstBufferError(const std::string& msg) {
269     return Status(StatusCode::ConstBuffer, msg);
270   }
271 
272   /** Return a DimensionError error class Status with a given message **/
DimensionError(const std::string & msg)273   static Status DimensionError(const std::string& msg) {
274     return Status(StatusCode::Dimension, msg);
275   }
276 
277   /** Return a DomainError error class Status with a given message **/
DomainError(const std::string & msg)278   static Status DomainError(const std::string& msg) {
279     return Status(StatusCode::Domain, msg);
280   }
281 
282   /** Return a ConsolidatorError error class Status with a given message **/
ConsolidatorError(const std::string & msg)283   static Status ConsolidatorError(const std::string& msg) {
284     return Status(StatusCode::Consolidator, msg);
285   }
286 
287   /** Return a LRUCacheError error class Status with a given message **/
LRUCacheError(const std::string & msg)288   static Status LRUCacheError(const std::string& msg) {
289     return Status(StatusCode::LRUCache, msg);
290   }
291 
292   /** Return a KVError error class Status with a given message **/
KVError(const std::string & msg)293   static Status KVError(const std::string& msg) {
294     return Status(StatusCode::KV, msg);
295   }
296 
297   /** Return a KVItemError error class Status with a given message **/
KVItemError(const std::string & msg)298   static Status KVItemError(const std::string& msg) {
299     return Status(StatusCode::KVItem, msg);
300   }
301 
302   /** Return a KVIterError error class Status with a given message **/
KVIterError(const std::string & msg)303   static Status KVIterError(const std::string& msg) {
304     return Status(StatusCode::KVIter, msg);
305   }
306 
307   /** Return a ConfigError error class Status with a given message **/
ConfigError(const std::string & msg)308   static Status ConfigError(const std::string& msg) {
309     return Status(StatusCode::Config, msg);
310   }
311 
312   /** Return a UtilsError error class Status with a given message **/
UtilsError(const std::string & msg)313   static Status UtilsError(const std::string& msg) {
314     return Status(StatusCode::Utils, msg);
315   }
316 
317   /** Return a UtilsError error class Status with a given message **/
S3Error(const std::string & msg)318   static Status S3Error(const std::string& msg) {
319     return Status(StatusCode::FS_S3, msg);
320   }
321 
322   /** Return a UtilsError error class Status with a given message **/
AzureError(const std::string & msg)323   static Status AzureError(const std::string& msg) {
324     return Status(StatusCode::FS_AZURE, msg);
325   }
326 
327   /** Return a UtilsError error class Status with a given message **/
GCSError(const std::string & msg)328   static Status GCSError(const std::string& msg) {
329     return Status(StatusCode::FS_GCS, msg);
330   }
331 
332   /** Return a UtilsError error class Status with a given message **/
HDFSError(const std::string & msg)333   static Status HDFSError(const std::string& msg) {
334     return Status(StatusCode::FS_HDFS, msg);
335   }
336 
337   /** Return a MemFSError error class Status with a given message **/
MemFSError(const std::string & msg)338   static Status MemFSError(const std::string& msg) {
339     return Status(StatusCode::FS_MEM, msg);
340   }
341 
342   /** Return a AttributeError error class Status with a given message **/
AttributeError(const std::string & msg)343   static Status AttributeError(const std::string& msg) {
344     return Status(StatusCode::Attribute, msg);
345   }
346 
347   /** Return a WriteCellSlabIterError error class Status with a given message
348    * **/
WriteCellSlabIterError(const std::string & msg)349   static Status WriteCellSlabIterError(const std::string& msg) {
350     return Status(StatusCode::WriteCellSlabIter, msg);
351   }
352 
353   /** Return a SparseGlobalOrderReaderError error class Status with a given
354    * message **/
SparseGlobalOrderReaderError(const std::string & msg)355   static Status SparseGlobalOrderReaderError(const std::string& msg) {
356     return Status(StatusCode::SparseGlobalOrderReaderError, msg);
357   }
358 
359   /** Return a SparseUnorderedWithDupsReaderError error class Status with a
360    * given message **/
SparseUnorderedWithDupsReaderError(const std::string & msg)361   static Status SparseUnorderedWithDupsReaderError(const std::string& msg) {
362     return Status(StatusCode::SparseUnorderedWithDupsReaderError, msg);
363   }
364 
365   /** Return a DenseReaderError error class Status with a given message **/
DenseReaderError(const std::string & msg)366   static Status DenseReaderError(const std::string& msg) {
367     return Status(StatusCode::DenseReaderError, msg);
368   }
369 
370   /** Return a ReaderError error class Status with a given message **/
ReaderError(const std::string & msg)371   static Status ReaderError(const std::string& msg) {
372     return Status(StatusCode::Reader, msg);
373   }
374 
375   /** Return a WriterError error class Status with a given message **/
WriterError(const std::string & msg)376   static Status WriterError(const std::string& msg) {
377     return Status(StatusCode::Writer, msg);
378   }
379 
380   /** Return a PreallocatedBufferError error class Status with a given message
381    * **/
PreallocatedBufferError(const std::string & msg)382   static Status PreallocatedBufferError(const std::string& msg) {
383     return Status(StatusCode::PreallocatedBuffer, msg);
384   }
385 
386   /** Return a FilterError error class Status with a given message **/
FilterError(const std::string & msg)387   static Status FilterError(const std::string& msg) {
388     return Status(StatusCode::Filter, msg);
389   }
390 
391   /** Return a EncryptionError error class Status with a given message **/
EncryptionError(const std::string & msg)392   static Status EncryptionError(const std::string& msg) {
393     return Status(StatusCode::Encryption, msg);
394   }
395 
396   /** Return an ArrayError error class Status with a given message **/
ArrayError(const std::string & msg)397   static Status ArrayError(const std::string& msg) {
398     return Status(StatusCode::Array, msg);
399   }
400 
401   /** Return a VFSFileHandle error class Status with a given message **/
VFSFileHandleError(const std::string & msg)402   static Status VFSFileHandleError(const std::string& msg) {
403     return Status(StatusCode::VFSFileHandleError, msg);
404   }
405 
406   /** Return a ContextError error class Status with a given message **/
ContextError(const std::string & msg)407   static Status ContextError(const std::string& msg) {
408     return Status(StatusCode::ContextError, msg);
409   }
410 
411   /** Return a SubarrayError error class Status with a given message **/
SubarrayError(const std::string & msg)412   static Status SubarrayError(const std::string& msg) {
413     return Status(StatusCode::SubarrayError, msg);
414   }
415 
416   /** Return a SubarrayPartitionerError error class Status with a given message
417    * **/
SubarrayPartitionerError(const std::string & msg)418   static Status SubarrayPartitionerError(const std::string& msg) {
419     return Status(StatusCode::SubarrayPartitionerError, msg);
420   }
421 
422   /** Return a RTreeError error class Status with a given message **/
RTreeError(const std::string & msg)423   static Status RTreeError(const std::string& msg) {
424     return Status(StatusCode::RTreeError, msg);
425   }
426 
427   /** Return a CellSlabIterError error class Status with a given message **/
CellSlabIterError(const std::string & msg)428   static Status CellSlabIterError(const std::string& msg) {
429     return Status(StatusCode::CellSlabIterError, msg);
430   }
431 
432   /** Return a RestError error class Status with a given message **/
RestError(const std::string & msg)433   static Status RestError(const std::string& msg) {
434     return Status(StatusCode::RestError, msg);
435   }
436 
437   /** Return a SerializationError error class Status with a given message **/
SerializationError(const std::string & msg)438   static Status SerializationError(const std::string& msg) {
439     return Status(StatusCode::SerializationError, msg);
440   }
441 
442   /** Return a ThreadPoolError error class Status with a given message **/
ThreadPoolError(const std::string & msg)443   static Status ThreadPoolError(const std::string& msg) {
444     return Status(StatusCode::ThreadPoolError, msg);
445   }
446 
447   /** Return a FragmentInfoError error class Status with a given message **/
FragmentInfoError(const std::string & msg)448   static Status FragmentInfoError(const std::string& msg) {
449     return Status(StatusCode::FragmentInfoError, msg);
450   }
451 
452   /** Return a DenseTilerError error class Status with a given message **/
DenseTilerError(const std::string & msg)453   static Status DenseTilerError(const std::string& msg) {
454     return Status(StatusCode::DenseTilerError, msg);
455   }
456 
457   /** Return a QueryConditionError error class Status with a given message **/
QueryConditionError(const std::string & msg)458   static Status QueryConditionError(const std::string& msg) {
459     return Status(StatusCode::QueryConditionError, msg);
460   }
461 
462   /** Returns true iff the status indicates success **/
ok()463   bool ok() const {
464     return (state_ == nullptr);
465   }
466 
467   /**
468    * Return a std::string representation of this status object suitable for
469    * printing.  Return "Ok" for success.
470    */
471   std::string to_string() const;
472 
473   /** Return a string representation of the status code **/
474   std::string code_to_string() const;
475 
476   /** Return the status code of this Status object **/
code()477   StatusCode code() const {
478     return (
479         (state_ == nullptr) ? StatusCode::Ok :
480                               static_cast<StatusCode>(state_[4]));
481   }
482 
483   /** Return an std::string copy of the Status message **/
message()484   std::string message() const {
485     uint32_t length;
486     memcpy(&length, state_, sizeof(length));
487     std::string msg;
488     msg.append((state_ + 7), length);
489     return msg;
490   }
491 
492  private:
493   /* ********************************* */
494   /*         PRIVATE ATTRIBUTES        */
495   /* ********************************* */
496 
497   /**
498    * OK status has a NULL state_.  Otherwise, state_ is a new[] array
499    * of the following form:
500    *    state_[0..3] == length of message
501    *    state_[4]    == code
502    *    state_[5..6] == reserved
503    *    state_[7..]  == message
504    */
505   const char* state_;
506 
507   /* ********************************* */
508   /*           PRIVATE METHODS         */
509   /* ********************************* */
510 
511   /** Clones and returns the input state (allocates memory). */
512   static const char* copy_state(const char* s);
513 };
514 
Status(const Status & s)515 inline Status::Status(const Status& s) {
516   state_ = (s.state_ == nullptr) ? nullptr : copy_state(s.state_);
517 }
518 
519 inline void Status::operator=(const Status& s) {
520   // The following condition catches both aliasing (when this == &s),
521   // and when both s and *this are ok.
522   if (state_ != s.state_) {
523     tdb_delete_array(state_);
524     state_ = (s.state_ == nullptr) ? nullptr : copy_state(s.state_);
525   }
526 }
527 
528 }  // namespace common
529 }  // namespace tiledb
530 
531 #endif  // TILEDB_STATUS_H
532