Commit 3d4d3435 authored by Eyad Hasan's avatar Eyad Hasan
Browse files

updated Realm from 2.5.1 to 2.10.0

This should hopefully fix some issues that we where having earlier
parent d372f347
PODS:
- Realm (2.5.1):
- Realm/Headers (= 2.5.1)
- Realm/Headers (2.5.1)
- RealmSwift (2.5.1):
- Realm (= 2.5.1)
- Realm (2.10.0):
- Realm/Headers (= 2.10.0)
- Realm/Headers (2.10.0)
- RealmSwift (2.10.0):
- Realm (= 2.10.0)
DEPENDENCIES:
- RealmSwift
SPEC CHECKSUMS:
Realm: 32f86104d37c8521f864d4274050b38ba6190733
RealmSwift: f719e7511c902b8908593e8f143f59e47931bdb6
Realm: 98b3a25643cf6b3e07d2b99fb43fe0eb9c801dec
RealmSwift: 34073ad3a31232bbaf7c0db898c037940284cba2
PODFILE CHECKSUM: b8c4ac0f68e1021098d7016accb14cf642240f47
......
PODS:
- Realm (2.5.1):
- Realm/Headers (= 2.5.1)
- Realm/Headers (2.5.1)
- RealmSwift (2.5.1):
- Realm (= 2.5.1)
- Realm (2.10.0):
- Realm/Headers (= 2.10.0)
- Realm/Headers (2.10.0)
- RealmSwift (2.10.0):
- Realm (= 2.10.0)
DEPENDENCIES:
- RealmSwift
SPEC CHECKSUMS:
Realm: 32f86104d37c8521f864d4274050b38ba6190733
RealmSwift: f719e7511c902b8908593e8f143f59e47931bdb6
Realm: 98b3a25643cf6b3e07d2b99fb43fe0eb9c801dec
RealmSwift: 34073ad3a31232bbaf7c0db898c037940284cba2
PODFILE CHECKSUM: b8c4ac0f68e1021098d7016accb14cf642240f47
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -4,7 +4,7 @@ TABLE OF CONTENTS
2. Realm Components
3. Export Compliance
-------------------------------------------------------------------------------
1. -------------------------------------------------------------------------------
Apache License
Version 2.0, January 2004
......@@ -181,17 +181,19 @@ TABLE OF CONTENTS
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
2. -------------------------------------------------------------------------------
REALM COMPONENTS
This software contains components with separate copyright and license terms.
Your use of these components is subject to the terms and conditions of the
following licenses.
For the Realm Core component
For the Realm Platform Extensions component
Realm Core Binary License
Realm Platform Extensions License
Copyright (c) 2011-2016 Realm Inc All rights reserved
Copyright (c) 2011-2017 Realm Inc All rights reserved
Redistribution and use in binary form, with or without modification, is
permitted provided that the following conditions are met:
......@@ -222,6 +224,8 @@ For the Realm Core component
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
3. -------------------------------------------------------------------------------
EXPORT COMPLIANCE
You understand that the Software may contain cryptographic functions that may be
......
......@@ -7,7 +7,7 @@ This repository holds the source code for the iOS, macOS, tvOS & watchOS version
* **Mobile-first:** Realm is the first database built from the ground up to run directly inside phones, tablets and wearables.
* **Simple:** Data is directly [exposed as objects](https://realm.io/docs/objc/latest/#models) and [queryable by code](https://realm.io/docs/objc/latest/#queries), removing the need for ORM's riddled with performance & maintenance issues. Most of our users pick it up intuitively, getting simple apps up & running in minutes.
* **Modern:** Realm supports relationships, generics, vectorization and even Swift.
* **Modern:** Realm supports relationships, generics, vectorization and Swift.
* **Fast:** Realm is faster than even raw SQLite on common operations, while maintaining an extremely rich feature set.
## Getting Started
......@@ -31,7 +31,7 @@ The API reference is located at [realm.io/docs/swift/latest/api](https://realm.i
- **Need help with your code?**: Look for previous questions on the [#realm tag](https://stackoverflow.com/questions/tagged/realm?sort=newest) — or [ask a new question](https://stackoverflow.com/questions/ask?tags=realm). We actively monitor & answer questions on SO!
- **Have a bug to report?** [Open an issue](https://github.com/realm/realm-cocoa/issues/new). If possible, include the version of Realm, a full log, the Realm file, and a project that shows the issue.
- **Have a feature request?** [Open an issue](https://github.com/realm/realm-cocoa/issues/new). Tell us what the feature should do, and why you want the feature.
- Sign up for our [**Community Newsletter**](https://www2.realm.io/l/210132/2016-12-05/fy9m) to get regular tips, learn about other use-cases and get alerted of blogposts and tutorials about Realm.
- Sign up for our [**Community Newsletter**](https://realm.io/realm-news-subscribe) to get regular tips, learn about other use-cases and get alerted of blogposts and tutorials about Realm.
## Building Realm
......@@ -67,7 +67,7 @@ not eligible to receive the product under U.S. law.**
## Feedback
**_If you use Realm and are happy with it, all we ask is that you please consider sending out a tweet mentioning [@realm](https://twitter.com/realm) or email [help@realm.io](mailto:help@realm.io) to share your thoughts!_**
**_If you use Realm and are happy with it, all we ask is that you please consider sending out a tweet mentioning [@realm](https://twitter.com/realm) to share your thoughts!_**
**_And if you don't like it, please let us know what you would like improved, so we can fix it!_**
......
......@@ -29,6 +29,13 @@
return nil;
}
- (void(^)(void))rlmSync_deleteRealmBlock {
if (self.domain == RLMSyncErrorDomain && self.code == RLMSyncErrorPermissionDeniedError) {
return self.userInfo[kRLMSyncInitiateDeleteRealmBlockKey];
}
return nil;
}
- (NSString *)rlmSync_clientResetBackedUpRealmPath {
if (self.domain == RLMSyncErrorDomain && self.code == RLMSyncErrorClientResetError) {
return self.userInfo[kRLMSyncPathOfRealmBackupCopyKey];
......
......@@ -110,6 +110,6 @@ std::vector<char> metadata_realm_encryption_key()
auto key_bytes = reinterpret_cast<const char *>(CFDataGetBytePtr(key_data.get()));
return std::vector<char>(key_bytes, key_bytes + key_size);
}
}
}
......@@ -31,6 +31,9 @@ std::function<bool (size_t)>
CollectionNotifier::get_modification_checker(TransactionChangeInfo const& info,
Table const& root_table)
{
if (info.schema_changed)
set_table(root_table);
// First check if any of the tables accessible from the root table were
// actually modified. This can be false if there were only insertions, or
// deletions which were not linked to by any row in the linking table
......@@ -90,9 +93,13 @@ bool DeepChangeChecker::check_outgoing_links(size_t table_ndx,
// Check if we're already checking if the destination of the link is
// modified, and if not add it to the stack
auto already_checking = [&](size_t col) {
for (auto p = m_current_path.begin(); p < m_current_path.begin() + depth; ++p) {
if (p->table == table_ndx && p->row == row_ndx && p->col == col)
return true;
auto end = m_current_path.begin() + depth;
auto match = std::find_if(m_current_path.begin(), end, [&](auto& p) {
return p.table == table_ndx && p.row == row_ndx && p.col == col;
});
if (match != end) {
for (; match < end; ++match) match->depth_exceeded = true;
return true;
}
m_current_path[depth] = {table_ndx, row_ndx, col, false};
return false;
......@@ -127,7 +134,7 @@ bool DeepChangeChecker::check_row(Table const& table, size_t idx, size_t depth)
if (depth >= m_current_path.size()) {
// Don't mark any of the intermediate rows checked along the path as
// not modified, as a search starting from them might hit a modification
for (size_t i = 1; i < m_current_path.size(); ++i)
for (size_t i = 0; i < m_current_path.size(); ++i)
m_current_path[i].depth_exceeded = true;
return false;
}
......
......@@ -113,15 +113,21 @@ void RealmCoordinator::set_config(const Realm::Config& config)
{
if (config.encryption_key.data() && config.encryption_key.size() != 64)
throw InvalidEncryptionKeyException();
if (config.schema_mode == SchemaMode::ReadOnly && config.sync_config)
throw std::logic_error("Synchronized Realms cannot be opened in read-only mode");
if (config.schema_mode == SchemaMode::Immutable && config.sync_config)
throw std::logic_error("Synchronized Realms cannot be opened in immutable mode");
if (config.schema_mode == SchemaMode::Additive && config.migration_function)
throw std::logic_error("Realms opened in Additive-only schema mode do not use a migration function");
if (config.schema_mode == SchemaMode::ReadOnly && config.migration_function)
if (config.schema_mode == SchemaMode::Immutable && config.migration_function)
throw std::logic_error("Realms opened in immutable mode do not use a migration function");
if (config.schema_mode == SchemaMode::ReadOnlyAlternative && config.migration_function)
throw std::logic_error("Realms opened in read-only mode do not use a migration function");
if (config.schema_mode == SchemaMode::Immutable && config.initialization_function)
throw std::logic_error("Realms opened in immutable mode do not use an initialization function");
if (config.schema_mode == SchemaMode::ReadOnlyAlternative && config.initialization_function)
throw std::logic_error("Realms opened in read-only mode do not use an initialization function");
if (config.schema && config.schema_version == ObjectStore::NotVersioned)
throw std::logic_error("A schema version must be specified when the schema is specified");
if (!config.realm_data.is_null() && (!config.read_only() || !config.in_memory))
if (!config.realm_data.is_null() && (!config.immutable() || !config.in_memory))
throw std::logic_error("In-memory realms initialized from memory buffers can only be opened in read-only mode");
if (!config.realm_data.is_null() && !config.path.empty())
throw std::logic_error("Specifying both memory buffer and path is invalid");
......@@ -136,7 +142,7 @@ void RealmCoordinator::set_config(const Realm::Config& config)
m_config = config;
}
else {
if (m_config.read_only() != config.read_only()) {
if (m_config.immutable() != config.immutable()) {
throw MismatchedConfigException("Realm at path '%1' already opened with different read permissions.", config.path);
}
if (m_config.in_memory != config.in_memory) {
......@@ -195,6 +201,7 @@ std::shared_ptr<Realm> RealmCoordinator::get_realm(Realm::Config config)
auto schema = std::move(config.schema);
auto migration_function = std::move(config.migration_function);
auto initialization_function = std::move(config.initialization_function);
config.schema = {};
if (config.cache) {
......@@ -223,7 +230,7 @@ std::shared_ptr<Realm> RealmCoordinator::get_realm(Realm::Config config)
if (!realm) {
realm = Realm::make_shared_realm(std::move(config), shared_from_this());
if (!config.read_only() && !m_notifier && config.automatic_change_notifications) {
if (!config.immutable() && !m_notifier && config.automatic_change_notifications) {
try {
m_notifier = std::make_unique<ExternalCommitHelper>(*this);
}
......@@ -236,7 +243,8 @@ std::shared_ptr<Realm> RealmCoordinator::get_realm(Realm::Config config)
if (schema) {
lock.unlock();
realm->update_schema(std::move(*schema), config.schema_version, std::move(migration_function));
realm->update_schema(std::move(*schema), config.schema_version, std::move(migration_function),
std::move(initialization_function));
}
return realm;
......@@ -385,7 +393,7 @@ void RealmCoordinator::wake_up_notifier_worker()
void RealmCoordinator::commit_write(Realm& realm)
{
REALM_ASSERT(!m_config.read_only());
REALM_ASSERT(!m_config.immutable());
REALM_ASSERT(realm.is_in_transaction());
{
......@@ -774,8 +782,21 @@ void RealmCoordinator::advance_to_ready(Realm& realm)
auto& sg = Realm::Internal::get_shared_group(realm);
if (notifiers) {
auto version = notifiers.version();
if (version && *version <= sg->get_version_of_current_transaction())
return;
if (version) {
auto current_version = sg->get_version_of_current_transaction();
// Notifications are out of date, so just discard
// This should only happen if begin_read() was used to change the
// read version outside of our control
if (*version < current_version)
return;
// While there is a newer version, notifications are for the current
// version so just deliver them without advancing
if (*version == current_version) {
notifiers.deliver(*sg);
notifiers.after_advance();
return;
}
}
}
transaction::advance(sg, realm.m_binding_context.get(), notifiers);
......
......@@ -29,8 +29,7 @@ ResultsNotifier::ResultsNotifier(Results& target)
Query q = target.get_query();
set_table(*q.get_table());
m_query_handover = Realm::Internal::get_shared_group(*get_realm())->export_for_handover(q, MutableSourcePayload::Move);
SortDescriptor::generate_patch(target.get_sort(), m_sort_handover);
SortDescriptor::generate_patch(target.get_distinct(), m_distinct_handover);
DescriptorOrdering::generate_patch(target.get_descriptor_ordering(), m_ordering_handover);
}
void ResultsNotifier::target_results_moved(Results& old_target, Results& new_target)
......@@ -116,16 +115,16 @@ void ResultsNotifier::calculate_changes()
if (changes) {
auto const& moves = changes->moves;
for (auto& idx : m_previous_rows) {
auto it = lower_bound(begin(moves), end(moves), idx,
[](auto const& a, auto b) { return a.from < b; });
if (it != moves.end() && it->from == idx)
idx = it->to;
else if (changes->deletions.contains(idx))
idx = npos;
if (changes->deletions.contains(idx)) {
// check if this deletion was actually a move
auto it = lower_bound(begin(moves), end(moves), idx,
[](auto const& a, auto b) { return a.from < b; });
idx = it != moves.end() && it->from == idx ? it->to : npos;
}
else
REALM_ASSERT_DEBUG(!changes->insertions.contains(idx));
idx = changes->insertions.shift(changes->deletions.unshift(idx));
}
if (m_target_is_in_table_order && !m_sort)
if (m_target_is_in_table_order && !m_descriptor_ordering.will_apply_sort())
move_candidates = changes->insertions;
}
......@@ -149,12 +148,15 @@ void ResultsNotifier::run()
m_query->sync_view_if_needed();
m_tv = m_query->find_all();
if (m_sort) {
m_tv.sort(m_sort);
}
if (m_distinct) {
m_tv.distinct(m_distinct);
}
#if REALM_HAVE_COMPOSABLE_DISTINCT
m_tv.apply_descriptor_ordering(m_descriptor_ordering);
#else
if (m_descriptor_ordering.sort)
m_tv.sort(m_descriptor_ordering.sort);
if (m_descriptor_ordering.distinct)
m_tv.distinct(m_descriptor_ordering.distinct);
#endif
m_last_seen_version = m_tv.sync_if_needed();
calculate_changes();
......@@ -218,8 +220,7 @@ void ResultsNotifier::do_attach_to(SharedGroup& sg)
{
REALM_ASSERT(m_query_handover);
m_query = sg.import_from_handover(std::move(m_query_handover));
m_sort = SortDescriptor::create_from_and_consume_patch(m_sort_handover, *m_query->get_table());
m_distinct = SortDescriptor::create_from_and_consume_patch(m_distinct_handover, *m_query->get_table());
m_descriptor_ordering = DescriptorOrdering::create_from_and_consume_patch(m_ordering_handover, *m_query->get_table());
}
void ResultsNotifier::do_detach_from(SharedGroup& sg)
......@@ -227,8 +228,7 @@ void ResultsNotifier::do_detach_from(SharedGroup& sg)
REALM_ASSERT(m_query);
REALM_ASSERT(!m_tv.is_attached());
SortDescriptor::generate_patch(m_sort, m_sort_handover);
SortDescriptor::generate_patch(m_distinct, m_distinct_handover);
DescriptorOrdering::generate_patch(m_descriptor_ordering, m_ordering_handover);
m_query_handover = sg.export_for_handover(*m_query, MutableSourcePayload::Move);
m_query = nullptr;
}
......@@ -226,6 +226,8 @@ struct MarkDirtyMixin {
bool set_int_unique(size_t, size_t, size_t, int_fast64_t) { return true; }
bool set_string_unique(size_t, size_t, size_t, StringData) { return true; }
bool add_row_with_key(size_t, size_t, size_t, int64_t) { return true; }
};
class TransactLogValidationMixin {
......@@ -243,11 +245,6 @@ protected:
size_t current_table() const noexcept { return m_current_table; }
public:
bool select_descriptor(int levels, const size_t*)
{
// subtables not supported
return levels == 0;
}
bool select_table(size_t group_level_ndx, int, const size_t*) noexcept
{
......@@ -277,11 +274,12 @@ public:
// Non-schema changes are all allowed
void parse_complete() { }
bool select_descriptor(int, const size_t*) { return true; }
bool select_link_list(size_t, size_t, size_t) { return true; }
bool insert_empty_rows(size_t, size_t, size_t, bool) { return true; }
bool erase_rows(size_t, size_t, size_t, bool) { return true; }
bool swap_rows(size_t, size_t) { return true; }
bool clear_table() noexcept { return true; }
bool clear_table(size_t=0) noexcept { return true; }
bool link_list_set(size_t, size_t, size_t) { return true; }
bool link_list_insert(size_t, size_t, size_t) { return true; }
bool link_list_erase(size_t, size_t) { return true; }
......@@ -362,81 +360,103 @@ void adjust_ge(std::vector<size_t>& values, size_t i)
// Extends TransactLogValidator to track changes made to LinkViews
class TransactLogObserver : public TransactLogValidationMixin, public MarkDirtyMixin<TransactLogObserver> {
_impl::TransactionChangeInfo& m_info;
_impl::CollectionChangeBuilder* m_active = nullptr;
_impl::CollectionChangeBuilder* m_active_list = nullptr;
_impl::CollectionChangeBuilder* m_active_table = nullptr;
_impl::CollectionChangeBuilder* m_active_descriptor = nullptr;
_impl::CollectionChangeBuilder* get_change()
{
auto tbl_ndx = current_table();
if (!m_info.track_all && (tbl_ndx >= m_info.table_modifications_needed.size() || !m_info.table_modifications_needed[tbl_ndx]))
return nullptr;
if (m_info.tables.size() <= tbl_ndx) {
m_info.tables.resize(std::max(m_info.tables.size() * 2, tbl_ndx + 1));
}
return &m_info.tables[tbl_ndx];
}
bool m_need_move_info = false;
bool m_is_top_level_table = true;
bool need_move_info() const
_impl::CollectionChangeBuilder* find_list(size_t tbl, size_t col, size_t row)
{
auto tbl_ndx = current_table();
return m_info.track_all || (tbl_ndx < m_info.table_moves_needed.size() && m_info.table_moves_needed[tbl_ndx]);
// When there are multiple source versions there could be multiple
// change objects for a single LinkView, in which case we need to use
// the last one
for (auto it = m_info.lists.rbegin(), end = m_info.lists.rend(); it != end; ++it) {
if (it->table_ndx == tbl && it->row_ndx == row && it->col_ndx == col)
return it->changes;
}
return nullptr;
}
public:
TransactLogObserver(_impl::TransactionChangeInfo& info)
: m_info(info) { }
void mark_dirty(size_t row, size_t col)
{
if (auto change = get_change())
change->modify(row, col);
if (m_active_table)
m_active_table->modify(row, col);
}
void parse_complete()
{
for (auto& table : m_info.tables) {
for (auto& table : m_info.tables)
table.parse_complete();
}
for (auto& list : m_info.lists) {
for (auto& list : m_info.lists)
list.changes->clean_up_stale_moves();
}
bool select_descriptor(int levels, const size_t*) noexcept
{
if (levels == 0) // schema of selected table is being modified
m_active_descriptor = m_active_table;
else // schema of subtable is being modified; currently don't need to track this
m_active_descriptor = nullptr;
return true;
}
bool select_table(size_t group_level_ndx, int len, size_t const* path) noexcept
{
TransactLogValidationMixin::select_table(group_level_ndx, len, path);
m_active_table = nullptr;
m_active_descriptor = nullptr;
m_is_top_level_table = true;
if (len > 0) {
// ignore changes to subtables for now
m_is_top_level_table = false;
return true;
}
auto tbl_ndx = current_table();
if (!m_info.track_all && (tbl_ndx >= m_info.table_modifications_needed.size() || !m_info.table_modifications_needed[tbl_ndx]))
return true;
m_need_move_info = m_info.track_all || (tbl_ndx < m_info.table_moves_needed.size() &&
m_info.table_moves_needed[tbl_ndx]);
if (m_info.tables.size() <= tbl_ndx)
m_info.tables.resize(std::max(m_info.tables.size() * 2, tbl_ndx + 1));
m_active_table = &m_info.tables[tbl_ndx];
return true;
}
bool select_link_list(size_t col, size_t row, size_t)
{
mark_dirty(row, col);
m_active = nullptr;
// When there are multiple source versions there could be multiple
// change objects for a single LinkView, in which case we need to use
// the last one
for (auto it = m_info.lists.rbegin(), end = m_info.lists.rend(); it != end; ++it) {
if (it->table_ndx == current_table() && it->row_ndx == row && it->col_ndx == col) {
m_active = it->changes;
break;
}
}
m_active_list = find_list(current_table(), col, row);
return true;
}
bool link_list_set(size_t index, size_t, size_t)
{
if (m_active)
m_active->modify(index);
if (m_active_list)
m_active_list->modify(index);
return true;
}
bool link_list_insert(size_t index, size_t, size_t)
{
if (m_active)
m_active->insert(index);
if (m_active_list)
m_active_list->insert(index);
return true;
}
bool link_list_erase(size_t index, size_t)
{
if (m_active)
m_active->erase(index);
if (m_active_list)
m_active_list->erase(index);
return true;
}
......@@ -454,22 +474,24 @@ public:
bool link_list_clear(size_t old_size)
{
if (m_active)
m_active->clear(old_size);
if (m_active_list)
m_active_list->clear(old_size);
return true;
}
bool link_list_move(size_t from, size_t to)
{
if (m_active)
m_active->move(from, to);
if (m_active_list)
m_active_list->move(from, to);
return true;
}
bool insert_empty_rows(size_t row_ndx, size_t num_rows_to_insert, size_t, bool)
{
if (auto change = get_change())
change->insert(row_ndx, num_rows_to_insert, need_move_info());
if (m_active_table)
m_active_table->insert(row_ndx, num_rows_to_insert, m_need_move_info);
if (!m_is_top_level_table)
return true;
for (auto& list : m_info.lists) {
if (list.table_ndx == current_table() && list.row_ndx >= row_ndx)
list.row_ndx += num_rows_to_insert;
......@@ -477,16 +499,26 @@ public:
return true;
}
bool add_row_with_key(size_t row_ndx, size_t prior_num_rows, size_t, int64_t)
{
insert_empty_rows(row_ndx, 1, prior_num_rows, false);
return true;
}
bool erase_rows(size_t row_ndx, size_t, size_t prior_num_rows, bool unordered)
{
if (!unordered) {
if (auto change = get_change())
change->deletions.add(row_ndx);
if (m_active_table)
m_active_table->deletions.add(row_ndx);
return true;
}
REALM_ASSERT(unordered);
size_t last_row = prior_num_rows - 1;
if (m_active_table)
m_active_table->move_over(row_ndx, last_row, m_need_move_info);