Post merge master fixes
This commit is contained in:
@@ -1099,45 +1099,59 @@ namespace Duplicati.Library.Main.Database
|
||||
/// Gets the minimal unique prefix entries for a given fileset ID.
|
||||
/// This returns the roots of all unique paths in the fileset.
|
||||
/// </summary>
|
||||
/// <param name="filesetId">The fileset id</param>
|
||||
/// <returns>The entries that are unique roots</returns>
|
||||
public IList<IListFolderEntry> GetMinimalUniquePrefixEntries(long filesetId)
|
||||
/// <param name="filesetId">The fileset id.</param>
|
||||
/// <param name="token"> A cancellation token to cancel the operation.</param>
|
||||
/// <returns>A task that when awaited returns a list of the entries that are unique roots.</returns>
|
||||
public async IAsyncEnumerable<IListFolderEntry> GetMinimalUniquePrefixEntries(long filesetId, [EnumeratorCancellation] CancellationToken token)
|
||||
{
|
||||
var results = new List<IListFolderEntry>();
|
||||
|
||||
using var cmd = m_connection.CreateCommand();
|
||||
await using var cmd = m_connection.CreateCommand();
|
||||
cmd.SetCommandAndParameters(@"
|
||||
WITH AllPaths AS (
|
||||
SELECT fl.""ID"" AS ""FileID"",
|
||||
SELECT
|
||||
fl.""ID"" AS ""FileID"",
|
||||
pp.""Prefix"" || fl.""Path"" AS ""FullPath"",
|
||||
fl.""BlocksetID"",
|
||||
b.""Length"",
|
||||
fe.""Lastmodified""
|
||||
FROM ""FilesetEntry"" fe
|
||||
JOIN ""FileLookup"" fl ON fe.""FileID"" = fl.""ID""
|
||||
JOIN ""PathPrefix"" pp ON fl.""PrefixID"" = pp.""ID""
|
||||
LEFT JOIN ""Blockset"" b ON fl.""BlocksetID"" = b.""ID""
|
||||
JOIN ""FileLookup"" fl
|
||||
ON fe.""FileID"" = fl.""ID""
|
||||
JOIN ""PathPrefix"" pp
|
||||
ON fl.""PrefixID"" = pp.""ID""
|
||||
LEFT JOIN ""Blockset"" b
|
||||
ON fl.""BlocksetID"" = b.""ID""
|
||||
WHERE fe.""FilesetID"" = @FilesetId
|
||||
),
|
||||
RootCandidates AS (
|
||||
SELECT a1.*
|
||||
FROM AllPaths a1
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM AllPaths a2
|
||||
WHERE a2.""FullPath"" != a1.""FullPath""
|
||||
AND a1.""FullPath"" LIKE a2.""FullPath"" || '%'
|
||||
SELECT 1
|
||||
FROM AllPaths a2
|
||||
WHERE
|
||||
a2.""FullPath"" != a1.""FullPath""
|
||||
AND a1.""FullPath"" LIKE a2.""FullPath"" || '%'
|
||||
)
|
||||
)
|
||||
SELECT ""FullPath"", ""Length"",
|
||||
CASE WHEN ""BlocksetID"" = -100 THEN 1 ELSE 0 END AS ""IsDirectory"",
|
||||
CASE WHEN ""BlocksetID"" = -200 THEN 1 ELSE 0 END AS ""IsSymlink"",
|
||||
CASE
|
||||
WHEN ""BlocksetID"" = -100
|
||||
THEN 1
|
||||
ELSE 0
|
||||
END AS ""IsDirectory"",
|
||||
CASE
|
||||
WHEN ""BlocksetID"" = -200
|
||||
THEN 1
|
||||
ELSE 0
|
||||
END AS ""IsSymlink"",
|
||||
""Lastmodified""
|
||||
FROM RootCandidates
|
||||
ORDER BY ""FullPath""
|
||||
");
|
||||
cmd.SetParameterValue("@FilesetId", filesetId);
|
||||
")
|
||||
.SetTransaction(m_rtr)
|
||||
.SetParameterValue("@FilesetId", filesetId);
|
||||
|
||||
foreach (var rd in cmd.ExecuteReaderEnumerable())
|
||||
await foreach (var rd in cmd.ExecuteReaderEnumerableAsync(token))
|
||||
{
|
||||
var path = rd.ConvertValueToString(0) ?? string.Empty;
|
||||
var size = rd.ConvertValueToInt64(1, -1);
|
||||
@@ -1145,10 +1159,8 @@ namespace Duplicati.Library.Main.Database
|
||||
var isSymlink = rd.GetInt32(3) != 0;
|
||||
var lastModified = new DateTime(rd.ConvertValueToInt64(4, 0), DateTimeKind.Utc);
|
||||
|
||||
results.Add(new FolderEntry(path, size, isDir, isSymlink, lastModified));
|
||||
yield return new FolderEntry(path, size, isDir, isSymlink, lastModified);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -63,7 +63,10 @@ internal static class ListFolderHandler
|
||||
{
|
||||
if (folders != null && folders.Length > 1)
|
||||
throw new UserInformationException("When no folder is specified, only one folder can be listed", "MultipleFoldersFound");
|
||||
var rootFolders = db.GetMinimalUniquePrefixEntries(filesetIds[0]);
|
||||
var rootFolders = await db
|
||||
.GetMinimalUniquePrefixEntries(filesetIds[0], result.TaskControl.ProgressToken)
|
||||
.ToListAsync(cancellationToken: result.TaskControl.ProgressToken)
|
||||
.ConfigureAwait(false);
|
||||
result.Entries = new PaginatedResults<IListFolderEntry>(0, rootFolders.Count, 1, rootFolders.Count, rootFolders);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -433,9 +433,9 @@ namespace Duplicati.Library.Main.Operation
|
||||
await backendManager.DeleteAsync(vol.Name, vol.Size, true, m_result.TaskControl.ProgressToken).ConfigureAwait(false);
|
||||
await backendManager.WaitForEmptyAsync(repairdb, m_result.TaskControl.ProgressToken).ConfigureAwait(false);
|
||||
await repairdb.Transaction
|
||||
.CommitAsync("ReplaceFaultyIndexFileCommit")
|
||||
.CommitAsync("ReplaceFaultyIndexFileCommit", token: cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
m_results.RemoveResult(vol.Name);
|
||||
m_result.RemoveResult(vol.Name);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -337,7 +337,8 @@ namespace Duplicati.UnitTest
|
||||
]);
|
||||
|
||||
var result = await db
|
||||
.GetMinimalUniquePrefixEntries(1).Select(e => e.Path, CancellationToken.None)
|
||||
.GetMinimalUniquePrefixEntries(1, CancellationToken.None)
|
||||
.Select(e => e.Path)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
@@ -363,7 +364,8 @@ namespace Duplicati.UnitTest
|
||||
]);
|
||||
|
||||
var result = await db
|
||||
.GetMinimalUniquePrefixEntries(1).Select(e => e.Path, CancellationToken.None)
|
||||
.GetMinimalUniquePrefixEntries(1, CancellationToken.None)
|
||||
.Select(e => e.Path)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
@@ -387,7 +389,8 @@ namespace Duplicati.UnitTest
|
||||
]);
|
||||
|
||||
var result = await db
|
||||
.GetMinimalUniquePrefixEntries(1).Select(e => e.Path, CancellationToken.None)
|
||||
.GetMinimalUniquePrefixEntries(1, CancellationToken.None)
|
||||
.Select(e => e.Path)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
@@ -414,7 +417,8 @@ namespace Duplicati.UnitTest
|
||||
]);
|
||||
|
||||
var result = await db
|
||||
.GetMinimalUniquePrefixEntries(1).Select(e => e.Path, CancellationToken.None)
|
||||
.GetMinimalUniquePrefixEntries(1, CancellationToken.None)
|
||||
.Select(e => e.Path)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
@@ -429,7 +433,7 @@ namespace Duplicati.UnitTest
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetMinimalUniquePrefixEntries_ShouldReturnExpectedMinimalRoots()
|
||||
public async Task GetMinimalUniquePrefixEntries_ShouldReturnExpectedMinimalRoots()
|
||||
{
|
||||
// Arrange: Prepare prefixes (minimal unique) and contents
|
||||
var testPrefixes = new[]
|
||||
@@ -448,10 +452,15 @@ namespace Duplicati.UnitTest
|
||||
|
||||
// Act
|
||||
using var tempFile = new TempFile();
|
||||
using var db = new LocalListDatabase(tempFile, 1);
|
||||
await using var db = await LocalListDatabase.CreateAsync(tempFile, null, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
SeedTestData(db, testPrefixes);
|
||||
|
||||
var resultItems = db.GetMinimalUniquePrefixEntries(1).ToList();
|
||||
var resultItems = await db
|
||||
.GetMinimalUniquePrefixEntries(1, CancellationToken.None)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var result = resultItems.Select(e => e.Path).ToList();
|
||||
|
||||
Assert.That(result, Does.Contain(@"C:\Downloads\testsource\AA\"));
|
||||
|
||||
Reference in New Issue
Block a user