Spin on failed sqlite initialization

This commit is contained in:
Ali 2023-10-27 16:15:49 +04:00
parent 019b4f45e8
commit 06a647c473
6 changed files with 54 additions and 20 deletions

View File

@ -136,6 +136,7 @@ private final class MediaBoxKeepResourceContext {
public final class MediaBox {
public let basePath: String
public let isMainProcess: Bool
private let statusQueue = Queue()
private let concurrentQueue = Queue.concurrentDefaultQueue()
@ -187,15 +188,16 @@ public final class MediaBox {
let _ = try? FileManager.default.createDirectory(atPath: self.basePath + "/short-cache", withIntermediateDirectories: true, attributes: nil)
}()
public init(basePath: String) {
public init(basePath: String, isMainProcess: Bool) {
self.basePath = basePath
self.isMainProcess = isMainProcess
self.storageBox = StorageBox(logger: StorageBox.Logger(impl: { string in
postboxLog(string)
}), basePath: basePath + "/storage")
}), basePath: basePath + "/storage", isMainProcess: isMainProcess)
self.cacheStorageBox = StorageBox(logger: StorageBox.Logger(impl: { string in
postboxLog(string)
}), basePath: basePath + "/cache-storage")
}), basePath: basePath + "/cache-storage", isMainProcess: isMainProcess)
self.timeBasedCleanup = TimeBasedCleanup(storageBox: self.storageBox, generalPaths: [
self.basePath + "/cache",

View File

@ -1368,7 +1368,7 @@ func debugRestoreState(basePath: String, name: String) {
}
}
public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, encryptionParameters: ValueBoxEncryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32, isTemporary: Bool, isReadOnly: Bool, useCopy: Bool, useCaches: Bool, removeDatabaseOnError: Bool) -> Signal<PostboxResult, NoError> {
public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, encryptionParameters: ValueBoxEncryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32, isMainProcess: Bool, isTemporary: Bool, isReadOnly: Bool, useCopy: Bool, useCaches: Bool, removeDatabaseOnError: Bool) -> Signal<PostboxResult, NoError> {
let queue = Postbox.sharedQueue
return Signal { subscriber in
queue.async {
@ -1496,7 +1496,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
let endTime = CFAbsoluteTimeGetCurrent()
postboxLog("Postbox load took \((endTime - startTime) * 1000.0) ms")
subscriber.putNext(.postbox(Postbox(queue: queue, basePath: basePath, seedConfiguration: seedConfiguration, valueBox: valueBox, timestampForAbsoluteTimeBasedOperations: timestampForAbsoluteTimeBasedOperations, isTemporary: isTemporary, tempDir: tempDir, useCaches: useCaches)))
subscriber.putNext(.postbox(Postbox(queue: queue, basePath: basePath, seedConfiguration: seedConfiguration, valueBox: valueBox, timestampForAbsoluteTimeBasedOperations: timestampForAbsoluteTimeBasedOperations, isMainProcess: isMainProcess, isTemporary: isTemporary, tempDir: tempDir, useCaches: useCaches)))
postboxLog("openPostbox, putCompletion")
@ -4168,6 +4168,7 @@ public class Postbox {
seedConfiguration: SeedConfiguration,
valueBox: SqliteValueBox,
timestampForAbsoluteTimeBasedOperations: Int32,
isMainProcess: Bool,
isTemporary: Bool,
tempDir: TempBoxDirectory?,
useCaches: Bool
@ -4177,7 +4178,7 @@ public class Postbox {
self.seedConfiguration = seedConfiguration
postboxLog("MediaBox path: \(basePath + "/media")")
self.mediaBox = MediaBox(basePath: basePath + "/media")
self.mediaBox = MediaBox(basePath: basePath + "/media", isMainProcess: isMainProcess)
let isInTransaction = self.isInTransaction

View File

@ -163,20 +163,37 @@ public final class StorageBox {
private var queuedInternalTransactions = Atomic<[() -> Void]>(value: [])
init(queue: Queue, logger: StorageBox.Logger, basePath: String) {
init(queue: Queue, logger: StorageBox.Logger, basePath: String, isMainProcess: Bool) {
self.queue = queue
self.logger = logger
self.basePath = basePath
let databasePath = self.basePath + "/db"
let _ = try? FileManager.default.createDirectory(atPath: databasePath, withIntermediateDirectories: true)
var valueBox = SqliteValueBox(basePath: databasePath, queue: queue, isTemporary: false, isReadOnly: false, useCaches: true, removeDatabaseOnError: true, encryptionParameters: nil, upgradeProgress: { _ in })
if valueBox == nil {
let _ = try? FileManager.default.removeItem(atPath: databasePath)
valueBox = SqliteValueBox(basePath: databasePath, queue: queue, isTemporary: false, isReadOnly: false, useCaches: true, removeDatabaseOnError: true, encryptionParameters: nil, upgradeProgress: { _ in })
var valueBox: SqliteValueBox?
for i in 0 ..< 3 {
if let valueBoxValue = SqliteValueBox(basePath: basePath + "/db", queue: queue, isTemporary: false, isReadOnly: false, useCaches: isMainProcess, removeDatabaseOnError: isMainProcess, encryptionParameters: nil, upgradeProgress: { _ in }) {
valueBox = valueBoxValue
break
} else {
postboxLog("Could not open value box at \(basePath + "/db") (try \(i))")
postboxLogSync()
Thread.sleep(forTimeInterval: 0.1 + 0.5 * Double(i))
}
}
guard let valueBox = valueBox else {
preconditionFailure("Could not open database")
if valueBox == nil, isMainProcess {
postboxLog("Removing value box at \(basePath + "/db")")
let _ = try? FileManager.default.removeItem(atPath: databasePath)
valueBox = SqliteValueBox(basePath: databasePath, queue: queue, isTemporary: false, isReadOnly: false, useCaches: isMainProcess, removeDatabaseOnError: isMainProcess, encryptionParameters: nil, upgradeProgress: { _ in })
}
guard let valueBox else {
postboxLog("Giving up on opening value box at \(basePath + "/db")")
postboxLogSync()
preconditionFailure()
}
self.valueBox = valueBox
@ -1025,11 +1042,11 @@ public final class StorageBox {
private let queue: Queue
private let impl: QueueLocalObject<Impl>
public init(logger: StorageBox.Logger, basePath: String) {
public init(logger: StorageBox.Logger, basePath: String, isMainProcess: Bool) {
let queue = StorageBox.sharedQueue
self.queue = queue
self.impl = QueueLocalObject(queue: queue, generate: {
return Impl(queue: queue, logger: logger, basePath: basePath)
return Impl(queue: queue, logger: logger, basePath: basePath, isMainProcess: isMainProcess)
})
}

View File

@ -183,6 +183,7 @@ public func accountWithId(accountManager: AccountManager<TelegramAccountManagerT
seedConfiguration: telegramPostboxSeedConfiguration,
encryptionParameters: encryptionParameters,
timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970),
isMainProcess: !supplementary,
isTemporary: false,
isReadOnly: false,
useCopy: false,
@ -1445,6 +1446,7 @@ public func standaloneStateManager(
seedConfiguration: telegramPostboxSeedConfiguration,
encryptionParameters: encryptionParameters,
timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970),
isMainProcess: false,
isTemporary: false,
isReadOnly: false,
useCopy: false,

View File

@ -92,11 +92,23 @@ final class AccountManagerImpl<Types: AccountManagerTypes> {
return nil
}
self.guardValueBox = guardValueBox
guard let valueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, useCaches: useCaches, removeDatabaseOnError: removeDatabaseOnError, encryptionParameters: nil, upgradeProgress: { _ in }) else {
postboxLog("Could not open value box at \(basePath + "/db")")
var valueBox: SqliteValueBox?
for i in 0 ..< 3 {
if let valueBoxValue = SqliteValueBox(basePath: basePath + "/db", queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, useCaches: useCaches, removeDatabaseOnError: removeDatabaseOnError, encryptionParameters: nil, upgradeProgress: { _ in }) {
valueBox = valueBoxValue
break
} else {
postboxLog("Could not open value box at \(basePath + "/db") (try \(i))")
postboxLogSync()
Thread.sleep(forTimeInterval: 0.1 + 0.5 * Double(i))
}
}
guard let valueBox else {
postboxLog("Giving up on opening value box at \(basePath + "/db")")
postboxLogSync()
preconditionFailure()
return nil
}
self.valueBox = valueBox
@ -537,7 +549,7 @@ public final class AccountManager<Types: AccountManagerTypes> {
preconditionFailure()
}
})
self.mediaBox = MediaBox(basePath: basePath + "/media")
self.mediaBox = MediaBox(basePath: basePath + "/media", isMainProcess: removeDatabaseOnError)
}
public func transaction<T>(ignoreDisabled: Bool = false, _ f: @escaping (AccountManagerModifier<Types>) -> T) -> Signal<T, NoError> {

View File

@ -172,7 +172,7 @@ public enum AccountTransactionError {
public func accountTransaction<T>(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, isReadOnly: Bool, useCopy: Bool = false, useCaches: Bool = true, removeDatabaseOnError: Bool = true, transaction: @escaping (Postbox, Transaction) -> T) -> Signal<T, AccountTransactionError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true, isReadOnly: isReadOnly, useCopy: useCopy, useCaches: useCaches, removeDatabaseOnError: removeDatabaseOnError)
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isMainProcess: false, isTemporary: true, isReadOnly: isReadOnly, useCopy: useCopy, useCaches: useCaches, removeDatabaseOnError: removeDatabaseOnError)
return postbox
|> castError(AccountTransactionError.self)
|> mapToSignal { value -> Signal<T, AccountTransactionError> in