diff --git a/CHANGELOG.md b/CHANGELOG.md
index ce154f06d9..da07086db6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,15 +21,20 @@
* Added the method `App.DeleteUserFromServerAsync` to delete a user from the server. It will also invalidate the user locally as well as remove all their local data. It will not remove any data the user has uploaded from the server. (Issue [#2675](https://github.com/realm/realm-dotnet/issues/2675))
* Added boolean property `ChangeSet.IsCleared` that is true when the collection gets cleared. Also Realm collections now raise `CollectionChanged` event with action `Reset` instead of `Remove` when the collections is cleared. Please note that this will work only with collection properties, such as `IList` and `ISet`. (Issue [#2856](https://github.com/realm/realm-dotnet/issues/2856))
* Added `PopulateInitialSubscriptions` to `FlexibleSyncConfiguration` - this is a callback that will be invoked the first time a Realm is opened. It allows you to create the initial subscriptions that will be added to the Realm before it is opened. (Issue [#2913](https://github.com/realm/realm-dotnet/issues/2913))
+* Bump the SharedInfo version to 12. This requires update of any app accessing the file in a multiprocess scenario, including Realm Studio.
+* The sync client will gracefully handle compensating write error messages from the server and pass detailed info to the SDK's sync error handler about which objects caused the compensating write to occur. ([#5528](https://github.com/realm/realm-core/pull/5528))
### Fixed
-* None
+* Adding an object to a Set, deleting the parent object, and then deleting the previously mentioned object causes crash ([#5387](https://github.com/realm/realm-core/issues/5387))
+* Flexible sync would not correctly resume syncing if a bootstrap was interrupted ([#5466](https://github.com/realm/realm-core/pull/5466))
+* Flexible sync will now ensure that a bootstrap from the server will only be applied if the entire bootstrap is received - ensuring there are no orphaned objects as a result of changing the read snapshot on the server ([#5331](https://github.com/realm/realm-core/pull/5331))
+* Partially fix a performance regression in write performance on Apple platforms. Committing an empty write transaction is ~10x faster than 10.13.0, but still slower than pre-10.7.1 due to using more crash-safe file synchronization (since v10.7.1). (Swift issue [#7740](https://github.com/realm/realm-swift/issues/7740)).
### Compatibility
* Realm Studio: 11.0.0 or later.
### Internal
-* Using Core x.y.z.
+* Using Core 12.1.0.
## 10.13.0 (2022-05-18)
diff --git a/Realm/Realm/Exceptions/Sync/ErrorCode.cs b/Realm/Realm/Exceptions/Sync/ErrorCode.cs
index eec769f08f..18c0d8c874 100644
--- a/Realm/Realm/Exceptions/Sync/ErrorCode.cs
+++ b/Realm/Realm/Exceptions/Sync/ErrorCode.cs
@@ -150,6 +150,12 @@ public enum ErrorCode
///
WriteNotAllowed = 230,
+ ///
+ /// Client attempted a write that is disallowed by permissions, or modifies an
+ /// object outside the current query, and the server undid the modification.
+ ///
+ CompensatingWrite = 231,
+
///
/// Your request parameters did not validate.
///
diff --git a/Tests/Realm.Tests/Sync/FlexibleSyncTests.cs b/Tests/Realm.Tests/Sync/FlexibleSyncTests.cs
index 93adddd527..75685b82e6 100644
--- a/Tests/Realm.Tests/Sync/FlexibleSyncTests.cs
+++ b/Tests/Realm.Tests/Sync/FlexibleSyncTests.cs
@@ -26,7 +26,6 @@
using Realms.Exceptions;
using Realms.Exceptions.Sync;
using Realms.Sync;
-using Realms.Sync.ErrorHandling;
using Realms.Sync.Exceptions;
namespace Realms.Tests.Sync
@@ -1575,7 +1574,7 @@ public void Integration_SubscriptionSet_WaitForSynchronization_CanBeCalledMultip
});
}
- [Test, Ignore("This is no longer an error due to compensating writes")]
+ [Test]
public void Integration_CreateObjectNotMatchingSubscriptions_ShouldError()
{
SyncTestHelpers.RunBaasTestAsync(async () =>
@@ -1583,17 +1582,13 @@ public void Integration_CreateObjectNotMatchingSubscriptions_ShouldError()
var errorTcs = new TaskCompletionSource();
var testGuid = Guid.NewGuid();
var config = await GetFLXIntegrationConfigAsync();
- config.ClientResetHandler = new ManualRecoveryHandler(error =>
- {
- errorTcs.TrySetResult(error);
- });
config.OnSessionError = (session, error) =>
{
errorTcs.TrySetResult(error);
};
- var realm = await GetFLXIntegrationRealmAsync();
+ var realm = await GetRealmAsync(config);
realm.Subscriptions.Update(() =>
{
@@ -1606,7 +1601,7 @@ public void Integration_CreateObjectNotMatchingSubscriptions_ShouldError()
});
var sessionError = await errorTcs.Task;
- Assert.That(sessionError.ErrorCode, Is.EqualTo(ErrorCode.WriteNotAllowed));
+ Assert.That(sessionError.ErrorCode, Is.EqualTo(ErrorCode.CompensatingWrite));
});
}
@@ -1615,13 +1610,13 @@ public void Integration_UpdateObjectNotMatchingSubscriptions_ShouldError()
{
SyncTestHelpers.RunBaasTestAsync(async () =>
{
- var errorTcs = new TaskCompletionSource();
+ var errorTcs = new TaskCompletionSource();
var testGuid = Guid.NewGuid();
var config = await GetFLXIntegrationConfigAsync();
- config.ClientResetHandler = new ManualRecoveryHandler(error =>
+ config.OnSessionError = (session, error) =>
{
errorTcs.TrySetResult(error);
- });
+ };
var realm = await GetRealmAsync(config);
@@ -1651,7 +1646,7 @@ public void Integration_UpdateObjectNotMatchingSubscriptions_ShouldError()
});
var sessionError = await errorTcs.Task;
- Assert.That(sessionError.ErrorCode, Is.EqualTo(ErrorCode.WriteNotAllowed));
+ Assert.That(sessionError.ErrorCode, Is.EqualTo(ErrorCode.CompensatingWrite));
});
}
diff --git a/wrappers/realm-core b/wrappers/realm-core
index d0f02225f1..f8f6b3730e 160000
--- a/wrappers/realm-core
+++ b/wrappers/realm-core
@@ -1 +1 @@
-Subproject commit d0f02225f161401d6cf493c0d0024d6216b60135
+Subproject commit f8f6b3730e32dcc5b6564ebbfa5626a640cdb52a