//////////////////////////////////////////////////////////////////////////// // // Copyright 2015 Realm Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////// #ifndef REALM_REALM_HPP #define REALM_REALM_HPP #include "schema.hpp" #include #include #include #include #include #include #include namespace realm { class BindingContext; class ClientHistory; class Group; class Realm; class RealmDelegate; class SharedGroup; typedef std::shared_ptr SharedRealm; typedef std::weak_ptr WeakRealm; namespace _impl { class AsyncQuery; class RealmCoordinator; } class Realm : public std::enable_shared_from_this { public: typedef std::function MigrationFunction; struct Config { std::string path; // User-supplied encryption key. Must be either empty or 64 bytes. std::vector encryption_key; // Optional schema for the file. If nullptr, the existing schema // from the file opened will be used. If present, the file will be // migrated to the schema if needed. std::unique_ptr schema; uint64_t schema_version; MigrationFunction migration_function; bool read_only = false; bool in_memory = false; // The following are intended for internal/testing purposes and // should not be publically exposed in binding APIs // If false, always return a new Realm instance, and don't return // that Realm instance for other requests for a cached Realm. Useful // for dynamic Realms and for tests that need multiple instances on // one thread bool cache = true; // Throw an exception rather than automatically upgrading the file // format. Used by the browser to warn the user that it'll modify // the file. bool disable_format_upgrade = false; // Disable the background worker thread for producing change // notifications. Useful for tests for those notifications so that // everything can be done deterministically on one thread, and // speeds up tests that don't need notifications. bool automatic_change_notifications = true; Config(); Config(Config&&); Config(const Config& c); ~Config(); Config& operator=(Config const&); Config& operator=(Config&&) = default; }; // Get a cached Realm or create a new one if no cached copies exists // Caching is done by path - mismatches for in_memory and read_only // Config properties will raise an exception // If schema/schema_version is specified, update_schema is called // automatically on the realm and a migration is performed. If not // specified, the schema version and schema are dynamically read from // the the existing Realm. static SharedRealm get_shared_realm(Config config); // Updates a Realm to a given target schema/version creating tables and // updating indexes as necessary. Uses the existing migration function // on the Config, and the resulting Schema and version with updated // column mappings are set on the realms config upon success. void update_schema(std::unique_ptr schema, uint64_t version); static uint64_t get_schema_version(Config const& config); const Config &config() const { return m_config; } void begin_transaction(); void commit_transaction(); void cancel_transaction(); bool is_in_transaction() const { return m_in_transaction; } bool is_in_read_transaction() const { return !!m_group; } bool refresh(); void set_auto_refresh(bool auto_refresh) { m_auto_refresh = auto_refresh; } bool auto_refresh() const { return m_auto_refresh; } void notify(); void invalidate(); bool compact(); std::thread::id thread_id() const { return m_thread_id; } void verify_thread() const; void verify_in_write() const; bool can_deliver_notifications() const noexcept; // Close this Realm and remove it from the cache. Continuing to use a // Realm after closing it will produce undefined behavior. void close(); ~Realm(); void init(std::shared_ptr<_impl::RealmCoordinator> coordinator); Realm(Config config); // Expose some internal functionality to other parts of the ObjectStore // without making it public to everyone class Internal { friend class _impl::AsyncQuery; friend class _impl::RealmCoordinator; // AsyncQuery needs access to the SharedGroup to be able to call the // handover functions, which are not very wrappable static SharedGroup& get_shared_group(Realm& realm) { return *realm.m_shared_group; } static ClientHistory& get_history(Realm& realm) { return *realm.m_history; } // AsyncQuery needs to be able to access the owning coordinator to // wake up the worker thread when a callback is added, and // coordinators need to be able to get themselves from a Realm static _impl::RealmCoordinator& get_coordinator(Realm& realm) { return *realm.m_coordinator; } }; static void open_with_config(const Config& config, std::unique_ptr& history, std::unique_ptr& shared_group, std::unique_ptr& read_only_group); private: Config m_config; std::thread::id m_thread_id = std::this_thread::get_id(); bool m_in_transaction = false; bool m_auto_refresh = true; std::unique_ptr m_history; std::unique_ptr m_shared_group; std::unique_ptr m_read_only_group; Group *m_group = nullptr; std::shared_ptr<_impl::RealmCoordinator> m_coordinator; public: std::unique_ptr m_binding_context; // FIXME private Group *read_group(); }; class RealmFileException : public std::runtime_error { public: enum class Kind { /** Thrown for any I/O related exception scenarios when a realm is opened. */ AccessError, /** Thrown if the user does not have permission to open or create the specified file in the specified access mode when the realm is opened. */ PermissionDenied, /** Thrown if create_Always was specified and the file did already exist when the realm is opened. */ Exists, /** Thrown if no_create was specified and the file was not found when the realm is opened. */ NotFound, /** Thrown if the database file is currently open in another process which cannot share with the current process due to an architecture mismatch. */ IncompatibleLockFile, /** 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)) {} Kind kind() const { return m_kind; } const std::string& path() const { return m_path; } private: Kind m_kind; std::string m_path; }; class MismatchedConfigException : public std::runtime_error { public: MismatchedConfigException(std::string message) : std::runtime_error(message) {} }; class InvalidTransactionException : public std::runtime_error { public: InvalidTransactionException(std::string message) : std::runtime_error(message) {} }; class IncorrectThreadException : public std::runtime_error { public: IncorrectThreadException() : std::runtime_error("Realm accessed from incorrect thread.") {} }; class UnitializedRealmException : public std::runtime_error { public: UnitializedRealmException(std::string message) : std::runtime_error(message) {} }; class InvalidEncryptionKeyException : public std::runtime_error { public: InvalidEncryptionKeyException() : std::runtime_error("Encryption key must be 64 bytes.") {} }; } #endif /* defined(REALM_REALM_HPP) */