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