Improved progress display
Previously, the progress bar updated only after completing an entire table. For large tables such as LIBARC, this could make the application appear to have stopped responding. Phase 10 updates the interface while rows are being exported.
This commit is contained in:
@@ -1569,6 +1569,9 @@ struct WorkbenchDatabaseTransferView: View {
|
||||
@State private var database = ""
|
||||
@State private var isWorking = false
|
||||
@State private var progress = 0.0
|
||||
@State private var transferredRows: Int64 = 0
|
||||
@State private var currentTableRows: Int64 = 0
|
||||
@State private var currentTableExpected: Int64 = 0
|
||||
@State private var status = "Ready"
|
||||
@State private var operationTask: Task<Void, Never>?
|
||||
@State private var showingImportConfirmation = false
|
||||
@@ -1707,6 +1710,12 @@ struct WorkbenchDatabaseTransferView: View {
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.textSelection(.enabled)
|
||||
if isWorking && selectedMode == 0 && currentTableExpected > 0 {
|
||||
ProgressView(value: Double(currentTableRows), total: Double(currentTableExpected))
|
||||
Text("Current table: \(currentTableRows.formatted()) / \(currentTableExpected.formatted()) rows · Total exported: \(transferredRows.formatted())")
|
||||
.font(.caption.monospacedDigit())
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1975,6 +1984,9 @@ struct WorkbenchDatabaseTransferView: View {
|
||||
exportSession = dedicatedProfile
|
||||
isWorking = true
|
||||
progress = 0
|
||||
transferredRows = 0
|
||||
currentTableRows = 0
|
||||
currentTableExpected = 0
|
||||
let tables = availableTables.filter { selectedTables.contains($0) }
|
||||
let tempURL = url.deletingLastPathComponent().appendingPathComponent(".\(UUID().uuidString).sql.tmp")
|
||||
var handle: FileHandle?
|
||||
@@ -2090,12 +2102,18 @@ struct WorkbenchDatabaseTransferView: View {
|
||||
let expectedCount = Int64(countText) else {
|
||||
throw WorkbenchTransferError.message("Cannot count rows in \(table)")
|
||||
}
|
||||
currentTableRows = 0
|
||||
currentTableExpected = expectedCount
|
||||
try write("-- Streamed snapshot: \(expectedCount) rows; order: \(usableIndex ?? "server scan")\n")
|
||||
let select = "SELECT CONCAT('(', CONCAT_WS(',', \(expressions)), ')') FROM \(qualified)" +
|
||||
(orderBy.map { " ORDER BY " + $0 } ?? "")
|
||||
let outputHandle = handle!
|
||||
let prefix = Data("INSERT INTO \(qualified) (\(names)) VALUES ".utf8)
|
||||
let suffix = Data(";\n".utf8)
|
||||
let completedBeforeTable = transferredRows
|
||||
let completedTables = index
|
||||
let totalUnits = max(tables.count + views.count, 1)
|
||||
var streamedInTable: Int64 = 0
|
||||
let written = try await NativeMySQLRunner.stream(
|
||||
profile: dedicatedProfile,
|
||||
database: database,
|
||||
@@ -2105,7 +2123,21 @@ struct WorkbenchDatabaseTransferView: View {
|
||||
try outputHandle.write(contentsOf: prefix)
|
||||
try outputHandle.write(contentsOf: Data(literal.utf8))
|
||||
try outputHandle.write(contentsOf: suffix)
|
||||
streamedInTable += 1
|
||||
if streamedInTable % 500 == 0 || streamedInTable == expectedCount {
|
||||
let completed = streamedInTable
|
||||
DispatchQueue.main.async {
|
||||
currentTableRows = completed
|
||||
transferredRows = completedBeforeTable + completed
|
||||
progress = (Double(completedTables) +
|
||||
Double(completed) / Double(max(expectedCount, 1))) /
|
||||
Double(totalUnits)
|
||||
status = "Exporting \(table): \(completed.formatted()) / \(expectedCount.formatted()) rows"
|
||||
}
|
||||
}
|
||||
}
|
||||
currentTableRows = written
|
||||
transferredRows = completedBeforeTable + written
|
||||
guard written == expectedCount else {
|
||||
throw WorkbenchTransferError.message(
|
||||
"Table \(table): expected \(expectedCount) rows, streamed \(written). Backup discarded."
|
||||
@@ -2113,6 +2145,8 @@ struct WorkbenchDatabaseTransferView: View {
|
||||
}
|
||||
status = "Exported \(table): \(written) rows"
|
||||
}
|
||||
currentTableExpected = 0
|
||||
currentTableRows = 0
|
||||
progress = Double(index + 1) / Double(max(tables.count + views.count, 1))
|
||||
}
|
||||
// Views are exported after base tables so dependencies exist on restore.
|
||||
@@ -2199,7 +2233,7 @@ struct WorkbenchDatabaseTransferView: View {
|
||||
do {
|
||||
try WorkbenchBackupIntegrity.createSidecar(for: url)
|
||||
progress = 1
|
||||
status = "Export complete and SHA-256 verified: \(tables.count) tables, \(views.count) views"
|
||||
status = "Export complete and SHA-256 verified: \(tables.count) tables, \(views.count) views, \(transferredRows.formatted()) rows"
|
||||
} catch {
|
||||
progress = 1
|
||||
status = "SQL export complete, but checksum creation failed: \(error.localizedDescription)"
|
||||
|
||||
Reference in New Issue
Block a user