-
Notifications
You must be signed in to change notification settings - Fork 0
feat: optimise backup & restore for performance #458
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR refactors backup management logic by introducing a computed isRequired property to the BackupItemStatus model and updates the backup infrastructure. The changes improve code maintainability by replacing repetitive synced < required comparisons with a clearer semantic property.
Key changes:
- Added
isRequiredcomputed property toBackupItemStatusfor cleaner backup status checks - Refactored
BackupRepoto useIoDispatcherfor I/O operations and enhanced backup scheduling logic - Updated
WalletViewModelto trigger backup scheduling after wallet creation and simplified backup restore flow
Reviewed Changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| gradle/libs.versions.toml | Bumped bitkit-core-android version from 0.1.22 to 0.1.23 |
| app/src/main/java/to/bitkit/models/BackupCategory.kt | Added isRequired computed property to BackupItemStatus and changed default values from 0L to 0 |
| app/src/main/java/to/bitkit/repositories/BackupRepo.kt | Changed from BgDispatcher to IoDispatcher, replaced direct comparisons with isRequired property, enhanced backup scheduling with immediate running flag, added scheduleFullBackup function, extracted nowMillis utility |
| app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt | Refactored restoreFromBackup to be suspend function, added backup scheduling after wallet creation |
| app/src/main/java/to/bitkit/viewmodels/BackupsViewModel.kt | Moved disableRetry logic from ViewModel to toUiState extension function |
| app/src/main/java/to/bitkit/ui/settings/BackupSettingsScreen.kt | Updated all backup status checks to use isRequired property instead of direct comparison |
| app/src/main/java/to/bitkit/repositories/HealthRepo.kt | Changed sync comparison from > to >= for consistency |
| app/src/main/java/to/bitkit/repositories/WalletRepo.kt | Added BackupRepo dependency and call to stop observing backups during wallet wipe |
| app/src/main/java/to/bitkit/data/backup/VssBackupClient.kt | Changed from BgDispatcher to IoDispatcher, simplified storeId retrieval in else branch |
| app/src/main/java/to/bitkit/di/DispatchersModule.kt | Removed @retention annotations from dispatcher qualifiers |
| app/src/main/java/to/bitkit/ext/DateTime.kt | Added nowMillis utility function that wraps Clock usage |
dcdb3a7 to
b0a344b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Fix issue where restoring wallet B from seed resulted in restoring the backup data of wallet A
Code Review - PR #458: Optimize backup & restore for performanceSummaryThis PR makes significant improvements to the backup and restore system with a focus on performance optimization and bug fixes. Overall, the changes are well-structured and address real issues. Below are my findings organized by category. ✅ Strengths
🔴 Critical Issues1. Race Condition in VssBackupClient.reset() (VssBackupClient.kt:65-69)Severity: HIGH The fun reset() {
isSetup = CompletableDeferred() // Not thread-safe
vssStoreIdProvider.clearCache()
Logger.debug("VSS client reset", context = TAG)
}Problem:
Impact: If Recommendation: fun reset() {
synchronized(this) {
val oldSetup = isSetup
isSetup = CompletableDeferred()
oldSetup.completeExceptionally(CancellationException("VSS client reset"))
}
vssStoreIdProvider.clearCache()
Logger.debug("VSS client reset", context = TAG)
}2. Missing Parameterless clearCache() in VssStoreIdProvider (VssBackupClient.kt:67)Severity: MEDIUM fun reset() {
isSetup = CompletableDeferred()
vssStoreIdProvider.clearCache() // ⚠️ This doesn't exist\!
Logger.debug("VSS client reset", context = TAG)
}Problem: Impact: In a multi-wallet scenario, resetting wallet 1 won't clear its VSS cache properly, potentially causing the bug this PR aims to fix. Recommendation: Either:
|
|
Fixed all relevant points from Claude's review 🚀 |
Code Review - PR #458: Optimize backup & restore for performanceSummaryThis PR delivers solid performance improvements and critical bug fixes for backup and restore operations. The changes are well-structured with good attention to race conditions and edge cases. Overall quality is high with a few areas for consideration. ✅ Strengths
🔍 Potential Issues1. Thread Safety Concern - VssBackupClient (Medium Priority)Location: fun reset() {
synchronized(this) {
isSetup.cancel()
isSetup = CompletableDeferred()
}
vssStoreIdProvider.clearCache() // ⚠️ Outside synchronized block
Logger.debug("VSS client reset", context = TAG)
}Issue: Recommendation: Move 2. Race Condition in Backup Scheduling (Low Priority)Location: The double-check pattern has a small race window:
Impact: Minor - just redundant state updates. Recommendation: Consider checking if (status.isRequired && !status.running && !isRestoring) {
triggerBackup(category)
}3. Inconsistent State Updates Order (Low Priority)Location: suspend fun wipeWallet(walletIndex: Int = 0): Result<Unit> = withContext(bgDispatcher) {
try {
backupRepo.reset() // Stops observers
_walletState.update { WalletState() } // Clears state
_balanceState.update { BalanceState() }
keychain.wipe() // Then wipes sensitive data
db.clearAllTables()
// ...Observation: State is cleared before keychain/DB. If someone observes Recommendation: Consider clearing state after wiping persistent storage, or document why this order is intentional. 🚀 Performance Considerations
Minor Suggestion: Consider adding metrics/logging for backup performance to track improvements in production. 🔒 Security Considerations
Note: The 🧪 Test CoverageUpdated Tests:
Missing Tests (Recommendations):
Test Quality: Existing tests properly updated. Consider adding integration tests for the backup/restore round-trip scenarios described in QA notes. 📝 Code Quality
Minor Suggestion: Consider extracting magic numbers to named constants:
🎯 RecommendationsHigh Priority
Medium Priority
Low Priority
📊 Overall AssessmentRating: Approve with minor suggestions ⭐⭐⭐⭐½ This is a high-quality PR that addresses real bugs and delivers meaningful performance improvements. The code is well-structured, the dispatcher change is correct, and the race condition fixes are important. The few concerns raised are mostly minor and could be addressed in follow-up improvements. The QA test plan is thorough and covers the critical scenarios. Great work on this optimization! Files Reviewed
|
ben-kaufman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK, code looks good to me
About tags, is android not using bitkit-core for saving tags?
Can repeat here what we discussed so it's out in the open: Android uses bitkit-core tags, but we also have tags for receive, which need to be persisted standalone and attached to the activity when someone pays that bip21. Receive tags are persisted until a tx actually comes in, then they're removed. |
This PR optimizes backup & restore performance while fixing several bugs.
Description
Performance Improvements
BgDispatchertoIoDispatcherfor backup operations (more appropriate for I/O-bound work)running = trueflag when scheduling backups to prevent false failure UI during debounce periodBug Fixes
syncedandrequiredtimestampsscheduleFullBackup()after wallet create>=instead of>for accurate backup statusRefactoring
isRequiredcomputed property@Retentionannotations from dispatcher DI qualifiersnowMillis()global helper0.1.23Preview
backupPerfOptimal.mp4
restoreBoost.mp4
QA Notes
1️⃣ Test backup status after restore
2️⃣ Test backup during wallet wipe
3️⃣ Regression - Backup & Restore roundtrip
4️⃣ Test reset wallet A & restore wallet B