• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-core / 1662

12 Sep 2023 09:48AM UTC coverage: 91.217% (-0.05%) from 91.265%
1662

push

Evergreen

GitHub
Resending pending subscriptions can result in inconsistent sync progress (#6965)

95838 of 175790 branches covered (0.0%)

87 of 94 new or added lines in 2 files covered. (92.55%)

165 existing lines in 16 files now uncovered.

233563 of 256053 relevant lines covered (91.22%)

6854188.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.23
/src/realm/sync/noinst/client_reset_operation.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2021 Realm Inc.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 * http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 **************************************************************************/
18

19
#include <realm/transaction.hpp>
20
#include <realm/sync/history.hpp>
21
#include <realm/sync/noinst/client_history_impl.hpp>
22
#include <realm/sync/noinst/client_reset.hpp>
23
#include <realm/sync/noinst/client_reset_operation.hpp>
24
#include <realm/util/scope_exit.hpp>
25

26
namespace realm::_impl {
27

28
namespace {
29

30
constexpr static std::string_view c_fresh_suffix(".fresh");
31

32
} // namespace
33

34
ClientResetOperation::ClientResetOperation(util::Logger& logger, DBRef db, DBRef db_fresh, ClientResyncMode mode,
35
                                           CallbackBeforeType notify_before, CallbackAfterType notify_after,
36
                                           bool recovery_is_allowed)
37
    : m_logger{logger}
38
    , m_db{db}
39
    , m_db_fresh(std::move(db_fresh))
40
    , m_mode(mode)
41
    , m_notify_before(std::move(notify_before))
42
    , m_notify_after(std::move(notify_after))
43
    , m_recovery_is_allowed(recovery_is_allowed)
44
{
336✔
45
    REALM_ASSERT(m_db);
336✔
46
    REALM_ASSERT_RELEASE(m_mode != ClientResyncMode::Manual);
336✔
47
    m_logger.debug("Create ClientResetOperation, realm_path = %1, mode = %2, recovery_allowed = %3", m_db->get_path(),
336✔
48
                   m_mode, m_recovery_is_allowed);
336✔
49
}
336✔
50

51
std::string ClientResetOperation::get_fresh_path_for(const std::string& path)
52
{
3,309,332✔
53
    const size_t suffix_len = c_fresh_suffix.size();
3,309,332✔
54
    REALM_ASSERT(path.length());
3,309,332✔
55
    REALM_ASSERT_DEBUG_EX(
3,309,332✔
56
        path.size() < suffix_len || path.substr(path.size() - suffix_len, suffix_len) != c_fresh_suffix, path);
3,309,332✔
57
    return path + c_fresh_suffix.data();
3,309,332✔
58
}
3,309,332✔
59

60
bool ClientResetOperation::is_fresh_path(const std::string& path)
61
{
3,294✔
62
    const size_t suffix_len = c_fresh_suffix.size();
3,294✔
63
    REALM_ASSERT(path.length());
3,294✔
64
    if (path.size() < suffix_len) {
3,294✔
65
        return false;
×
66
    }
×
67
    return path.substr(path.size() - suffix_len, suffix_len) == c_fresh_suffix;
3,294✔
68
}
3,294✔
69

70
bool ClientResetOperation::finalize(sync::SaltedFileIdent salted_file_ident, sync::SubscriptionStore* sub_store,
71
                                    util::UniqueFunction<void(int64_t)> on_flx_version_complete)
72
{
336✔
73
    m_salted_file_ident = salted_file_ident;
336✔
74
    // only do the reset if there is data to reset
168✔
75
    // if there is nothing in this Realm, then there is nothing to reset and
168✔
76
    // sync should be able to continue as normal
168✔
77
    auto latest_version = m_db->get_version_id_of_latest_snapshot();
336✔
78

168✔
79
    bool local_realm_exists = latest_version.version != 0;
336✔
80
    m_logger.debug("ClientResetOperation::finalize, realm_path = %1, local_realm_exists = %2, mode = %3",
336✔
81
                   m_db->get_path(), local_realm_exists, m_mode);
336✔
82
    if (!local_realm_exists) {
336✔
83
        return false;
×
84
    }
×
85

168✔
86
    REALM_ASSERT_EX(m_db_fresh, m_db->get_path(), m_mode);
336✔
87

168✔
88
    client_reset::LocalVersionIDs local_version_ids;
336✔
89
    auto always_try_clean_up = util::make_scope_exit([&]() noexcept {
336✔
90
        clean_up_state();
336✔
91
    });
336✔
92

168✔
93
    VersionID frozen_before_state_version = m_notify_before ? m_notify_before() : latest_version;
296✔
94

168✔
95
    // If m_notify_after is set, pin the previous state to keep it around.
168✔
96
    TransactionRef previous_state;
336✔
97
    if (m_notify_after) {
336✔
98
        previous_state = m_db->start_frozen(frozen_before_state_version);
244✔
99
    }
244✔
100
    bool did_recover_out = false;
336✔
101
    local_version_ids = client_reset::perform_client_reset_diff(
336✔
102
        m_db, m_db_fresh, m_salted_file_ident, m_logger, m_mode, m_recovery_is_allowed, &did_recover_out, sub_store,
336✔
103
        std::move(on_flx_version_complete)); // throws
336✔
104

168✔
105
    if (m_notify_after) {
336✔
106
        m_notify_after(previous_state->get_version_of_current_transaction(), did_recover_out);
188✔
107
    }
188✔
108

168✔
109
    m_client_reset_old_version = local_version_ids.old_version;
336✔
110
    m_client_reset_new_version = local_version_ids.new_version;
336✔
111

168✔
112
    return true;
336✔
113
}
336✔
114

115
void ClientResetOperation::clean_up_state() noexcept
116
{
336✔
117
    if (m_db_fresh) {
336✔
118
        std::string path_to_clean = m_db_fresh->get_path();
336✔
119
        try {
336✔
120
            // In order to obtain the lock and delete the realm, we first have to close
168✔
121
            // the Realm. This requires that we are the only remaining ref holder, and
168✔
122
            // this is expected. Releasing the last ref should release the hold on the
168✔
123
            // lock file and allow us to clean up.
168✔
124
            long use_count = m_db_fresh.use_count();
336✔
125
            REALM_ASSERT_DEBUG_EX(use_count == 1, use_count, path_to_clean);
336✔
126
            m_db_fresh.reset();
336✔
127
            // clean up the fresh Realm
168✔
128
            // we don't mind leaving the fresh lock file around because trying to delete it
168✔
129
            // here could cause a race if there are multiple resets ongoing
168✔
130
            bool did_lock = DB::call_with_lock(path_to_clean, [&](const std::string& path) {
336✔
131
                constexpr bool delete_lockfile = false;
336✔
132
                DB::delete_files(path, nullptr, delete_lockfile);
336✔
133
            });
336✔
134
            if (!did_lock) {
336✔
135
                m_logger.warn("In ClientResetOperation::finalize, the fresh copy '%1' could not be cleaned up. "
×
136
                              "There were %2 refs remaining.",
×
137
                              path_to_clean, use_count);
×
138
            }
×
139
        }
336✔
140
        catch (const std::exception& err) {
168✔
UNCOV
141
            m_logger.warn("In ClientResetOperation::finalize, the fresh copy '%1' could not be cleaned up due to "
×
UNCOV
142
                          "an exception: '%2'",
×
UNCOV
143
                          path_to_clean, err.what());
×
144
            // ignored, this is just a best effort
UNCOV
145
        }
×
146
    }
336✔
147
}
336✔
148

149
} // namespace realm::_impl
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc