Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client reset w/recovery #4711

Merged
merged 31 commits into from
Oct 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8ccbb84
Update BAAS
kneth Jun 17, 2022
6d4a82f
Add new client reset modes
kneth Jun 30, 2022
9cdf764
basic support for client reset w/recovery
kneth Jul 7, 2022
cbf471a
Migrate existing client reset tests
kneth Jul 7, 2022
eed600a
adding first tests
kneth Jul 8, 2022
5da73bd
Update API
kneth Aug 9, 2022
bfe3eba
Expand manual mode
kneth Sep 27, 2022
b1be3e7
Refactor sync error handlers. Add TS types
kneth Oct 1, 2022
026e52c
Add tests for manual client reset
kneth Oct 1, 2022
8acdab9
remove space
kneth Oct 12, 2022
e5b1b9d
Add triggerClientReset
kneth Oct 12, 2022
c07df56
Server-side client reset
kneth Oct 12, 2022
893c56b
TS defs for client reset
kneth Oct 12, 2022
20720ae
Fix warning. Fix linting errors.
kneth Oct 12, 2022
f566c2c
Trigger client reset
kneth Oct 12, 2022
c839965
wip
kneth Oct 12, 2022
87e0d7b
wip
kneth Oct 12, 2022
5212512
Also testing flexible sync
kneth Oct 13, 2022
5d23205
wip
kneth Oct 14, 2022
b3f5189
Fix test
kneth Oct 14, 2022
7208c54
disable flx tests
kneth Oct 14, 2022
d0e09a2
Apply suggestions from code review
kneth Oct 14, 2022
f3c514f
Rename to UnsyncedChanges
kneth Oct 17, 2022
98b632f
Update API + docs + tests + TS defs
kneth Oct 21, 2022
65b1bc1
C++ code formatting
kneth Oct 21, 2022
e28658a
Fix session test
kneth Oct 25, 2022
28fb013
Increase timeout for client reset tests to an insane large value
kneth Oct 26, 2022
579733a
Suppress destruction on node/electron for callbacks
kneth Oct 26, 2022
b40e3c5
Increase timeout
kneth Oct 28, 2022
a110a89
wip
kneth Oct 31, 2022
2ca2df1
lint
kneth Oct 31, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
## vNext (TBD)

### Enhancements
* Improve performance of client reset with automatic recovery and converting top-level tables into embedded tables. ([realm/realm-core#5897](https://github.com/realm/realm-core/pull/5897))
* If a sync client sends a message larger than 16 MB, the sync server will request a client reset. ([realm/realm-core#5209](https://github.com/realm/realm-core/issues/5209))
* Add two new modes to client reset: `RecoverUnsyncedChanges` and `RecoverOrDiscardUnsyncedChanges`. The two modes will recover local/unsynced changes with changes from the server if possible. If not possible, `RecoverOrDiscardUnsyncedChanges` will remove the local Realm file and download a fresh file from the server. The mode `DiscardLocal` is duplicated as `DiscardUnsyncedChanges`, and `DiscardLocal` is be removed in a future version. ([#4135](https://github.com/realm/realm-js/issues/4135))

### Fixed
* Fixed a use-after-free if the last external reference to an encrypted Realm was closed between when a client reset error was received and when the download of the new Realm began. ([realm/realm-core#5949](https://github.com/realm/realm-core/pull/5949), since v10.20.0)
Expand Down
8 changes: 5 additions & 3 deletions docs/sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@
/**
* This describes the options to configure client reset.
* @typedef {Object} Realm.App.Sync~ClientResetConfiguration
* @property {string} mode - Either "manual" (deprecated, see also `Realm.App.Sync.initiateClientReset()`) or "discardLocal" (download a fresh copy from the server).
* @property {callback(realm)|null} [clientResetBefore] - called before sync initiates a client reset.
* @property {callback(beforeRealm, afterRealm)|null} [clientResetAfter] - called after client reset has been executed; `beforeRealm` and `afterRealm` are instances of the Realm before and after the client reset.
* @property {string} mode - Either "manual" (deprecated, see also `Realm.App.Sync.initiateClientReset()`), "discardUnsyncedChanges" (download a fresh copy from the server), "recoverUnsyncedChanges" (merged remote and local, unsynced changes), or "recoverOrDiscardUnsyncedChanges" (download a fresh copy from the server if recovery of unsynced changes is not possible)
* @property {callback(realm)|null} [onBefore] - called before sync initiates a client reset (only for "discardUnsyncedChanges", "recoverUnsyncedChanges" or "recoverOrDiscardUnsyncedChanges" modes).
* @property {callback(beforeRealm, afterRealm)|null} [onAfter] - called after client reset has been executed; `beforeRealm` and `afterRealm` are instances of the Realm before and after the client reset (only for "discardUnsyncedChanges", "recoverUnsyncedChanges" or "recoverOrDiscardUnsyncedChanges" modes).
* @property {callback(session, path)|null} [onFallback] - called if recovery or discard fail (only for "recoverUnsyncedChanges" or "recoverOrDiscardUnsyncedChanges" modes).
* @property {callback(session, path)|null} [onManual] - perform manual client reset - see also `Realm.App.Sync.initiateClientReset()` (only "manual" mode).
* @since {10.11.0}
*/

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "triggerClientReset",
"private": false,
"run_as_system": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2022 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.
//
////////////////////////////////////////////////////////////////////////////

/* eslint-env node */
/* global context */

exports = async function (appId, userId) {
return (await deleteClientFile(`__realm_sync_${appId}`, userId)) || (await deleteClientFile(`__realm_sync`, userId));
};

async function deleteClientFile(db, userId) {
const mongodb = context.services.get("mongodb");
return (await mongodb.db(db).collection("clientfiles").deleteMany({ ownerId: userId })).deletedCount > 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "triggerClientReset",
"private": false,
"run_as_system": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2022 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.
//
////////////////////////////////////////////////////////////////////////////

/* eslint-env node */
/* global context */

exports = async function (appId, userId) {
return (await deleteClientFile(`__realm_sync_${appId}`, userId)) || (await deleteClientFile(`__realm_sync`, userId));
};

async function deleteClientFile(db, userId) {
const mongodb = context.services.get("mongodb");
return (await mongodb.db(db).collection("clientfiles").deleteMany({ ownerId: userId })).deletedCount > 0;
}
1 change: 1 addition & 0 deletions integration-tests/tests/src/tests/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ import "./sync/flexible";
import "./sync/asymmetric";
import "./sync/sync-as-local";
import "./transaction";
import "./sync/client-reset";
1 change: 1 addition & 0 deletions integration-tests/tests/src/tests/sync/asymmetric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { authenticateUserBefore, importAppBefore, openRealmBeforeEach } from "..

describe.skipIf(environment.missingServer, "Asymmetric sync", function () {
describe("Configuration and schema", function () {
this.timeout(20 * 1000);
const PersonSchema: Realm.ObjectSchema = {
name: "Person",
asymmetric: true,
Expand Down
Loading