This differential implements restore from backup log function on web and native. Backup logs aren't decrypted - I agreed with @michal that log decryption will take place in rust just after downloading log.
Details
- Reviewers
kamil michal - Commits
- rCOMMd0fb20607662: Implement restore from backup logs
- Temporarily disable backup log encryption. Replace encryptedLogBytes with logBytes in NativeConnectionManager.cpp in persistLog.
- Build native app.
- Use the app, create some drafts.
- Download backup logs from XCode.
- Apply this patch to web: https://gist.github.com/marcinwasowicz/1fd0e17c4808d72467ecf11dca9e0ca3
- Find the first log that creates draft and use button introduced by the patch above to trigger restoration.
- Refresh web app. Ensure draft created on native is there.
To test native:
- Comment out removing backup directory in DatabaseManager::clearSensitiveData().
- Comment out code that encrypts logs.
- Add a call that creates main compaction restore_backup in backup.rs.
- Build the app.
- Create compaction by pressing button in backup menu.
- Create some drafts.
- Log out.
- Download app Documents container from XCode and see how many logs are there.
- Change restore_backup to restore from all logs files that affect drafts.
- Build the app. Log in.
- Press button in backup menu to restore from logs
- See that drafts are recreated.
In order to test conflict handler repeat steps above but do not restore from all logs in step 9. Basically skip log that inserts draft and apply only those that modify it. Ensure no drafts are created but logs in the XCode console appear informing that conflict occurred.
Diff Detail
- Repository
- rCOMM Comm
- Lint
No Lint Coverage - Unit
No Test Coverage
Event Timeline
native/cpp/CommonCpp/DatabaseManagers/NativeConnectionManager.cpp | ||
---|---|---|
238–240 ↗ | (On Diff #36487) | This temporarily disables logs capture for the time of restoration. |
native/cpp/CommonCpp/DatabaseManagers/SQLiteConnectionManager.cpp | ||
67 ↗ | (On Diff #36487) | This function is invoked when sqlite3changeset_apply encounters issue when applying change. I highly recommend reviewers to read detailed explanation here, but I will shortly explain what is going on here and why I decided to implement conflict handler like this. The second argument to conflict handler is the conflict reason and return value from handler dictates how conflicting change is treated. In our case we can have the following conflict reasons:
In summary all conflicts we might encounter are due to the fact that we missed some logs. Apart from the last one we don't have an easy automatic way to recover from them. Theoretically we could recover from SQLITE_CHANGESET_NOTFOUND during update by inspecting update statement and constructing insert statement from it. However it would complicate the code significantly. That said I implemented this stack to ensure that no logs are missed in the first place, so in conflict handler I just inspect conflict content, log it and either solve if is the easy case with insert or return SQLITE_CHANGESET_OMIT which makes sqlite3changeset_apply ignore the change. |