Skip to content

Commit 3a7b9f2

Browse files
committed
refine error handling
1 parent 219b030 commit 3a7b9f2

13 files changed

Lines changed: 128 additions & 140 deletions

src/iceberg/avro/avro_stream_internal.cc

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,9 @@ bool AvroInputStream::next(const uint8_t** data, size_t* len) {
6666
}
6767

6868
void AvroInputStream::backup(size_t len) {
69-
ICEBERG_CHECK(len <= buffer_pos_, "Cannot backup {} bytes, only {} bytes available",
70-
len, buffer_pos_);
69+
ICEBERG_CHECK_OR_DIE(len <= buffer_pos_,
70+
"Cannot backup {} bytes, only {} bytes available", len,
71+
buffer_pos_);
7172

7273
buffer_pos_ -= len;
7374
byte_count_ -= len;
@@ -88,7 +89,8 @@ size_t AvroInputStream::byteCount() const { return byte_count_; }
8889

8990
void AvroInputStream::seek(int64_t position) {
9091
auto status = input_stream_->Seek(position);
91-
ICEBERG_CHECK(status.ok(), "Failed to seek to {}, got {}", position, status.ToString());
92+
ICEBERG_CHECK_OR_DIE(status.ok(), "Failed to seek to {}, got {}", position,
93+
status.ToString());
9294

9395
buffer_pos_ = 0;
9496
available_bytes_ = 0;
@@ -116,8 +118,9 @@ bool AvroOutputStream::next(uint8_t** data, size_t* len) {
116118
}
117119

118120
void AvroOutputStream::backup(size_t len) {
119-
ICEBERG_CHECK(len <= buffer_pos_, "Cannot backup {} bytes, only {} bytes available",
120-
len, buffer_pos_);
121+
ICEBERG_CHECK_OR_DIE(len <= buffer_pos_,
122+
"Cannot backup {} bytes, only {} bytes available", len,
123+
buffer_pos_);
121124
buffer_pos_ -= len;
122125
}
123126

@@ -126,12 +129,12 @@ uint64_t AvroOutputStream::byteCount() const { return flushed_bytes_ + buffer_po
126129
void AvroOutputStream::flush() {
127130
if (buffer_pos_ > 0) {
128131
auto status = output_stream_->Write(buffer_.data(), buffer_pos_);
129-
ICEBERG_CHECK(status.ok(), "Write failed {}", status.ToString());
132+
ICEBERG_CHECK_OR_DIE(status.ok(), "Write failed {}", status.ToString());
130133
flushed_bytes_ += buffer_pos_;
131134
buffer_pos_ = 0;
132135
}
133136
auto status = output_stream_->Flush();
134-
ICEBERG_CHECK(status.ok(), "Flush failed {}", status.ToString());
137+
ICEBERG_CHECK_OR_DIE(status.ok(), "Flush failed {}", status.ToString());
135138
}
136139

137140
const std::shared_ptr<::arrow::io::OutputStream>& AvroOutputStream::arrow_output_stream()

src/iceberg/exception.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class ICEBERG_EXPORT ExpressionError : public IcebergError {
4444
explicit ExpressionError(const std::string& what) : IcebergError(what) {}
4545
};
4646

47-
#define ICEBERG_CHECK(condition, ...) \
47+
#define ICEBERG_CHECK_OR_DIE(condition, ...) \
4848
do { \
4949
if (!(condition)) [[unlikely]] { \
5050
throw iceberg::IcebergError(std::format(__VA_ARGS__)); \

src/iceberg/table_metadata.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ Result<std::shared_ptr<Schema>> TableMetadata::Schema() const {
6969
}
7070

7171
Result<std::shared_ptr<Schema>> TableMetadata::SchemaById(
72-
const std::optional<int32_t>& schema_id) const {
72+
std::optional<int32_t> schema_id) const {
7373
auto iter = std::ranges::find_if(schemas, [schema_id](const auto& schema) {
74-
return schema->schema_id() == schema_id;
74+
return schema != nullptr && schema->schema_id() == schema_id;
7575
});
7676
if (iter == schemas.end()) {
7777
return NotFound("Schema with ID {} is not found", schema_id.value_or(-1));
@@ -81,7 +81,7 @@ Result<std::shared_ptr<Schema>> TableMetadata::SchemaById(
8181

8282
Result<std::shared_ptr<PartitionSpec>> TableMetadata::PartitionSpec() const {
8383
auto iter = std::ranges::find_if(partition_specs, [this](const auto& spec) {
84-
return spec->spec_id() == default_spec_id;
84+
return spec != nullptr && spec->spec_id() == default_spec_id;
8585
});
8686
if (iter == partition_specs.end()) {
8787
return NotFound("Default partition spec is not found");
@@ -91,7 +91,7 @@ Result<std::shared_ptr<PartitionSpec>> TableMetadata::PartitionSpec() const {
9191

9292
Result<std::shared_ptr<SortOrder>> TableMetadata::SortOrder() const {
9393
auto iter = std::ranges::find_if(sort_orders, [this](const auto& order) {
94-
return order->order_id() == default_sort_order_id;
94+
return order != nullptr && order->order_id() == default_sort_order_id;
9595
});
9696
if (iter == sort_orders.end()) {
9797
return NotFound("Default sort order is not found");
@@ -105,7 +105,7 @@ Result<std::shared_ptr<Snapshot>> TableMetadata::Snapshot() const {
105105

106106
Result<std::shared_ptr<Snapshot>> TableMetadata::SnapshotById(int64_t snapshot_id) const {
107107
auto iter = std::ranges::find_if(snapshots, [snapshot_id](const auto& snapshot) {
108-
return snapshot->snapshot_id == snapshot_id;
108+
return snapshot != nullptr && snapshot->snapshot_id == snapshot_id;
109109
});
110110
if (iter == snapshots.end()) {
111111
return NotFound("Snapshot with ID {} is not found", snapshot_id);

src/iceberg/table_metadata.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ struct ICEBERG_EXPORT TableMetadata {
128128
Result<std::shared_ptr<iceberg::Schema>> Schema() const;
129129
/// \brief Get the current schema by ID, return NotFoundError if not found
130130
Result<std::shared_ptr<iceberg::Schema>> SchemaById(
131-
const std::optional<int32_t>& schema_id) const;
131+
std::optional<int32_t> schema_id) const;
132132
/// \brief Get the current partition spec, return NotFoundError if not found
133133
Result<std::shared_ptr<iceberg::PartitionSpec>> PartitionSpec() const;
134134
/// \brief Get the current sort order, return NotFoundError if not found

src/iceberg/test/snapshot_util_test.cc

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -337,11 +337,11 @@ TEST_F(SnapshotUtilTest, SnapshotAfter) {
337337
TEST_F(SnapshotUtilTest, SnapshotIdAsOfTime) {
338338
// Test with timestamp before any snapshot
339339
auto early_timestamp = base_timestamp_ - std::chrono::milliseconds(1000);
340-
auto snapshot_id = SnapshotUtil::NullableSnapshotIdAsOfTime(*table_, early_timestamp);
340+
auto snapshot_id = SnapshotUtil::OptionalSnapshotIdAsOfTime(*table_, early_timestamp);
341341
EXPECT_FALSE(snapshot_id.has_value());
342342

343343
// Test with timestamp at base snapshot
344-
auto snapshot_id1 = SnapshotUtil::NullableSnapshotIdAsOfTime(*table_, base_timestamp_);
344+
auto snapshot_id1 = SnapshotUtil::OptionalSnapshotIdAsOfTime(*table_, base_timestamp_);
345345
ASSERT_TRUE(snapshot_id1.has_value());
346346
EXPECT_EQ(snapshot_id1.value(), base_snapshot_id_);
347347

@@ -357,21 +357,18 @@ TEST_F(SnapshotUtilTest, LatestSnapshot) {
357357
ICEBERG_UNWRAP_OR_FAIL(
358358
auto main_snapshot,
359359
SnapshotUtil::LatestSnapshot(*table_, std::string(SnapshotRef::kMainBranch)));
360-
ASSERT_TRUE(main_snapshot.has_value());
361-
EXPECT_EQ(main_snapshot.value()->snapshot_id, main2_snapshot_id_);
360+
EXPECT_EQ(main_snapshot->snapshot_id, main2_snapshot_id_);
362361

363362
// Test branch
364363
ICEBERG_UNWRAP_OR_FAIL(auto branch_snapshot,
365364
SnapshotUtil::LatestSnapshot(*table_, "b1"));
366-
ASSERT_TRUE(branch_snapshot.has_value());
367-
EXPECT_EQ(branch_snapshot.value()->snapshot_id, branch_snapshot_id_);
365+
EXPECT_EQ(branch_snapshot->snapshot_id, branch_snapshot_id_);
368366

369367
// Test non-existing branch
370368
ICEBERG_UNWRAP_OR_FAIL(auto non_existing,
371369
SnapshotUtil::LatestSnapshot(*table_, "non-existing"));
372-
ASSERT_TRUE(non_existing.has_value());
373370
// Should return current snapshot
374-
EXPECT_EQ(non_existing.value()->snapshot_id, main2_snapshot_id_);
371+
EXPECT_EQ(non_existing->snapshot_id, main2_snapshot_id_);
375372
}
376373

377374
} // namespace iceberg

src/iceberg/type.cc

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,9 @@ StructType::InitFieldByLowerCaseName(const StructType& self) {
141141
}
142142

143143
ListType::ListType(SchemaField element) : element_(std::move(element)) {
144-
ICEBERG_CHECK(element_.name() == kElementName,
145-
"ListType: child field name should be '{}', was '{}'", kElementName,
146-
element_.name());
144+
ICEBERG_CHECK_OR_DIE(element_.name() == kElementName,
145+
"ListType: child field name should be '{}', was '{}'",
146+
kElementName, element_.name());
147147
}
148148

149149
ListType::ListType(int32_t field_id, std::shared_ptr<Type> type, bool optional)
@@ -200,12 +200,12 @@ bool ListType::Equals(const Type& other) const {
200200

201201
MapType::MapType(SchemaField key, SchemaField value)
202202
: fields_{std::move(key), std::move(value)} {
203-
ICEBERG_CHECK(this->key().name() == kKeyName,
204-
"MapType: key field name should be '{}', was '{}'", kKeyName,
205-
this->key().name());
206-
ICEBERG_CHECK(this->value().name() == kValueName,
207-
"MapType: value field name should be '{}', was '{}'", kValueName,
208-
this->value().name());
203+
ICEBERG_CHECK_OR_DIE(this->key().name() == kKeyName,
204+
"MapType: key field name should be '{}', was '{}'", kKeyName,
205+
this->key().name());
206+
ICEBERG_CHECK_OR_DIE(this->value().name() == kValueName,
207+
"MapType: value field name should be '{}', was '{}'", kValueName,
208+
this->value().name());
209209
}
210210

211211
const SchemaField& MapType::key() const { return fields_[0]; }
@@ -292,8 +292,8 @@ bool DoubleType::Equals(const Type& other) const { return other.type_id() == kTy
292292

293293
DecimalType::DecimalType(int32_t precision, int32_t scale)
294294
: precision_(precision), scale_(scale) {
295-
ICEBERG_CHECK(precision >= 0 && precision <= kMaxPrecision,
296-
"DecimalType: precision must be in [0, 38], was {}", precision);
295+
ICEBERG_CHECK_OR_DIE(precision >= 0 && precision <= kMaxPrecision,
296+
"DecimalType: precision must be in [0, 38], was {}", precision);
297297
}
298298

299299
int32_t DecimalType::precision() const { return precision_; }
@@ -341,7 +341,7 @@ std::string UuidType::ToString() const { return "uuid"; }
341341
bool UuidType::Equals(const Type& other) const { return other.type_id() == kTypeId; }
342342

343343
FixedType::FixedType(int32_t length) : length_(length) {
344-
ICEBERG_CHECK(length >= 0, "FixedType: length must be >= 0, was {}", length);
344+
ICEBERG_CHECK_OR_DIE(length >= 0, "FixedType: length must be >= 0, was {}", length);
345345
}
346346

347347
int32_t FixedType::length() const { return length_; }

src/iceberg/util/decimal.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,8 @@ bool RescaleWouldCauseDataLoss(const Decimal& value, int32_t delta_scale,
300300

301301
Decimal::Decimal(std::string_view str) {
302302
auto result = Decimal::FromString(str);
303-
ICEBERG_CHECK(result, "Failed to parse Decimal from string: {}, error: {}", str,
304-
result.error().message);
303+
ICEBERG_CHECK_OR_DIE(result, "Failed to parse Decimal from string: {}, error: {}", str,
304+
result.error().message);
305305
*this = std::move(result.value());
306306
}
307307

src/iceberg/util/macros.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,25 @@
4242
ICEBERG_ASSIGN_OR_RAISE_IMPL(ICEBERG_ASSIGN_OR_RAISE_NAME(result_, __COUNTER__), lhs, \
4343
rexpr)
4444

45+
// Macro for debug checks
4546
#define ICEBERG_DCHECK(expr, message) assert((expr) && (message))
4647

48+
// Macro for precondition checks, usually used for function arguments
49+
#define ICEBERG_PRECHECK(expr, ...) \
50+
do { \
51+
if (!(expr)) [[unlikely]] { \
52+
return InvalidArgument(__VA_ARGS__); \
53+
} \
54+
} while (0)
55+
56+
// Macro for state checks, usually used for unexpected states
57+
#define ICEBERG_CHECK(expr, ...) \
58+
do { \
59+
if (!(expr)) [[unlikely]] { \
60+
return Invalid(__VA_ARGS__); \
61+
} \
62+
} while (0)
63+
4764
#define ERROR_TO_EXCEPTION(error) \
4865
if (error.kind == iceberg::ErrorKind::kInvalidExpression) { \
4966
throw iceberg::ExpressionError(error.message); \

0 commit comments

Comments
 (0)