Merge pull request #3732 from danieldaquino/gh-3726-b
Report Compaction Progress and Improve UI
This commit is contained in:
@@ -24,19 +24,45 @@ struct CompactionView: View {
|
|||||||
let keypair: Keypair
|
let keypair: Keypair
|
||||||
let appDelegate: AppDelegate?
|
let appDelegate: AppDelegate?
|
||||||
|
|
||||||
@State private var isCompacting: Bool = false
|
/// The current state of the startup compaction flow.
|
||||||
@State private var compactionComplete: Bool = false
|
enum CompactionState {
|
||||||
@State private var compactionError: String? = nil
|
case idle
|
||||||
|
case compacting(progress: Double, stepTitle: String, stepDetail: String)
|
||||||
|
case failed(error: String)
|
||||||
|
case complete
|
||||||
|
|
||||||
|
/// The initial visible state shown when compaction begins.
|
||||||
|
static var initialCompactingState: CompactionState {
|
||||||
|
return .compacting(
|
||||||
|
progress: 0.05,
|
||||||
|
stepTitle: NSLocalizedString("Preparing database compaction", comment: "Initial title shown during database compaction"),
|
||||||
|
stepDetail: NSLocalizedString("Checking the database and getting everything ready.", comment: "Initial detail shown during database compaction")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@State private var compactionState: CompactionState = .idle
|
||||||
@State private var hasStartedCompactionFlow: Bool = false
|
@State private var hasStartedCompactionFlow: Bool = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
Group {
|
||||||
if compactionComplete {
|
switch compactionState {
|
||||||
|
case .complete:
|
||||||
ContentView(keypair: keypair, appDelegate: appDelegate)
|
ContentView(keypair: keypair, appDelegate: appDelegate)
|
||||||
} else {
|
|
||||||
|
case .idle:
|
||||||
CompactionLoadingView(
|
CompactionLoadingView(
|
||||||
isCompacting: isCompacting,
|
state: .compacting(
|
||||||
error: compactionError,
|
progress: 0.0,
|
||||||
|
stepTitle: NSLocalizedString("Preparing database compaction", comment: "Title shown before database compaction starts"),
|
||||||
|
stepDetail: NSLocalizedString("Checking whether database optimization is needed.", comment: "Detail shown before database compaction starts")
|
||||||
|
),
|
||||||
|
continueAfterError: continueAfterError
|
||||||
|
)
|
||||||
|
|
||||||
|
case .compacting, .failed:
|
||||||
|
CompactionLoadingView(
|
||||||
|
state: compactionState,
|
||||||
continueAfterError: continueAfterError
|
continueAfterError: continueAfterError
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -60,24 +86,32 @@ struct CompactionView: View {
|
|||||||
|
|
||||||
let needsCompaction = UserDefaults.standard.bool(forKey: Ndb.compact_on_next_launch_key)
|
let needsCompaction = UserDefaults.standard.bool(forKey: Ndb.compact_on_next_launch_key)
|
||||||
guard needsCompaction else {
|
guard needsCompaction else {
|
||||||
compactionComplete = true
|
compactionState = .complete
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
isCompacting = true
|
compactionState = CompactionState.initialCompactingState
|
||||||
|
|
||||||
Task.detached(priority: .userInitiated) {
|
Task.detached(priority: .userInitiated) {
|
||||||
do {
|
do {
|
||||||
try Ndb.compact_if_needed()
|
try Ndb.compact_if_needed(
|
||||||
|
progress: { progress in
|
||||||
|
Task { @MainActor in
|
||||||
|
compactionState = .compacting(
|
||||||
|
progress: progress.fractionCompleted,
|
||||||
|
stepTitle: progress.step.title,
|
||||||
|
stepDetail: progress.step.detail
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
isCompacting = false
|
compactionState = .complete
|
||||||
compactionComplete = true
|
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
isCompacting = false
|
compactionState = .failed(error: error.localizedDescription)
|
||||||
compactionError = error.localizedDescription
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,7 +119,7 @@ struct CompactionView: View {
|
|||||||
|
|
||||||
/// Continues to the main content after the user acknowledges a compaction error.
|
/// Continues to the main content after the user acknowledges a compaction error.
|
||||||
private func continueAfterError() {
|
private func continueAfterError() {
|
||||||
compactionComplete = true
|
compactionState = .complete
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,43 +128,106 @@ struct CompactionView: View {
|
|||||||
/// Shows a spinner and informative text to the user while the compaction process runs.
|
/// Shows a spinner and informative text to the user while the compaction process runs.
|
||||||
/// If compaction fails, it shows the error and requires explicit acknowledgement before continuing.
|
/// If compaction fails, it shows the error and requires explicit acknowledgement before continuing.
|
||||||
struct CompactionLoadingView: View {
|
struct CompactionLoadingView: View {
|
||||||
let isCompacting: Bool
|
let state: CompactionView.CompactionState
|
||||||
let error: String?
|
|
||||||
let continueAfterError: () -> Void
|
let continueAfterError: () -> Void
|
||||||
|
|
||||||
|
/// A percentage label for the current compaction progress.
|
||||||
|
private var progressPercentageText: String? {
|
||||||
|
guard case .compacting(let progress, _, _) = state else { return nil }
|
||||||
|
|
||||||
|
let percentage = Int((progress * 100).rounded())
|
||||||
|
return String(
|
||||||
|
format: NSLocalizedString("%d%% complete", comment: "Accessibility and status label showing database compaction progress percentage"),
|
||||||
|
percentage
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
Color(uiColor: .systemBackground)
|
LinearGradient(
|
||||||
|
colors: [
|
||||||
|
Color(uiColor: .systemBackground),
|
||||||
|
Color.accentColor.opacity(0.08)
|
||||||
|
],
|
||||||
|
startPoint: .top,
|
||||||
|
endPoint: .bottom
|
||||||
|
)
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
|
||||||
VStack(spacing: 20) {
|
VStack(spacing: 28) {
|
||||||
|
VStack(spacing: 16) {
|
||||||
Image("icon")
|
Image("icon")
|
||||||
.resizable()
|
.resizable()
|
||||||
.frame(width: 80, height: 80)
|
.frame(width: 88, height: 88)
|
||||||
.cornerRadius(16)
|
.cornerRadius(20)
|
||||||
|
.shadow(color: .black.opacity(0.08), radius: 12, y: 6)
|
||||||
if isCompacting {
|
|
||||||
ProgressView()
|
|
||||||
.scaleEffect(1.5)
|
|
||||||
.padding()
|
|
||||||
|
|
||||||
Text("Optimizing Database", comment: "Title shown during database compaction")
|
Text("Optimizing Database", comment: "Title shown during database compaction")
|
||||||
|
.font(.title2.weight(.semibold))
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
|
||||||
|
if let progressPercentageText {
|
||||||
|
Text(progressPercentageText)
|
||||||
|
.font(.caption.weight(.semibold))
|
||||||
|
.foregroundColor(.accentColor)
|
||||||
|
.padding(.horizontal, 10)
|
||||||
|
.padding(.vertical, 6)
|
||||||
|
.background(
|
||||||
|
Capsule()
|
||||||
|
.fill(Color.accentColor.opacity(0.12))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch state {
|
||||||
|
case .idle, .complete:
|
||||||
|
EmptyView()
|
||||||
|
|
||||||
|
case .compacting(let progress, let stepTitle, let stepDetail):
|
||||||
|
VStack(spacing: 20) {
|
||||||
|
ProgressView(value: progress, total: 1.0)
|
||||||
|
.progressViewStyle(.linear)
|
||||||
|
.tint(.accentColor)
|
||||||
|
.scaleEffect(x: 1, y: 1.4, anchor: .center)
|
||||||
|
|
||||||
|
VStack(alignment: .leading, spacing: 14) {
|
||||||
|
Text(stepTitle)
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
.foregroundColor(.primary)
|
.foregroundColor(.primary)
|
||||||
|
|
||||||
Text("This may take a moment…", comment: "Subtitle shown during database compaction")
|
Text(stepDetail)
|
||||||
.font(.subheadline)
|
.font(.subheadline)
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
|
.multilineTextAlignment(.leading)
|
||||||
|
}
|
||||||
|
.padding(20)
|
||||||
|
.frame(maxWidth: 420, alignment: .leading)
|
||||||
|
.background(
|
||||||
|
RoundedRectangle(cornerRadius: 24, style: .continuous)
|
||||||
|
.fill(Color(uiColor: .secondarySystemBackground))
|
||||||
|
)
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 24, style: .continuous)
|
||||||
|
.stroke(Color.primary.opacity(0.06), lineWidth: 1)
|
||||||
|
)
|
||||||
|
|
||||||
|
Label(
|
||||||
|
NSLocalizedString("This can take a few minutes. Please keep the app open.", comment: "Subtitle shown during long-running database compaction"),
|
||||||
|
systemImage: "clock"
|
||||||
|
)
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
.padding(.horizontal)
|
.frame(maxWidth: 420)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let error {
|
case .failed(let error):
|
||||||
VStack(spacing: 12) {
|
VStack(spacing: 16) {
|
||||||
Image(systemName: "exclamationmark.triangle")
|
Image(systemName: "exclamationmark.triangle.fill")
|
||||||
.font(.system(size: 40))
|
.font(.system(size: 42))
|
||||||
.foregroundColor(.orange)
|
.foregroundColor(.orange)
|
||||||
|
|
||||||
|
VStack(spacing: 8) {
|
||||||
Text("Compaction Warning", comment: "Title shown when database compaction encounters an error")
|
Text("Compaction Warning", comment: "Title shown when database compaction encounters an error")
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
.foregroundColor(.primary)
|
.foregroundColor(.primary)
|
||||||
@@ -139,41 +236,52 @@ struct CompactionLoadingView: View {
|
|||||||
.font(.subheadline)
|
.font(.subheadline)
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
.padding(.horizontal)
|
|
||||||
|
|
||||||
Text("The app can continue, but some storage may not have been freed.", comment: "Message shown when compaction fails but app can continue after acknowledgement")
|
Text("The app can continue, but some storage may not have been freed.", comment: "Message shown when compaction fails but app can continue after acknowledgement")
|
||||||
.font(.caption)
|
.font(.footnote)
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
.padding(.horizontal)
|
}
|
||||||
|
|
||||||
Button(action: continueAfterError) {
|
Button(action: continueAfterError) {
|
||||||
Text("Continue", comment: "Button title used to continue into the app after acknowledging a compaction error")
|
Text("Continue", comment: "Button title used to continue into the app after acknowledging a compaction error")
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
}
|
}
|
||||||
.buttonStyle(.borderedProminent)
|
.buttonStyle(.borderedProminent)
|
||||||
.padding(.top, 8)
|
.padding(.top, 4)
|
||||||
.padding(.horizontal)
|
}
|
||||||
|
.padding(20)
|
||||||
|
.frame(maxWidth: 420)
|
||||||
|
.background(
|
||||||
|
RoundedRectangle(cornerRadius: 24, style: .continuous)
|
||||||
|
.fill(Color(uiColor: .secondarySystemBackground))
|
||||||
|
)
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 24, style: .continuous)
|
||||||
|
.stroke(Color.orange.opacity(0.2), lineWidth: 1)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
.padding(.horizontal, 24)
|
||||||
.padding()
|
.padding(.vertical, 32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
CompactionLoadingView(
|
CompactionLoadingView(
|
||||||
isCompacting: true,
|
state: CompactionView.CompactionState.compacting(
|
||||||
error: nil,
|
progress: 0.55,
|
||||||
|
stepTitle: "Creating compacted snapshot",
|
||||||
|
stepDetail: "Copying data into a smaller optimized database file. This is usually the longest step."
|
||||||
|
),
|
||||||
continueAfterError: {}
|
continueAfterError: {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview("With Error") {
|
#Preview("With Error") {
|
||||||
CompactionLoadingView(
|
CompactionLoadingView(
|
||||||
isCompacting: false,
|
state: CompactionView.CompactionState.failed(error: "Failed to compact database"),
|
||||||
error: "Failed to compact database",
|
|
||||||
continueAfterError: {}
|
continueAfterError: {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,84 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
/// A progress update emitted while database compaction advances through its major stages.
|
||||||
|
struct NdbCompactionProgress: Equatable {
|
||||||
|
/// A stable identifier for the current compaction stage.
|
||||||
|
enum Step: Int, CaseIterable, Equatable {
|
||||||
|
case preparing
|
||||||
|
case creatingTempDirectory
|
||||||
|
case openingDatabase
|
||||||
|
case creatingSnapshot
|
||||||
|
case validatingSnapshot
|
||||||
|
case replacingDatabase
|
||||||
|
case cleaningUp
|
||||||
|
case completed
|
||||||
|
|
||||||
|
/// The user-facing title for the current stage.
|
||||||
|
var title: String {
|
||||||
|
switch self {
|
||||||
|
case .preparing:
|
||||||
|
return NSLocalizedString("Preparing database compaction", comment: "Compaction progress stage title")
|
||||||
|
case .creatingTempDirectory:
|
||||||
|
return NSLocalizedString("Creating temporary workspace", comment: "Compaction progress stage title")
|
||||||
|
case .openingDatabase:
|
||||||
|
return NSLocalizedString("Opening database", comment: "Compaction progress stage title")
|
||||||
|
case .creatingSnapshot:
|
||||||
|
return NSLocalizedString("Creating compacted snapshot", comment: "Compaction progress stage title")
|
||||||
|
case .validatingSnapshot:
|
||||||
|
return NSLocalizedString("Validating compacted database", comment: "Compaction progress stage title")
|
||||||
|
case .replacingDatabase:
|
||||||
|
return NSLocalizedString("Replacing database files", comment: "Compaction progress stage title")
|
||||||
|
case .cleaningUp:
|
||||||
|
return NSLocalizedString("Cleaning up temporary files", comment: "Compaction progress stage title")
|
||||||
|
case .completed:
|
||||||
|
return NSLocalizedString("Finishing up", comment: "Compaction progress stage title")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A short user-facing description for the current stage.
|
||||||
|
var detail: String {
|
||||||
|
switch self {
|
||||||
|
case .preparing:
|
||||||
|
return NSLocalizedString("Checking the database and getting everything ready.", comment: "Compaction progress stage detail")
|
||||||
|
case .creatingTempDirectory:
|
||||||
|
return NSLocalizedString("Setting up a temporary location for the compacted copy.", comment: "Compaction progress stage detail")
|
||||||
|
case .openingDatabase:
|
||||||
|
return NSLocalizedString("Opening the existing database safely in the background.", comment: "Compaction progress stage detail")
|
||||||
|
case .creatingSnapshot:
|
||||||
|
return NSLocalizedString("Copying data into a smaller optimized database file. This is usually the longest step.", comment: "Compaction progress stage detail")
|
||||||
|
case .validatingSnapshot:
|
||||||
|
return NSLocalizedString("Making sure the compacted database looks valid before replacing the original.", comment: "Compaction progress stage detail")
|
||||||
|
case .replacingDatabase:
|
||||||
|
return NSLocalizedString("Swapping in the optimized database files.", comment: "Compaction progress stage detail")
|
||||||
|
case .cleaningUp:
|
||||||
|
return NSLocalizedString("Removing temporary files and recording completion.", comment: "Compaction progress stage detail")
|
||||||
|
case .completed:
|
||||||
|
return NSLocalizedString("Database optimization is complete.", comment: "Compaction progress stage detail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The zero-based index of the step in the overall compaction flow.
|
||||||
|
var index: Int {
|
||||||
|
return Self.allCases.firstIndex(of: self) ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The total number of steps in the overall compaction flow.
|
||||||
|
static var totalCount: Int {
|
||||||
|
return Self.allCases.count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The current compaction stage.
|
||||||
|
let step: Step
|
||||||
|
|
||||||
|
/// The fraction completed for the overall compaction flow.
|
||||||
|
var fractionCompleted: Double {
|
||||||
|
guard Step.totalCount > 1 else { return 1.0 }
|
||||||
|
return Double(step.index) / Double(Step.totalCount - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Defines how often the database should be automatically compacted.
|
/// Defines how often the database should be automatically compacted.
|
||||||
enum AutoCompactSchedule: String, CaseIterable, Equatable {
|
enum AutoCompactSchedule: String, CaseIterable, Equatable {
|
||||||
case daily
|
case daily
|
||||||
@@ -162,12 +240,19 @@ extension Ndb {
|
|||||||
/// 5. Remove the temp directory.
|
/// 5. Remove the temp directory.
|
||||||
/// 6. Clear the flag so compaction does not run again on the following launch.
|
/// 6. Clear the flag so compaction does not run again on the following launch.
|
||||||
///
|
///
|
||||||
/// - Parameter db_path: Override the database directory path. Pass `nil` (default) to use
|
/// - Parameters:
|
||||||
|
/// - db_path: Override the database directory path. Pass `nil` (default) to use
|
||||||
/// `Ndb.db_path`. Mainly useful for testing.
|
/// `Ndb.db_path`. Mainly useful for testing.
|
||||||
|
/// - progress: An optional callback invoked as the compaction advances through major stages.
|
||||||
/// - Throws: `CompactionError` when compaction was requested but could not be completed.
|
/// - Throws: `CompactionError` when compaction was requested but could not be completed.
|
||||||
static func compact_if_needed(db_path: String? = nil) throws {
|
static func compact_if_needed(
|
||||||
|
db_path: String? = nil,
|
||||||
|
progress: ((NdbCompactionProgress) -> Void)? = nil
|
||||||
|
) throws {
|
||||||
guard UserDefaults.standard.bool(forKey: compact_on_next_launch_key) else { return }
|
guard UserDefaults.standard.bool(forKey: compact_on_next_launch_key) else { return }
|
||||||
|
|
||||||
|
progress?(.init(step: .preparing))
|
||||||
|
|
||||||
guard let path = db_path ?? Self.db_path else {
|
guard let path = db_path ?? Self.db_path else {
|
||||||
Log.error("compact_if_needed: could not determine db path", for: .storage)
|
Log.error("compact_if_needed: could not determine db path", for: .storage)
|
||||||
throw CompactionError.missingDatabasePath
|
throw CompactionError.missingDatabasePath
|
||||||
@@ -176,6 +261,7 @@ extension Ndb {
|
|||||||
guard db_file_exists(path: path) else {
|
guard db_file_exists(path: path) else {
|
||||||
// No database file present yet; nothing to compact — just clear the flag.
|
// No database file present yet; nothing to compact — just clear the flag.
|
||||||
UserDefaults.standard.set(false, forKey: compact_on_next_launch_key)
|
UserDefaults.standard.set(false, forKey: compact_on_next_launch_key)
|
||||||
|
progress?(.init(step: .completed))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,6 +272,8 @@ extension Ndb {
|
|||||||
// Clean up any leftover temp directory from a previously failed attempt.
|
// Clean up any leftover temp directory from a previously failed attempt.
|
||||||
try? FileManager.default.removeItem(atPath: tempPath)
|
try? FileManager.default.removeItem(atPath: tempPath)
|
||||||
|
|
||||||
|
progress?(.init(step: .creatingTempDirectory))
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try FileManager.default.createDirectory(atPath: tempPath, withIntermediateDirectories: true)
|
try FileManager.default.createDirectory(atPath: tempPath, withIntermediateDirectories: true)
|
||||||
} catch {
|
} catch {
|
||||||
@@ -193,6 +281,8 @@ extension Ndb {
|
|||||||
throw CompactionError.createTempDirectoryFailed(underlyingError: error)
|
throw CompactionError.createTempDirectoryFailed(underlyingError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
progress?(.init(step: .openingDatabase))
|
||||||
|
|
||||||
// Open a temporary Ndb instance just to drive the compaction.
|
// Open a temporary Ndb instance just to drive the compaction.
|
||||||
guard let tempNdb = Ndb(path: path) else {
|
guard let tempNdb = Ndb(path: path) else {
|
||||||
Log.error("compact_if_needed: failed to open ndb for compaction", for: .storage)
|
Log.error("compact_if_needed: failed to open ndb for compaction", for: .storage)
|
||||||
@@ -202,6 +292,8 @@ extension Ndb {
|
|||||||
// Ensure the temporary Ndb is closed regardless of how this function exits.
|
// Ensure the temporary Ndb is closed regardless of how this function exits.
|
||||||
defer { tempNdb.close() }
|
defer { tempNdb.close() }
|
||||||
|
|
||||||
|
progress?(.init(step: .creatingSnapshot))
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try tempNdb.compact(to: tempPath)
|
try tempNdb.compact(to: tempPath)
|
||||||
} catch {
|
} catch {
|
||||||
@@ -212,6 +304,8 @@ extension Ndb {
|
|||||||
|
|
||||||
tempNdb.close()
|
tempNdb.close()
|
||||||
|
|
||||||
|
progress?(.init(step: .validatingSnapshot))
|
||||||
|
|
||||||
// Atomically replace the original data.mdb with the compacted copy.
|
// Atomically replace the original data.mdb with the compacted copy.
|
||||||
let originalDataMdb = URL(fileURLWithPath: "\(path)/\(main_db_file_name)")
|
let originalDataMdb = URL(fileURLWithPath: "\(path)/\(main_db_file_name)")
|
||||||
let compactedDataMdb = URL(fileURLWithPath: "\(tempPath)/\(main_db_file_name)")
|
let compactedDataMdb = URL(fileURLWithPath: "\(tempPath)/\(main_db_file_name)")
|
||||||
@@ -227,6 +321,8 @@ extension Ndb {
|
|||||||
throw CompactionError.compactedFileMissingOrEmpty(path: compactedDataMdb.path)
|
throw CompactionError.compactedFileMissingOrEmpty(path: compactedDataMdb.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
progress?(.init(step: .replacingDatabase))
|
||||||
|
|
||||||
// Delete the stale lock.mdb BEFORE replacing data.mdb.
|
// Delete the stale lock.mdb BEFORE replacing data.mdb.
|
||||||
// The temp Ndb wrote reader-table / txn state into lock.mdb that references
|
// The temp Ndb wrote reader-table / txn state into lock.mdb that references
|
||||||
// pages in the old data.mdb. After data.mdb is replaced with the smaller
|
// pages in the old data.mdb. After data.mdb is replaced with the smaller
|
||||||
@@ -256,6 +352,8 @@ extension Ndb {
|
|||||||
throw CompactionError.postReplaceSizeMismatch(expected: compactedSize, actual: finalSize)
|
throw CompactionError.postReplaceSizeMismatch(expected: compactedSize, actual: finalSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
progress?(.init(step: .cleaningUp))
|
||||||
|
|
||||||
Log.info("NostrDB compacted successfully", for: .storage)
|
Log.info("NostrDB compacted successfully", for: .storage)
|
||||||
|
|
||||||
// Clean up the temp directory (any remaining files such as lock.mdb).
|
// Clean up the temp directory (any remaining files such as lock.mdb).
|
||||||
@@ -266,5 +364,7 @@ extension Ndb {
|
|||||||
|
|
||||||
// Clear the flag so we don't compact again on the next launch.
|
// Clear the flag so we don't compact again on the next launch.
|
||||||
UserDefaults.standard.set(false, forKey: compact_on_next_launch_key)
|
UserDefaults.standard.set(false, forKey: compact_on_next_launch_key)
|
||||||
|
|
||||||
|
progress?(.init(step: .completed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user