Upgrade to core 1.0.0 and update the file exception translation to match

File::AccessError is now thrown for all file-related exceptions which don't
have more specific types (rather than std::runtime_error), which requires some
changes to how exception messages are built when translating them to get nice
results.

Also add `Realm::write_copy()` which just wraps `Group::write()` with error
translation.
This commit is contained in:
Thomas Goyne 2016-05-23 10:16:24 -07:00
parent 1d34e785e7
commit 840c46f8f3
4 changed files with 79 additions and 37 deletions

View File

@ -69,7 +69,7 @@ std::shared_ptr<Realm> RealmCoordinator::get_realm(Realm::Config config)
m_notifier = std::make_unique<ExternalCommitHelper>(*this);
}
catch (std::system_error const& ex) {
throw RealmFileException(RealmFileException::Kind::AccessError, config.path, ex.code().message());
throw RealmFileException(RealmFileException::Kind::AccessError, config.path, ex.code().message(), "");
}
}
}

View File

@ -68,51 +68,76 @@ Realm::Realm(Config config)
}
}
REALM_NOINLINE static void translate_file_exception(StringData path, bool read_only=false)
{
try {
throw;
}
catch (util::File::PermissionDenied const& ex) {
throw RealmFileException(RealmFileException::Kind::PermissionDenied, ex.get_path(),
"Unable to open a realm at path '" + ex.get_path() +
"'. Please use a path where your app has " + (read_only ? "read" : "read-write") + " permissions.",
ex.what());
}
catch (util::File::Exists const& ex) {
throw RealmFileException(RealmFileException::Kind::Exists, ex.get_path(),
"File at path '" + ex.get_path() + "' already exists.",
ex.what());
}
catch (util::File::NotFound const& ex) {
throw RealmFileException(RealmFileException::Kind::NotFound, ex.get_path(),
"Directory at path '" + ex.get_path() + "' does not exist.",
ex.what());
}
catch (util::File::AccessError const& ex) {
// Errors for `open()` include the path, but other errors don't. We
// don't want two copies of the path in the error, so strip it out if it
// appears, and then include it in our prefix.
std::string underlying = ex.what();
auto pos = underlying.find(ex.get_path());
if (pos != std::string::npos && pos > 0) {
// One extra char at each end for the quotes
underlying.replace(pos - 1, ex.get_path().size() + 2, "");
}
throw RealmFileException(RealmFileException::Kind::AccessError, ex.get_path(),
"Unable to open a realm at path '" + ex.get_path() + "': " + underlying,
ex.what());
}
catch (IncompatibleLockFile const& ex) {
throw RealmFileException(RealmFileException::Kind::IncompatibleLockFile, path,
"Realm file is currently open in another process "
"which cannot share access with this process. All processes sharing a single file must be the same architecture.",
ex.what());
}
catch (FileFormatUpgradeRequired const& ex) {
throw RealmFileException(RealmFileException::Kind::FormatUpgradeRequired, path,
"The Realm file format must be allowed to be upgraded "
"in order to proceed.",
ex.what());
}
}
void Realm::open_with_config(const Config& config,
std::unique_ptr<Replication>& history,
std::unique_ptr<SharedGroup>& shared_group,
std::unique_ptr<Group>& read_only_group)
{
if (config.encryption_key.data() && config.encryption_key.size() != 64) {
throw InvalidEncryptionKeyException();
}
try {
if (config.read_only) {
read_only_group = std::make_unique<Group>(config.path, config.encryption_key.data(), Group::mode_ReadOnly);
}
else {
if (config.encryption_key.data() && config.encryption_key.size() != 64) {
throw InvalidEncryptionKeyException();
}
history = realm::make_client_history(config.path, config.encryption_key.data());
SharedGroup::DurabilityLevel durability = config.in_memory ? SharedGroup::durability_MemOnly :
SharedGroup::durability_Full;
shared_group = std::make_unique<SharedGroup>(*history, durability, config.encryption_key.data(), !config.disable_format_upgrade);
}
}
catch (util::File::PermissionDenied const& ex) {
throw RealmFileException(RealmFileException::Kind::PermissionDenied, ex.get_path(),
"Unable to open a realm at path '" + ex.get_path() +
"'. Please use a path where your app has " + (config.read_only ? "read" : "read-write") + " permissions.");
}
catch (util::File::Exists const& ex) {
throw RealmFileException(RealmFileException::Kind::Exists, ex.get_path(),
"File at path '" + ex.get_path() + "' already exists.");
}
catch (util::File::NotFound const& ex) {
throw RealmFileException(RealmFileException::Kind::NotFound, ex.get_path(),
"File at path '" + ex.get_path() + "' does not exist.");
}
catch (util::File::AccessError const& ex) {
throw RealmFileException(RealmFileException::Kind::AccessError, ex.get_path(),
"Unable to open a realm at path '" + ex.get_path() + "'");
}
catch (IncompatibleLockFile const& ex) {
throw RealmFileException(RealmFileException::Kind::IncompatibleLockFile, config.path,
"Realm file is currently open in another process "
"which cannot share access with this process. All processes sharing a single file must be the same architecture.");
}
catch (FileFormatUpgradeRequired const& ex) {
throw RealmFileException(RealmFileException::Kind::FormatUpgradeRequired, config.path,
"The Realm file format must be allowed to be upgraded "
"in order to proceed.");
catch (...) {
translate_file_exception(config.path, config.read_only);
}
}
@ -138,7 +163,7 @@ void Realm::init(std::shared_ptr<RealmCoordinator> coordinator)
if (target_schema) {
if (m_config.read_only) {
if (m_config.schema_version == ObjectStore::NotVersioned) {
throw UnitializedRealmException("Can't open an un-initialized Realm without a Schema");
throw UninitializedRealmException("Can't open an un-initialized Realm without a Schema");
}
target_schema->validate();
ObjectStore::verify_schema(*m_config.schema, *target_schema, true);
@ -370,6 +395,18 @@ bool Realm::compact()
return m_shared_group->compact();
}
void Realm::write_copy(StringData path, BinaryData key)
{
REALM_ASSERT(!key.data() || key.size() == 64);
verify_thread();
try {
read_group()->write(path, key.data());
}
catch (...) {
translate_file_exception(path);
}
}
void Realm::notify()
{
verify_thread();

View File

@ -19,19 +19,20 @@
#ifndef REALM_REALM_HPP
#define REALM_REALM_HPP
#include "schema.hpp"
#include <memory>
#include <string>
#include <thread>
#include <vector>
namespace realm {
class BinaryData;
class BindingContext;
class Group;
class Realm;
class Replication;
class Schema;
class SharedGroup;
class StringData;
typedef std::shared_ptr<Realm> SharedRealm;
typedef std::weak_ptr<Realm> WeakRealm;
@ -121,6 +122,7 @@ namespace realm {
void invalidate();
bool compact();
void write_copy(StringData path, BinaryData encryption_key);
std::thread::id thread_id() const { return m_thread_id; }
void verify_thread() const;
@ -199,14 +201,16 @@ namespace realm {
/** Thrown if the file needs to be upgraded to a new format, but upgrades have been explicitly disabled. */
FormatUpgradeRequired,
};
RealmFileException(Kind kind, std::string path, std::string message) :
std::runtime_error(std::move(message)), m_kind(kind), m_path(std::move(path)) {}
RealmFileException(Kind kind, std::string path, std::string message, std::string underlying) :
std::runtime_error(std::move(message)), m_kind(kind), m_path(std::move(path)), m_underlying(std::move(underlying)) {}
Kind kind() const { return m_kind; }
const std::string& path() const { return m_path; }
const std::string& underlying() const { return m_underlying; }
private:
Kind m_kind;
std::string m_path;
std::string m_underlying;
};
class MismatchedConfigException : public std::runtime_error {
@ -224,9 +228,9 @@ namespace realm {
IncorrectThreadException() : std::runtime_error("Realm accessed from incorrect thread.") {}
};
class UnitializedRealmException : public std::runtime_error {
class UninitializedRealmException : public std::runtime_error {
public:
UnitializedRealmException(std::string message) : std::runtime_error(message) {}
UninitializedRealmException(std::string message) : std::runtime_error(message) {}
};
class InvalidEncryptionKeyException : public std::runtime_error {

View File

@ -3,6 +3,7 @@
#include "impl/realm_coordinator.hpp"
#include <realm/disable_sync_to_disk.hpp>
#include <realm/string_data.hpp>
#include <cstdlib>
#include <unistd.h>