mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-04 17:27:21 +00:00
Added backups of all data, restorable on another computer (#1008)
Co-authored-by: Thorsten Sommer <SommerEngineering@users.noreply.github.com>
This commit is contained in:
1 parent
ab45580473
commit
936043319c
144 files changed
+10417
-424
No files matched your search
@@ -0,0 +1,96 @@
|
||||
namespace AIStudio.Tools.Services;
|
||||
|
||||
public sealed partial class DataSourceEmbeddingService
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the indexing is paused right now, e.g., while a backup copies the indexes, or while a
|
||||
/// restore waits for the restart.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Deleting or repairing a data source waits for the end of a pause, so the user interface asks
|
||||
/// first and tells the user instead of waiting.
|
||||
/// </remarks>
|
||||
public bool IsIndexingPaused => this.pauses.IsPaused;
|
||||
|
||||
/// <summary>
|
||||
/// Pauses the indexing of every data source, e.g., while a backup copies the indexes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Every run stops, and the pause waits until they have, since a run may be about to write to
|
||||
/// both stores. A document a run embedded completely stays stored, and its fingerprint keeps the
|
||||
/// next run from embedding it once more. Every run asked for during the pause waits for its end,
|
||||
/// the next sync of a mailbox among them. Ending the pause queues every data source whose run it
|
||||
/// stopped, for the same reason that run was asked for.<br/><br/>
|
||||
///
|
||||
/// Pauses may overlap. The indexing goes on once the last one ended.
|
||||
/// </remarks>
|
||||
/// <param name="token">Stops waiting for the runs to stop, which ends the pause as well.</param>
|
||||
/// <returns>The pause. Disposing it ends the pause.</returns>
|
||||
public async Task<IAsyncDisposable> PauseIndexingAsync(CancellationToken token)
|
||||
{
|
||||
//
|
||||
// The pause begins before any run is stopped. A run which starts meanwhile is either among
|
||||
// the active runs below, or it finds the indexing paused and waits:
|
||||
//
|
||||
this.pauses.Begin();
|
||||
var pause = new IndexingPause(this);
|
||||
|
||||
var stoppedRuns = new List<Task>();
|
||||
foreach (var (dataSourceId, activeRun) in this.activeRuns)
|
||||
{
|
||||
if (!TryCancelRun(activeRun))
|
||||
continue;
|
||||
|
||||
this.pauses.RecordStoppedRun(dataSourceId, activeRun.RefreshMode);
|
||||
stoppedRuns.Add(activeRun.Completion.Task);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(stoppedRuns).WaitAsync(token);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await pause.DisposeAsync();
|
||||
throw;
|
||||
}
|
||||
|
||||
logger.LogInformation("Paused the indexing of all data sources. Stopped {StoppedRuns} active runs.", stoppedRuns.Count);
|
||||
return pause;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ends a pause, and once the last one ended, queues every data source whose run a pause stopped.
|
||||
/// </summary>
|
||||
private async Task EndPauseAsync()
|
||||
{
|
||||
var stoppedRuns = this.pauses.End();
|
||||
foreach (var stoppedRun in stoppedRuns)
|
||||
{
|
||||
// Deleted during the pause, so there is nothing to carry on with:
|
||||
if (!this.TryGetConfiguredIndexedSource(stoppedRun.DataSourceId, out var dataSource))
|
||||
continue;
|
||||
|
||||
await this.QueueDataSourceAsync(dataSource, true, stoppedRun.RefreshMode);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// One pause, which ends once it is disposed.
|
||||
/// </summary>
|
||||
private sealed class IndexingPause(DataSourceEmbeddingService service) : IAsyncDisposable
|
||||
{
|
||||
private int ended;
|
||||
|
||||
/// <summary>
|
||||
/// Ends the pause. Ending it again does nothing.
|
||||
/// </summary>
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (Interlocked.Exchange(ref this.ended, 1) == 1)
|
||||
return;
|
||||
|
||||
await service.EndPauseAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user