From d46f2c65baaae0ee47a94a91c248f0a46aeae3c4 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Fri, 4 Mar 2016 10:54:13 -0800 Subject: [PATCH] Refactor the transaction log parsers to eliminate some duplication --- src/impl/transact_log_handler.cpp | 136 ++++++++++++------------------ tests/results.cpp | 27 +++++- 2 files changed, 75 insertions(+), 88 deletions(-) diff --git a/src/impl/transact_log_handler.cpp b/src/impl/transact_log_handler.cpp index 1dd75e0f..5601ce34 100644 --- a/src/impl/transact_log_handler.cpp +++ b/src/impl/transact_log_handler.cpp @@ -29,9 +29,30 @@ using namespace realm; namespace { -// A transaction log handler that just validates that all operations made are -// ones supported by the object store -class TransactLogValidator { +template +struct MarkDirtyMixin { + bool mark_dirty(size_t row, size_t col) { static_cast(this)->mark_dirty(row, col); return true; } + + bool set_int(size_t col, size_t row, int_fast64_t) { return mark_dirty(row, col); } + bool set_bool(size_t col, size_t row, bool) { return mark_dirty(row, col); } + bool set_float(size_t col, size_t row, float) { return mark_dirty(row, col); } + bool set_double(size_t col, size_t row, double) { return mark_dirty(row, col); } + bool set_string(size_t col, size_t row, StringData) { return mark_dirty(row, col); } + bool set_binary(size_t col, size_t row, BinaryData) { return mark_dirty(row, col); } + bool set_olddatetime(size_t col, size_t row, OldDateTime) { return mark_dirty(row, col); } + bool set_timestamp(size_t col, size_t row, Timestamp) { return mark_dirty(row, col); } + bool set_table(size_t col, size_t row) { return mark_dirty(row, col); } + bool set_mixed(size_t col, size_t row, const Mixed&) { return mark_dirty(row, col); } + bool set_link(size_t col, size_t row, size_t, size_t) { return mark_dirty(row, col); } + bool set_null(size_t col, size_t row) { return mark_dirty(row, col); } + bool nullify_link(size_t col, size_t row, size_t) { return mark_dirty(row, col); } + bool set_int_unique(size_t col, size_t row, size_t, int_fast64_t) { return mark_dirty(row, col); } + bool set_string_unique(size_t col, size_t row, size_t, StringData) { return mark_dirty(row, col); } + bool insert_substring(size_t col, size_t row, size_t, StringData) { return mark_dirty(row, col); } + bool erase_substring(size_t col, size_t row, size_t, size_t) { return mark_dirty(row, col); } +}; + +class TransactLogValidationMixin { // Index of currently selected table size_t m_current_table = 0; @@ -120,30 +141,20 @@ public: bool link_list_clear(size_t) { return true; } bool link_list_move(size_t, size_t) { return true; } bool link_list_swap(size_t, size_t) { return true; } - bool set_int(size_t, size_t, int_fast64_t) { return true; } - bool set_bool(size_t, size_t, bool) { return true; } - bool set_float(size_t, size_t, float) { return true; } - bool set_double(size_t, size_t, double) { return true; } - bool set_string(size_t, size_t, StringData) { return true; } - bool set_binary(size_t, size_t, BinaryData) { return true; } - bool set_olddatetime(size_t, size_t, OldDateTime) { return true; } - bool set_timestamp(size_t, size_t, Timestamp) { return true; } - bool set_table(size_t, size_t) { return true; } - bool set_mixed(size_t, size_t, const Mixed&) { return true; } - bool set_link(size_t, size_t, size_t, size_t) { return true; } - bool set_null(size_t, size_t) { return true; } - bool nullify_link(size_t, size_t, size_t) { return true; } - bool insert_substring(size_t, size_t, size_t, StringData) { return true; } - bool erase_substring(size_t, size_t, size_t, size_t) { return true; } - bool optimize_table() { return true; } - 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 change_link_targets(size_t, size_t) { return true; } + bool optimize_table() { return true; } +}; + + +// A transaction log handler that just validates that all operations made are +// ones supported by the object store +struct TransactLogValidator : public TransactLogValidationMixin, public MarkDirtyMixin { + void mark_dirty(size_t, size_t) { } }; // Extends TransactLogValidator to also track changes and report it to the // binding context if any properties are being observed -class TransactLogObserver : public TransactLogValidator { +class TransactLogObserver : public TransactLogValidationMixin, public MarkDirtyMixin { using ColumnInfo = BindingContext::ColumnInfo; using ObserverState = BindingContext::ObserverState; @@ -182,16 +193,6 @@ class TransactLogObserver : public TransactLogValidator { } } - // Mark the given row/col as needing notifications sent - bool mark_dirty(size_t row_ndx, size_t col_ndx) - { - auto it = lower_bound(begin(m_observers), end(m_observers), ObserverState{current_table(), row_ndx, nullptr}); - if (it != end(m_observers) && it->table_ndx == current_table() && it->row_ndx == row_ndx) { - get_change(*it, col_ndx).changed = true; - } - return true; - } - // Remove the given observer from the list of observed objects and add it // to the listed of invalidated objects void invalidate(ObserverState *o) @@ -207,10 +208,7 @@ public: { if (!context) { if (validate_schema_changes) { - // The handler functions are non-virtual, so the parent class's - // versions are called if we don't need to track changes to observed - // objects - func(static_cast(*this)); + func(TransactLogValidator()); } else { func(); @@ -222,7 +220,7 @@ public: if (m_observers.empty()) { auto old_version = sg.get_version_of_current_transaction(); if (validate_schema_changes) { - func(static_cast(*this)); + func(TransactLogValidator()); } else { func(); @@ -237,6 +235,15 @@ public: context->did_change(m_observers, invalidated); } + // Mark the given row/col as needing notifications sent + void mark_dirty(size_t row_ndx, size_t col_ndx) + { + auto it = lower_bound(begin(m_observers), end(m_observers), ObserverState{current_table(), row_ndx, nullptr}); + if (it != end(m_observers) && it->table_ndx == current_table() && it->row_ndx == row_ndx) { + get_change(*it, col_ndx).changed = true; + } + } + // Called at the end of the transaction log immediately before the version // is advanced void parse_complete() @@ -250,7 +257,7 @@ public: if (observer.table_ndx >= table_ndx) ++observer.table_ndx; } - TransactLogValidator::insert_group_level_table(table_ndx, prior_size, name); + TransactLogValidationMixin::insert_group_level_table(table_ndx, prior_size, name); return true; } @@ -411,29 +418,10 @@ public: } return true; } - - // Things that just mark the field as modified - bool set_int(size_t col, size_t row, int_fast64_t) { return mark_dirty(row, col); } - bool set_bool(size_t col, size_t row, bool) { return mark_dirty(row, col); } - bool set_float(size_t col, size_t row, float) { return mark_dirty(row, col); } - bool set_double(size_t col, size_t row, double) { return mark_dirty(row, col); } - bool set_string(size_t col, size_t row, StringData) { return mark_dirty(row, col); } - bool set_binary(size_t col, size_t row, BinaryData) { return mark_dirty(row, col); } - bool set_olddatetime(size_t col, size_t row, OldDateTime) { return mark_dirty(row, col); } - bool set_timestamp(size_t col, size_t row, Timestamp) { return mark_dirty(row, col); } - bool set_table(size_t col, size_t row) { return mark_dirty(row, col); } - bool set_mixed(size_t col, size_t row, const Mixed&) { return mark_dirty(row, col); } - bool set_link(size_t col, size_t row, size_t, size_t) { return mark_dirty(row, col); } - bool set_null(size_t col, size_t row) { return mark_dirty(row, col); } - bool nullify_link(size_t col, size_t row, size_t) { return mark_dirty(row, col); } - bool set_int_unique(size_t col, size_t row, size_t, int_fast64_t) { return mark_dirty(row, col); } - bool set_string_unique(size_t col, size_t row, size_t, StringData) { return mark_dirty(row, col); } - bool insert_substring(size_t col, size_t row, size_t, StringData) { return mark_dirty(row, col); } - bool erase_substring(size_t col, size_t row, size_t, size_t) { return mark_dirty(row, col); } }; // Extends TransactLogValidator to track changes made to LinkViews -class LinkViewObserver : public TransactLogValidator { +class LinkViewObserver : public TransactLogValidationMixin, public MarkDirtyMixin { _impl::TransactionChangeInfo& m_info; CollectionChangeIndices* m_active = nullptr; @@ -448,17 +436,16 @@ class LinkViewObserver : public TransactLogValidator { return &m_info.tables[tbl_ndx]; } - bool mark_dirty(size_t row, __unused size_t col) - { - if (auto change = get_change()) - change->modify(row); - return true; - } - public: LinkViewObserver(_impl::TransactionChangeInfo& info) : m_info(info) { } + void mark_dirty(size_t row, __unused size_t col) + { + if (auto change = get_change()) + change->modify(row); + } + bool select_link_list(size_t col, size_t row, size_t) { mark_dirty(row, col); @@ -563,25 +550,6 @@ public: change->clear(0); // FIXME return true; } - - // Things that just mark the field as modified - bool set_int(size_t col, size_t row, int_fast64_t) { return mark_dirty(row, col); } - bool set_bool(size_t col, size_t row, bool) { return mark_dirty(row, col); } - bool set_float(size_t col, size_t row, float) { return mark_dirty(row, col); } - bool set_double(size_t col, size_t row, double) { return mark_dirty(row, col); } - bool set_string(size_t col, size_t row, StringData) { return mark_dirty(row, col); } - bool set_binary(size_t col, size_t row, BinaryData) { return mark_dirty(row, col); } - bool set_olddatetime(size_t col, size_t row, OldDateTime) { return mark_dirty(row, col); } - bool set_timestamp(size_t col, size_t row, Timestamp) { return mark_dirty(row, col); } - bool set_table(size_t col, size_t row) { return mark_dirty(row, col); } - bool set_mixed(size_t col, size_t row, const Mixed&) { return mark_dirty(row, col); } - bool set_link(size_t col, size_t row, size_t, size_t) { return mark_dirty(row, col); } - bool set_null(size_t col, size_t row) { return mark_dirty(row, col); } - bool nullify_link(size_t col, size_t row, size_t) { return mark_dirty(row, col); } - bool insert_substring(size_t col, size_t row, size_t, StringData) { return mark_dirty(row, col); } - bool erase_substring(size_t col, size_t row, size_t, size_t) { return mark_dirty(row, col); } - bool set_int_unique(size_t col, size_t row, size_t, int_fast64_t) { return mark_dirty(row, col); } - bool set_string_unique(size_t col, size_t row, size_t, StringData) { return mark_dirty(row, col); } }; } // anonymous namespace diff --git a/tests/results.cpp b/tests/results.cpp index 62989924..be8c13d4 100644 --- a/tests/results.cpp +++ b/tests/results.cpp @@ -363,8 +363,28 @@ TEST_CASE("Async Results error handling") { auto coordinator = _impl::RealmCoordinator::get_existing_coordinator(config.path); Results results(r, *config.schema->find("object"), *r->read_group()->get_table("class_object")); + class OpenFileLimiter { + public: + OpenFileLimiter() + { + // Set the max open files to zero so that opening new files will fail + getrlimit(RLIMIT_NOFILE, &m_old); + rlimit rl = m_old; + rl.rlim_cur = 0; + setrlimit(RLIMIT_NOFILE, &rl); + } + + ~OpenFileLimiter() + { + setrlimit(RLIMIT_NOFILE, &m_old); + } + + private: + rlimit m_old; + }; + SECTION("error when opening the advancer SG") { - unlink(config.path.c_str()); + OpenFileLimiter limiter; SECTION("error is delivered asynchronously") { bool called = false; @@ -412,7 +432,7 @@ TEST_CASE("Async Results error handling") { REQUIRE(err); called = true; }); - unlink(config.path.c_str()); + OpenFileLimiter limiter; REQUIRE(!called); coordinator->on_change(); @@ -428,7 +448,7 @@ TEST_CASE("Async Results error handling") { REQUIRE_FALSE(called); called = true; }); - unlink(config.path.c_str()); + OpenFileLimiter limiter; coordinator->on_change(); r->notify(); @@ -445,6 +465,5 @@ TEST_CASE("Async Results error handling") { REQUIRE(called2); } - } }