Skip to content

Commit

Permalink
Fix a bunch of throw statements to use Realm exceptions (#7141)
Browse files Browse the repository at this point in the history
* Fix a bunch of throw statements to use Realm exceptions
* check correct exception in test
* clang-format and replaced a couple of std::exceptions in SyncManager
* Updated changelog

---------

Co-authored-by: Jonathan Reams <[email protected]>
Co-authored-by: Jørgen Edelbo <[email protected]>
  • Loading branch information
3 people authored Nov 27, 2023
1 parent f59df94 commit bc48709
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 56 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

### Fixed
* <How do the end-user experience this issue? what was the impact?> ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?)
* None.
* Update existing std exceptions thrown by the Sync Client to use Realm exceptions. ([#6255](https://github.com/realm/realm-core/issues/6255), since v10.2.0)

### Breaking changes
* None.
* Update existing std exceptions thrown by the Sync Client to use Realm exceptions. ([PR #7141](https://github.com/realm/realm-core/pull/7141/files))

### Compatibility
* Fileformat: Generates files with format v23. Reads and automatically upgrade from fileformat v5.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ static void error(emscripten_fetch_t* fetch)
emscripten_fetch_get_response_headers(fetch, packed_headers.data(), packed_headers.size());

std::unique_ptr<FetchState> state(reinterpret_cast<FetchState*>(fetch->userData));
state->completion_block({fetch->status, 0, parse_headers(packed_headers), std::string(fetch->data, size_t(fetch->numBytes)), ErrorCodes::HTTPError});
state->completion_block({fetch->status, 0, parse_headers(packed_headers),
std::string(fetch->data, size_t(fetch->numBytes)), ErrorCodes::HTTPError});
}

void EmscriptenNetworkTransport::send_request_to_server(
Expand Down
23 changes: 14 additions & 9 deletions src/realm/object-store/sync/impl/sync_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ uint8_t value_of_hex_digit(char hex_digit)
return 10 + hex_digit - 'a';
}
else {
throw std::invalid_argument("Cannot get the value of a character that isn't a hex digit.");
throw LogicError(ErrorCodes::InvalidArgument, "Cannot get the value of a character that isn't a hex digit.");
}
}

Expand All @@ -82,7 +82,8 @@ bool character_is_unreserved(char character)
char decoded_char_for(const std::string& percent_encoding, size_t index)
{
if (index + 2 >= percent_encoding.length()) {
throw std::invalid_argument("Malformed string: not enough characters after '%' before end of string.");
throw LogicError(ErrorCodes::InvalidArgument,
"Malformed string: not enough characters after '%' before end of string.");
}
REALM_ASSERT(percent_encoding[index] == '%');
return (16 * value_of_hex_digit(percent_encoding[index + 1])) + value_of_hex_digit(percent_encoding[index + 2]);
Expand Down Expand Up @@ -126,7 +127,8 @@ std::string make_raw_string(const std::string& percent_encoded_string)
else {
// No need to decode. +1.
if (!character_is_unreserved(current)) {
throw std::invalid_argument("Input string is invalid: contains reserved characters.");
throw LogicError(ErrorCodes::InvalidArgument,
"Input string is invalid: contains reserved characters.");
}
buffer.push_back(current);
idx++;
Expand Down Expand Up @@ -207,7 +209,9 @@ std::string reserve_unique_file_name(const std::string& path, const std::string&
int fd = mkstemp(&path_buffer[0]);
if (fd < 0) {
int err = errno;
throw std::system_error(err, std::system_category());
throw RuntimeError(ErrorCodes::FileOperationFailed,
util::format("Failed to make temporary path: %1 (%2)",
std::system_error(err, std::system_category()).what(), err));
}
// Remove the file so we can use the name for our own file.
#ifdef _WIN32
Expand All @@ -225,7 +229,8 @@ static std::string validate_and_clean_path(const std::string& path)
REALM_ASSERT(path.length() > 0);
std::string escaped_path = util::make_percent_encoded_string(path);
if (filename_is_reserved(escaped_path))
throw std::invalid_argument(
throw LogicError(
ErrorCodes::InvalidArgument,
util::format("A path can't have an identifier reserved by the filesystem: '%1'", escaped_path));
return escaped_path;
}
Expand Down Expand Up @@ -419,10 +424,10 @@ std::string SyncFileManager::realm_file_path(const std::string& user_identity,
}
catch (const FileAccessError& e_hashed) {
// hashed test path also failed, give up and report error to user.
throw std::logic_error(util::format("A valid realm path cannot be created for the "
"Realm identity '%1' at neither '%2' nor '%3'. %4",
realm_file_name, preferred_name_with_suffix, hashed_path,
e_hashed.what()));
throw LogicError(ErrorCodes::InvalidArgument,
util::format("A valid realm path cannot be created for the "
"Realm identity '%1' at neither '%2' nor '%3'. %4",
realm_file_name, preferred_name_with_suffix, hashed_path, e_hashed.what()));
}
}

Expand Down
8 changes: 6 additions & 2 deletions src/realm/object-store/sync/sync_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <realm/util/sha_crypto.hpp>
#include <realm/util/hex_dump.hpp>

#include <realm/exceptions.hpp>

using namespace realm;
using namespace realm::_impl;

Expand Down Expand Up @@ -275,7 +277,8 @@ void SyncManager::set_logger_factory(SyncClientConfig::LoggerFactory factory)
m_config.logger_factory = std::move(factory);

if (m_sync_client)
throw std::logic_error("Cannot set the logger factory after creating the sync client");
throw LogicError(ErrorCodes::IllegalOperation,
"Cannot set the logger factory after creating the sync client");

// Create a new logger using the new factory
do_make_logger();
Expand Down Expand Up @@ -723,7 +726,8 @@ void SyncManager::set_session_multiplexing(bool allowed)
return; // Already enabled, we can ignore

if (m_sync_client)
throw std::logic_error("Cannot enable session multiplexing after creating the sync client");
throw LogicError(ErrorCodes::IllegalOperation,
"Cannot enable session multiplexing after creating the sync client");

m_config.multiplex_sessions = allowed;
}
Expand Down
4 changes: 2 additions & 2 deletions src/realm/sync/noinst/client_reset_recovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@ InternDictKey InterningBuffer::get_interned_key(const std::string_view& str) con
return key;
}
}
throw std::runtime_error(
util::format("InterningBuffer::get_interned_key(%1) did not contain the requested key", str));
throw RuntimeError(ErrorCodes::InvalidArgument,
util::format("InterningBuffer::get_interned_key(%1) did not contain the requested key", str));
return {};
}

Expand Down
5 changes: 3 additions & 2 deletions src/realm/sync/noinst/migration_store.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ bool MigrationStore::load_data(bool read_only)
// Load the metadata schema unless it was just created
if (!m_migration_table) {
if (*schema_version != c_schema_version) {
throw std::runtime_error("Invalid schema version for flexible sync migration store metadata");
throw RuntimeError(ErrorCodes::UnsupportedFileFormatVersion,
"Invalid schema version for flexible sync migration store metadata");
}
load_sync_metadata_schema(tr, &internal_tables);
}
Expand Down Expand Up @@ -381,4 +382,4 @@ std::optional<int64_t> MigrationStore::get_sentinel_subscription_set_version()
return m_sentinel_subscription_set_version;
}

} // namespace realm::sync
} // namespace realm::sync
65 changes: 39 additions & 26 deletions src/realm/sync/noinst/sync_metadata_schema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ void create_sync_metadata_schema(const TransactionRef& tr, std::vector<SyncMetad
util::FlatMap<std::string_view, TableRef> found_tables;
for (auto& table : *tables) {
if (tr->has_table(table.name)) {
throw std::runtime_error(
throw RuntimeError(
ErrorCodes::RuntimeError,
util::format("table %1 already existed when creating internal tables for sync", table.name));
}
TableRef table_ref;
Expand All @@ -64,18 +65,18 @@ void create_sync_metadata_schema(const TransactionRef& tr, std::vector<SyncMetad
if (column.data_type == type_LinkList) {
auto target_table_it = found_tables.find(column.target_table);
if (target_table_it == found_tables.end()) {
throw std::runtime_error(
util::format("cannot link to non-existant table %1 from internal sync table %2",
column.target_table, table.name));
throw LogicError(ErrorCodes::InvalidArgument,
util::format("cannot link to non-existant table %1 from internal sync table %2",
column.target_table, table.name));
}
*column.key_out = table_ref->add_column_list(*target_table_it->second, column.name);
}
else if (column.data_type == type_Link) {
auto target_table_it = found_tables.find(column.target_table);
if (target_table_it == found_tables.end()) {
throw std::runtime_error(
util::format("cannot link to non-existant table %1 from internal sync table %2",
column.target_table, table.name));
throw LogicError(ErrorCodes::InvalidArgument,
util::format("cannot link to non-existant table %1 from internal sync table %2",
column.target_table, table.name));
}
*column.key_out = table_ref->add_column(*target_table_it->second, column.name);
}
Expand All @@ -91,63 +92,75 @@ void load_sync_metadata_schema(const TransactionRef& tr, std::vector<SyncMetadat
for (auto& table : *tables) {
auto table_ref = tr->get_table(table.name);
if (!table_ref) {
throw std::runtime_error(util::format("could not find internal sync table %1", table.name));
throw RuntimeError(ErrorCodes::RuntimeError,
util::format("could not find internal sync table %1", table.name));
}

*table.key_out = table_ref->get_key();
if (table.pk_info) {
auto pk_col = table_ref->get_primary_key_column();
if (auto pk_name = table_ref->get_column_name(pk_col); pk_name != table.pk_info->name) {
throw std::runtime_error(util::format(
"primary key name of sync internal table %1 does not match (stored: %2, defined: %3)", table.name,
pk_name, table.pk_info->name));
throw RuntimeError(
ErrorCodes::RuntimeError,
util::format(
"primary key name of sync internal table %1 does not match (stored: %2, defined: %3)",
table.name, pk_name, table.pk_info->name));
}
if (auto pk_type = table_ref->get_column_type(pk_col); pk_type != table.pk_info->data_type) {
throw std::runtime_error(util::format(
"primary key type of sync internal table %1 does not match (stored: %2, defined: %3)", table.name,
pk_type, table.pk_info->data_type));
throw RuntimeError(
ErrorCodes::RuntimeError,
util::format(
"primary key type of sync internal table %1 does not match (stored: %2, defined: %3)",
table.name, pk_type, table.pk_info->data_type));
}
if (auto is_nullable = table_ref->is_nullable(pk_col); is_nullable != table.pk_info->is_optional) {
throw std::runtime_error(util::format(
"primary key nullabilty of sync internal table %1 does not match (stored: %2, defined: %3)",
table.name, is_nullable, table.pk_info->is_optional));
throw RuntimeError(
ErrorCodes::RuntimeError,
util::format(
"primary key nullabilty of sync internal table %1 does not match (stored: %2, defined: %3)",
table.name, is_nullable, table.pk_info->is_optional));
}
*table.pk_info->key_out = pk_col;
}
else if (table.is_embedded && !table_ref->is_embedded()) {
throw std::runtime_error(
util::format("internal sync table %1 should be embedded, but is not", table.name));
throw RuntimeError(ErrorCodes::RuntimeError,
util::format("internal sync table %1 should be embedded, but is not", table.name));
}

if (table.columns.size() + size_t(table.pk_info ? 1 : 0) != table_ref->get_column_count()) {
throw std::runtime_error(
throw RuntimeError(
ErrorCodes::RuntimeError,
util::format("sync internal table %1 has a different number of columns than its schema", table.name));
}

for (auto& col : table.columns) {
auto col_key = table_ref->get_column_key(col.name);
if (!col_key) {
throw std::runtime_error(
throw RuntimeError(
ErrorCodes::RuntimeError,
util::format("column %1 is missing in sync internal table %2", col.name, table.name));
}

auto found_col_type = table_ref->get_column_type(col_key);
if (found_col_type != col.data_type) {
throw std::runtime_error(
throw RuntimeError(
ErrorCodes::RuntimeError,
util::format("column %1 in sync internal table %2 is the wrong type", col.name, table.name));
}

if (col.is_optional != table_ref->is_nullable(col_key)) {
throw std::runtime_error(
throw RuntimeError(
ErrorCodes::RuntimeError,
util::format("column %1 in sync internal table %2 has different nullabilty than in its schema",
col.name, table.name));
}

if (col.data_type == type_LinkList &&
table_ref->get_link_target(col_key)->get_name() != col.target_table) {
throw std::runtime_error(
util::format("column %1 in sync internal table %2 links to the wrong table %3", col.name,
table.name, table_ref->get_link_target(col_key)->get_name()));
throw RuntimeError(ErrorCodes::RuntimeError,
util::format("column %1 in sync internal table %2 links to the wrong table %3",
col.name, table.name,
table_ref->get_link_target(col_key)->get_name()));
}
*col.key_out = col_key;
}
Expand Down
26 changes: 15 additions & 11 deletions src/realm/sync/subscriptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ SubscriptionSet::State state_from_storage(int64_t value)
case SubscriptionStateForStorage::Error:
return SubscriptionSet::State::Error;
default:
throw std::runtime_error(util::format("Invalid state for SubscriptionSet stored on disk: %1", value));
throw RuntimeError(ErrorCodes::InvalidArgument,
util::format("Invalid state for SubscriptionSet stored on disk: %1", value));
}
}

Expand Down Expand Up @@ -206,7 +207,7 @@ std::shared_ptr<const SubscriptionStore> SubscriptionSet::get_flx_subscription_s
if (auto mgr = m_mgr.lock()) {
return mgr;
}
throw std::logic_error("Active SubscriptionSet without a SubscriptionStore");
throw RuntimeError(ErrorCodes::BrokenInvariant, "Active SubscriptionSet without a SubscriptionStore");
}

int64_t SubscriptionSet::version() const
Expand Down Expand Up @@ -420,19 +421,21 @@ void MutableSubscriptionSet::update_state(State new_state, util::Optional<std::s
check_is_mutable();
auto old_state = state();
if (error_str && new_state != State::Error) {
throw std::logic_error("Cannot supply an error message for a subscription set when state is not Error");
throw LogicError(ErrorCodes::InvalidArgument,
"Cannot supply an error message for a subscription set when state is not Error");
}
switch (new_state) {
case State::Uncommitted:
throw std::logic_error("cannot set subscription set state to uncommitted");
throw LogicError(ErrorCodes::InvalidArgument, "cannot set subscription set state to uncommitted");

case State::Error:
if (old_state != State::Bootstrapping && old_state != State::Pending && old_state != State::Uncommitted) {
throw std::logic_error(
"subscription set must be in Bootstrapping or Pending to update state to error");
throw LogicError(ErrorCodes::InvalidArgument,
"subscription set must be in Bootstrapping or Pending to update state to error");
}
if (!error_str) {
throw std::logic_error("Must supply an error message when setting a subscription to the error state");
throw LogicError(ErrorCodes::InvalidArgument,
"Must supply an error message when setting a subscription to the error state");
}

m_state = new_state;
Expand All @@ -450,9 +453,9 @@ void MutableSubscriptionSet::update_state(State new_state, util::Optional<std::s
break;
}
case State::Superseded:
throw std::logic_error("Cannot set a subscription to the superseded state");
throw LogicError(ErrorCodes::InvalidArgument, "Cannot set a subscription to the superseded state");
case State::Pending:
throw std::logic_error("Cannot set subscription set to the pending state");
throw LogicError(ErrorCodes::InvalidArgument, "Cannot set subscription set to the pending state");
}
}

Expand Down Expand Up @@ -554,7 +557,7 @@ void MutableSubscriptionSet::process_notifications()
SubscriptionSet MutableSubscriptionSet::commit()
{
if (m_tr->get_transact_stage() != DB::transact_Writing) {
throw std::logic_error("SubscriptionSet is not in a commitable state");
throw RuntimeError(ErrorCodes::WrongTransactionState, "SubscriptionSet is not in a commitable state");
}
auto mgr = get_flx_subscription_store(); // Throws

Expand Down Expand Up @@ -690,7 +693,8 @@ SubscriptionStore::SubscriptionStore(DBRef db)
}
else {
if (*schema_version != c_flx_schema_version) {
throw std::runtime_error("Invalid schema version for flexible sync metadata");
throw RuntimeError(ErrorCodes::UnsupportedFileFormatVersion,
"Invalid schema version for flexible sync metadata");
}
load_sync_metadata_schema(tr, &internal_tables);
}
Expand Down
2 changes: 1 addition & 1 deletion test/test_sync_subscriptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ TEST(Sync_SubscriptionStoreRefreshSubscriptionSetInvalid)
store.reset();

// Throws since the SubscriptionStore is gone.
CHECK_THROW(latest->refresh(), std::logic_error);
CHECK_THROW(latest->refresh(), RuntimeError);
}

TEST(Sync_SubscriptionStoreInternalSchemaMigration)
Expand Down

0 comments on commit bc48709

Please sign in to comment.