/// <inheritdoc /> public async Task TryRepairDatabase(ProfilerThread Thread) { if (await this.uiDispatcher.DisplayAlert(AppResources.DatabaseIssue, AppResources.DatabaseCorruptInfoText, AppResources.RepairAndContinue, AppResources.ContinueAnyway)) { string method = "Delete database file(s) and create new empty database"; try { Thread?.NewState("Delete"); // 3. Delete and create a new empty database Directory.Delete(dataFolder, true); Thread?.NewState("Recreate"); this.databaseProvider = await CreateDatabaseFile(); Thread?.NewState("Repair3"); await this.databaseProvider.RepairIfInproperShutdown(string.Empty); // If we had to repair, we must register the provider 'again', as one hasn't been provided yet. if (!Database.HasProvider) { method = $"{nameof(Database)}.{nameof(Database.Register)}"; Database.Register(databaseProvider, false); } // All is good. this.SetState(StorageState.Ready); } catch (Exception e3) { e3 = Log.UnnestException(e3); Thread?.Exception(e3); // Delete and create new failed. We're out of options. this.logService.LogException(e3, this.GetClassAndMethod(MethodBase.GetCurrentMethod(), method)); Thread?.NewState("DisplayAlert2"); await this.uiDispatcher.DisplayAlert(AppResources.DatabaseIssue, AppResources.DatabaseRepairFailedInfoText, AppResources.Ok); } } }
private async Task PerformStartup(bool isResuming) { ProfilerThread thread = this.startupProfiler?.MainThread.CreateSubThread("AppStartup", ProfilerThreadType.Sequential); thread?.Start(); try { thread?.NewState("Report"); await this.SendErrorReportFromPreviousRun(); thread?.NewState("Startup"); ProfilerThread sdkStartupThread = this.startupProfiler?.CreateThread("SdkStartup", ProfilerThreadType.Sequential); sdkStartupThread?.Start(); sdkStartupThread?.NewState("DB"); this.sdk.UiDispatcher.IsRunningInTheBackground = false; // Start the db. // This is for soft restarts. // If this is a cold start, this call is made already in the App ctor, and this is then a no-op. this.sdk.StorageService.Init(sdkStartupThread); StorageState dbState = await this.sdk.StorageService.WaitForReadyState(); if (dbState == StorageState.NeedsRepair) { await this.sdk.StorageService.TryRepairDatabase(sdkStartupThread); } if (!isResuming) { await this.CreateOrRestoreConfiguration(); } sdkStartupThread?.NewState("Network"); await this.sdk.NetworkService.Load(isResuming); sdkStartupThread?.NewState("Load"); await this.sdk.NeuronService.Load(isResuming); sdkStartupThread?.NewState("Timer"); TimeSpan initialAutoSaveDelay = Constants.Intervals.AutoSave.Multiply(4); this.autoSaveTimer = new Timer(async _ => await AutoSave(), null, initialAutoSaveDelay, Constants.Intervals.AutoSave); sdkStartupThread?.Stop(); thread?.NewState("Navigation"); await this.sdk.NavigationService.Load(isResuming); thread?.NewState("Cache"); await this.imageCacheService.Load(isResuming); thread?.NewState("Orchestrators"); await this.contractOrchestratorService.Load(isResuming); await this.thingRegistryOrchestratorService.Load(isResuming); } catch (Exception e) { e = Waher.Events.Log.UnnestException(e); thread?.Exception(e); this.DisplayBootstrapErrorPage(e.Message, e.StackTrace); } thread?.Stop(); this.StartupCompleted("StartupProfile.uml", false); }
private async Task InitializeAsync(ProfilerThread Thread) { string createDbMethod = $"{nameof(FilesProvider)}.{nameof(FilesProvider.CreateAsync)}()"; string method = null; Thread?.Start(); try { Thread?.NewState("Provider"); // 1. Try create database method = createDbMethod; this.databaseProvider = await CreateDatabaseFile(); Thread?.NewState("Repair"); method = nameof(FilesProvider.RepairIfInproperShutdown); await this.databaseProvider.RepairIfInproperShutdown(string.Empty); } catch (Exception e1) { e1 = Log.UnnestException(e1); Thread?.Exception(e1); // Create failed. this.logService.LogException(e1, this.GetClassAndMethod(MethodBase.GetCurrentMethod(), method)); try { Thread?.NewState("Repair2"); // 2. Try repair database if (this.databaseProvider is null && Database.HasProvider) { // This is an attempt that _can_ work. // During a soft restart, there _may_ be a provider registered already. If so, grab it. this.databaseProvider = Database.Provider as FilesProvider; } if (this.databaseProvider is null) { // Reasoning: If we can't create a provider, and the database doesn't have one assigned either, we're in serious trouble. // Throw an exception, which is caught below, to try and perform a recovery. const string message = "Database does not have a provider, and one cannot be created because the Database file(s) are locked. Catch 22."; method = createDbMethod; throw new InvalidOperationException(message); } method = nameof(FilesProvider.RepairIfInproperShutdown); await this.databaseProvider.RepairIfInproperShutdown(string.Empty); } catch (Exception e2) { e2 = Log.UnnestException(e2); Thread?.Exception(e2); // Repair failed this.logService.LogException(e2, this.GetClassAndMethod(MethodBase.GetCurrentMethod(), method)); } } try { Thread?.NewState("Register"); if (databaseProvider != null) { method = $"{nameof(Database)}.{nameof(Database.Register)}"; Database.Register(databaseProvider, false); // All is good. this.SetState(StorageState.Ready); } else { this.SetState(StorageState.NeedsRepair); } } catch (Exception e) { e = Log.UnnestException(e); Thread?.Exception(e); this.logService.LogException(e, this.GetClassAndMethod(MethodBase.GetCurrentMethod(), method)); this.SetState(StorageState.NeedsRepair); } finally { Thread?.Stop(); } }