Skip to content

Commit 1792e59

Browse files
committed
Consolidate collection updating logic somewhat
1 parent 0e94a90 commit 1792e59

File tree

11 files changed

+154
-226
lines changed

11 files changed

+154
-226
lines changed

src/realm/collection.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,4 +237,25 @@ void Collection::get_any(QueryCtrlBlock& ctrl, Mixed val, size_t index)
237237
}
238238
}
239239

240+
UpdateStatus CollectionBase::do_init_from_parent(BPlusTreeBase* tree, ref_type ref, bool allow_create)
241+
{
242+
if (ref) {
243+
tree->init_from_ref(ref);
244+
}
245+
else {
246+
if (tree->init_from_parent()) {
247+
// All is well
248+
return UpdateStatus::Updated;
249+
}
250+
if (!allow_create) {
251+
tree->detach();
252+
return UpdateStatus::Detached;
253+
}
254+
// The ref in the column was NULL, create the tree in place.
255+
tree->create();
256+
REALM_ASSERT(tree->is_attached());
257+
}
258+
return UpdateStatus::Updated;
259+
}
260+
240261
} // namespace realm

src/realm/collection.hpp

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -53,18 +53,18 @@ class DummyParent : public CollectionParent {
5353
{
5454
return m_obj;
5555
}
56+
uint32_t parent_version() const noexcept final
57+
{
58+
return 0;
59+
}
5660

5761
protected:
5862
Obj m_obj;
5963
ref_type m_ref;
60-
UpdateStatus update_if_needed_with_status() const final
64+
UpdateStatus update_if_needed() const final
6165
{
6266
return UpdateStatus::Updated;
6367
}
64-
bool update_if_needed() const final
65-
{
66-
return true;
67-
}
6868
ref_type get_collection_ref(Index, CollectionType) const final
6969
{
7070
return m_ref;
@@ -255,6 +255,7 @@ class CollectionBase : public Collection {
255255
CollectionBase& operator=(CollectionBase&&) noexcept = default;
256256

257257
void validate_index(const char* msg, size_t index, size_t size) const;
258+
static UpdateStatus do_init_from_parent(BPlusTreeBase* tree, ref_type ref, bool allow_create);
258259
};
259260

260261
inline std::string_view collection_type_name(CollectionType col_type, bool uppercase = false)
@@ -492,7 +493,7 @@ class CollectionBaseImpl : public Interface, protected ArrayParent {
492493
if (m_parent) {
493494
try {
494495
// Update the parent. Will throw if parent is not existing.
495-
switch (m_parent->update_if_needed_with_status()) {
496+
switch (m_parent->update_if_needed()) {
496497
case UpdateStatus::Updated:
497498
// Make sure to update next time around
498499
m_content_version = 0;
@@ -524,7 +525,7 @@ class CollectionBaseImpl : public Interface, protected ArrayParent {
524525
{
525526
try {
526527
// `has_changed()` sneakily modifies internal state.
527-
update_if_needed_with_status();
528+
update_if_needed();
528529
if (m_last_content_version != m_content_version) {
529530
m_last_content_version = m_content_version;
530531
return true;
@@ -573,14 +574,12 @@ class CollectionBaseImpl : public Interface, protected ArrayParent {
573574
Obj m_obj_mem;
574575
std::shared_ptr<CollectionParent> m_col_parent;
575576
CollectionParent::Index m_index;
576-
mutable size_t m_my_version = 0;
577577
ColKey m_col_key;
578-
bool m_nullable = false;
579-
580578
mutable uint_fast64_t m_content_version = 0;
581-
582579
// Content version used by `has_changed()`.
583580
mutable uint_fast64_t m_last_content_version = 0;
581+
mutable uint32_t m_parent_version = 0;
582+
bool m_nullable = false;
584583

585584
CollectionBaseImpl() = default;
586585
CollectionBaseImpl(const CollectionBaseImpl& other)
@@ -650,13 +649,14 @@ class CollectionBaseImpl : public Interface, protected ArrayParent {
650649

651650
UpdateStatus get_update_status() const
652651
{
653-
UpdateStatus status = m_parent ? m_parent->update_if_needed_with_status() : UpdateStatus::Detached;
652+
UpdateStatus status = m_parent ? m_parent->update_if_needed() : UpdateStatus::Detached;
654653

655654
if (status != UpdateStatus::Detached) {
656655
auto content_version = m_alloc->get_content_version();
657-
if (content_version != m_content_version || m_my_version != m_parent->m_parent_version) {
656+
auto parent_version = m_parent->parent_version();
657+
if (content_version != m_content_version || m_parent_version != parent_version) {
658658
m_content_version = content_version;
659-
m_my_version = m_parent->m_parent_version;
659+
m_parent_version = parent_version;
660660
status = UpdateStatus::Updated;
661661
}
662662
}
@@ -667,18 +667,14 @@ class CollectionBaseImpl : public Interface, protected ArrayParent {
667667
/// Refresh the parent object (if needed) and compare version numbers.
668668
/// Return true if the collection should initialize from parent
669669
/// Throws if the owning object no longer exists.
670-
bool should_update()
670+
bool should_update() const
671671
{
672672
check_parent();
673-
bool changed = m_parent->update_if_needed(); // Throws if the object does not exist.
674-
auto content_version = m_alloc->get_content_version();
675-
676-
if (changed || content_version != m_content_version || m_my_version != m_parent->m_parent_version) {
677-
m_content_version = content_version;
678-
m_my_version = m_parent->m_parent_version;
679-
return true;
673+
auto status = get_update_status();
674+
if (status == UpdateStatus::Detached) {
675+
throw StaleAccessor("Parent no longer exists");
680676
}
681-
return false;
677+
return status == UpdateStatus::Updated;
682678
}
683679

684680
void bump_content_version()
@@ -796,7 +792,7 @@ class CollectionBaseImpl : public Interface, protected ArrayParent {
796792
///
797793
/// If no change has happened to the data, this function returns
798794
/// `UpdateStatus::NoChange`, and the caller is allowed to not do anything.
799-
virtual UpdateStatus update_if_needed_with_status() const = 0;
795+
virtual UpdateStatus update_if_needed() const = 0;
800796
};
801797

802798
namespace _impl {
@@ -884,7 +880,7 @@ class ObjCollectionBase : public Interface, public _impl::ObjListProxy {
884880
/// `BPlusTree<T>`.
885881
virtual BPlusTree<ObjKey>* get_mutable_tree() const = 0;
886882

887-
/// Implements update_if_needed() in a way that ensures the consistency of
883+
/// Implements `update_if_needed()` in a way that ensures the consistency of
888884
/// the unresolved list. Derived classes should call this instead of calling
889885
/// `update_if_needed()` on their inner accessor.
890886
UpdateStatus update_if_needed() const

src/realm/collection_parent.hpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class CollectionParent : public std::enable_shared_from_this<CollectionParent> {
7474
using Index = StableIndex;
7575

7676
// Return the nesting level of the parent
77-
size_t get_level() const noexcept
77+
uint8_t get_level() const noexcept
7878
{
7979
return m_level;
8080
}
@@ -106,21 +106,17 @@ class CollectionParent : public std::enable_shared_from_this<CollectionParent> {
106106
#else
107107
static constexpr size_t s_max_level = 100;
108108
#endif
109-
size_t m_level = 0;
110-
mutable size_t m_parent_version = 0;
109+
uint8_t m_level = 0;
111110

112-
constexpr CollectionParent(size_t level = 0)
111+
constexpr CollectionParent(uint8_t level = 0)
113112
: m_level(level)
114113
{
115114
}
116115

117116
virtual ~CollectionParent();
118117
/// Update the accessor (and return `UpdateStatus::Detached` if the
119118
// collection is not initialized.
120-
virtual UpdateStatus update_if_needed_with_status() const = 0;
121-
/// Check if the storage version has changed and update if it has
122-
/// Return true if the object was updated
123-
virtual bool update_if_needed() const = 0;
119+
virtual UpdateStatus update_if_needed() const = 0;
124120
/// Get owning object
125121
virtual const Obj& get_object() const noexcept = 0;
126122
/// Get the top ref from pareht
@@ -133,6 +129,8 @@ class CollectionParent : public std::enable_shared_from_this<CollectionParent> {
133129
/// Set the top ref in parent
134130
virtual void set_collection_ref(Index, ref_type ref, CollectionType) = 0;
135131

132+
virtual uint32_t parent_version() const noexcept = 0;
133+
136134
// Used when inserting a new link. You will not remove existing links in this process
137135
void set_backlink(ColKey col_key, ObjLink new_link) const;
138136
// Used when replacing a link, return true if CascadeState contains objects to remove

src/realm/dictionary.cpp

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -651,10 +651,9 @@ size_t Dictionary::find_index(const Index& index) const
651651
return m_values->find_key(index.get_salt());
652652
}
653653

654-
UpdateStatus Dictionary::update_if_needed_with_status() const
654+
UpdateStatus Dictionary::do_update_if_needed(bool allow_create) const
655655
{
656-
auto status = Base::get_update_status();
657-
switch (status) {
656+
switch (get_update_status()) {
658657
case UpdateStatus::Detached: {
659658
m_dictionary_top.reset();
660659
return UpdateStatus::Detached;
@@ -667,27 +666,24 @@ UpdateStatus Dictionary::update_if_needed_with_status() const
667666
// perform lazy initialization by treating it as an update.
668667
[[fallthrough]];
669668
}
670-
case UpdateStatus::Updated: {
671-
// Try to initialize. If the dictionary is not initialized
672-
// the function will return false;
673-
bool attached = init_from_parent(false);
674-
Base::update_content_version();
675-
CollectionParent::m_parent_version++;
676-
return attached ? UpdateStatus::Updated : UpdateStatus::Detached;
677-
}
669+
case UpdateStatus::Updated:
670+
return init_from_parent(allow_create);
678671
}
679672
REALM_UNREACHABLE();
680673
}
681674

675+
UpdateStatus Dictionary::update_if_needed() const
676+
{
677+
constexpr bool allow_create = false;
678+
return do_update_if_needed(allow_create);
679+
}
680+
682681
void Dictionary::ensure_created()
683682
{
684-
if (Base::should_update() || !(m_dictionary_top && m_dictionary_top->is_attached())) {
685-
// When allow_create is true, init_from_parent will always succeed
686-
// In case of errors, an exception is thrown.
687-
constexpr bool allow_create = true;
688-
init_from_parent(allow_create); // Throws
689-
CollectionParent::m_parent_version++;
690-
Base::update_content_version();
683+
constexpr bool allow_create = true;
684+
if (do_update_if_needed(allow_create) == UpdateStatus::Detached) {
685+
// FIXME: untested
686+
throw StaleAccessor("Dictionary no longer exists");
691687
}
692688
}
693689

@@ -836,8 +832,9 @@ void Dictionary::clear()
836832
}
837833
}
838834

839-
bool Dictionary::init_from_parent(bool allow_create) const
835+
UpdateStatus Dictionary::init_from_parent(bool allow_create) const
840836
{
837+
Base::update_content_version();
841838
try {
842839
auto ref = Base::get_collection_ref();
843840
if ((ref || allow_create) && !m_dictionary_top) {
@@ -870,7 +867,7 @@ bool Dictionary::init_from_parent(bool allow_create) const
870867
// dictionary detached
871868
if (!allow_create) {
872869
m_dictionary_top.reset();
873-
return false;
870+
return UpdateStatus::Detached;
874871
}
875872

876873
// Create dictionary
@@ -880,7 +877,7 @@ bool Dictionary::init_from_parent(bool allow_create) const
880877
m_dictionary_top->update_parent();
881878
}
882879

883-
return true;
880+
return UpdateStatus::Updated;
884881
}
885882
catch (...) {
886883
m_dictionary_top.reset();
@@ -1178,7 +1175,6 @@ ref_type Dictionary::get_collection_ref(Index index, CollectionType type) const
11781175
throw realm::IllegalOperation(util::format("Not a %1", type));
11791176
}
11801177
throw StaleAccessor("This collection is no more");
1181-
return 0;
11821178
}
11831179

11841180
bool Dictionary::check_collection_ref(Index index, CollectionType type) const noexcept
@@ -1199,15 +1195,6 @@ void Dictionary::set_collection_ref(Index index, ref_type ref, CollectionType ty
11991195
m_values->set(ndx, Mixed(ref, type));
12001196
}
12011197

1202-
bool Dictionary::update_if_needed() const
1203-
{
1204-
auto status = update_if_needed_with_status();
1205-
if (status == UpdateStatus::Detached) {
1206-
throw StaleAccessor("CollectionList no longer exists");
1207-
}
1208-
return status == UpdateStatus::Updated;
1209-
}
1210-
12111198
/************************* DictionaryLinkValues *************************/
12121199

12131200
DictionaryLinkValues::DictionaryLinkValues(const Obj& obj, ColKey col_key)

src/realm/dictionary.hpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,7 @@ class Dictionary final : public CollectionBaseImpl<DictionaryBase>, public Colle
3939
using Base = CollectionBaseImpl<DictionaryBase>;
4040
class Iterator;
4141

42-
Dictionary()
43-
: CollectionParent(0)
44-
{
45-
}
42+
Dictionary() = default;
4643
~Dictionary();
4744

4845
Dictionary(const Obj& obj, ColKey col_key)
@@ -213,12 +210,15 @@ class Dictionary final : public CollectionBaseImpl<DictionaryBase>, public Colle
213210
{
214211
return get_obj().get_table();
215212
}
216-
UpdateStatus update_if_needed_with_status() const override;
217-
bool update_if_needed() const override;
213+
UpdateStatus update_if_needed() const override;
218214
const Obj& get_object() const noexcept override
219215
{
220216
return get_obj();
221217
}
218+
uint32_t parent_version() const noexcept override
219+
{
220+
return m_parent_version;
221+
}
222222
ref_type get_collection_ref(Index, CollectionType) const override;
223223
bool check_collection_ref(Index, CollectionType) const noexcept override;
224224
void set_collection_ref(Index, ref_type ref, CollectionType) override;
@@ -241,7 +241,7 @@ class Dictionary final : public CollectionBaseImpl<DictionaryBase>, public Colle
241241

242242
Dictionary(Allocator& alloc, ColKey col_key, ref_type ref);
243243

244-
bool init_from_parent(bool allow_create) const;
244+
UpdateStatus init_from_parent(bool allow_create) const;
245245
Mixed do_get(size_t ndx) const;
246246
void do_erase(size_t ndx, Mixed key);
247247
Mixed do_get_key(size_t ndx) const;
@@ -263,12 +263,14 @@ class Dictionary final : public CollectionBaseImpl<DictionaryBase>, public Colle
263263
void do_accumulate(size_t* return_ndx, AggregateType& agg) const;
264264

265265
void ensure_created();
266-
inline bool update() const
266+
bool update() const
267267
{
268-
return update_if_needed_with_status() != UpdateStatus::Detached;
268+
return update_if_needed() != UpdateStatus::Detached;
269269
}
270270
void verify() const;
271271
void get_key_type();
272+
273+
UpdateStatus do_update_if_needed(bool allow_create) const;
272274
};
273275

274276
class Dictionary::Iterator {
@@ -461,7 +463,7 @@ class DictionaryLinkValues final : public ObjCollectionBase<CollectionBase> {
461463
// Overrides of ObjCollectionBase:
462464
UpdateStatus do_update_if_needed() const final
463465
{
464-
return m_source.update_if_needed_with_status();
466+
return m_source.update_if_needed();
465467
}
466468
BPlusTree<ObjKey>* get_mutable_tree() const final
467469
{

0 commit comments

Comments
 (0)