Skip to content

Commit

Permalink
Merge pull request 'bugfix/form-optimization' (#112) from bugfix/form…
Browse files Browse the repository at this point in the history
…-optimization into hotfix/v3.0.1

Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/DocSpace-server/pulls/112
Reviewed-by: Nikolay Rechkin <[email protected]>
  • Loading branch information
MaksimChegulov committed Dec 3, 2024
2 parents 73e6295 + 7a1512d commit 150502a
Show file tree
Hide file tree
Showing 13 changed files with 185 additions and 22 deletions.
17 changes: 14 additions & 3 deletions products/ASC.Files/Core/ApiModels/ResponseDto/FileDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,11 +229,22 @@ private async Task<FileDto<T>> GetFileWrapperAsync<T>(File<T> file, string order

if (fileType == FileType.Pdf)
{
var linkDao = daoFactory.GetLinkDao<T>();
var folderDao = daoFactory.GetCacheFolderDao<T>();

var linkedIdTask = linkDao.GetLinkedAsync(file.Id);
var propertiesTask = fileDao.GetProperties(file.Id);
Task<T> linkedIdTask;
Task<EntryProperties<T>> propertiesTask;

if (file.FormInfo != null)
{
linkedIdTask = Task.FromResult(file.FormInfo.LinkedId);
propertiesTask = Task.FromResult(file.FormInfo.Properties);
}
else
{
linkedIdTask = daoFactory.GetLinkDao<T>().GetLinkedAsync(file.Id);
propertiesTask = fileDao.GetProperties(file.Id);
}

var currentFolderTask = folderDao.GetFolderAsync(file.ParentId);
await Task.WhenAll(linkedIdTask, propertiesTask, currentFolderTask);

Expand Down
2 changes: 2 additions & 0 deletions products/ASC.Files/Core/Core/Dao/Interfaces/IFileDao.cs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,8 @@ IAsyncEnumerable<File<T>> GetFilesAsync(IEnumerable<T> parentIds, FilterType fil

Task<EntryProperties<T>> GetProperties(T fileId);

Task<Dictionary<T, EntryProperties<T>>> GetPropertiesAsync(IEnumerable<T> filesIds);

Task SaveProperties(T fileId, EntryProperties<T> entryProperties);

Task<int> GetFilesCountAsync(T parentId, FilterType filterType, bool subjectGroup, Guid subjectId, string searchText, string[] extension, bool searchInContent,
Expand Down
1 change: 1 addition & 0 deletions products/ASC.Files/Core/Core/Dao/Interfaces/ILinkDao.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public interface ILinkDao<T>
Task AddLinkAsync(T sourceId, T linkedId);
Task<T> GetSourceAsync(T linkedId);
Task<T> GetLinkedAsync(T sourceId);
Task<Dictionary<T, T>> GetLinkedIdsAsync(IEnumerable<T> sourceIds);
Task DeleteLinkAsync(T sourceId);
Task DeleteAllLinkAsync(T sourceId);
}
19 changes: 19 additions & 0 deletions products/ASC.Files/Core/Core/Dao/TeamlabDao/FileDao.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1805,6 +1805,25 @@ public async Task<EntryProperties<int>> GetProperties(int fileId)
return data != null ? EntryProperties<int>.Deserialize(data, logger) : null;
}

public async Task<Dictionary<int, EntryProperties<int>>> GetPropertiesAsync(IEnumerable<int> filesIds)
{
var tenantId = await _tenantManager.GetCurrentTenantIdAsync();
await using var filesDbContext = await _dbContextFactory.CreateDbContextAsync();

var properties = await filesDbContext.FilesPropertiesAsync(tenantId, filesIds.Select(f => f.ToString())).ToListAsync();

var propertiesMap = new Dictionary<int, EntryProperties<int>>(properties.Count);
foreach (var property in properties)
{
if (int.TryParse(property.EntryId, out var id))
{
propertiesMap.TryAdd(id, EntryProperties<int>.Deserialize(property.Data, logger));
}
}

return propertiesMap;
}

public async Task SaveProperties(int fileId, EntryProperties<int> entryProperties)
{
string data;
Expand Down
20 changes: 18 additions & 2 deletions products/ASC.Files/Core/Core/Dao/TeamlabDao/LinkDao.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public async Task<T> GetSourceAsync(T linkedId)
if (Equals(fromDb, default))
{
return default;
}
}

return (T)Convert.ChangeType(fromDb, typeof(T));
}
Expand All @@ -101,11 +101,27 @@ public async Task<T> GetLinkedAsync(T sourceId)
if (Equals(fromDb, default))
{
return default;
}
}

return (T)Convert.ChangeType(fromDb, typeof(T));
}

public async Task<Dictionary<T, T>> GetLinkedIdsAsync(IEnumerable<T> sourceIds)
{
var tenantId = await _tenantManager.GetCurrentTenantIdAsync();
var mapping = daoFactory.GetMapping<T>();

var mappedIds = await sourceIds.ToAsyncEnumerable().SelectAwait(async x => await mapping.MappingIdAsync(x)).ToListAsync();
var source = mappedIds.Select(x => x.ToString());

await using var filesDbContext = await _dbContextFactory.CreateDbContextAsync();

return await filesDbContext.FilesLinksAsync(tenantId, source, _authContext.CurrentAccount.ID)
.ToDictionaryAsync(
x => (T)Convert.ChangeType(x.SourceId, typeof(T)),
x => (T)Convert.ChangeType(x.LinkedId, typeof(T)));
}

public async Task DeleteLinkAsync(T sourceId)
{
var tenantId = await _tenantManager.GetCurrentTenantIdAsync();
Expand Down
13 changes: 13 additions & 0 deletions products/ASC.Files/Core/Core/EF/Queries/FileQueries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,12 @@ public Task<string> DataAsync(int tenantId, string entryId)
return FileQueries.DataAsync(this, tenantId, entryId);
}

[PreCompileQuery([PreCompileQuery.DefaultInt, null])]
public IAsyncEnumerable<DbFilesProperties> FilesPropertiesAsync(int tenantId, IEnumerable<string> filesIds)
{
return FileQueries.FilesPropertiesAsync(this, tenantId, filesIds);
}

[PreCompileQuery([PreCompileQuery.DefaultInt, null])]
public Task<int> DeleteFilesPropertiesAsync(int tenantId, string entryId)
{
Expand Down Expand Up @@ -830,6 +836,13 @@ select f
.Where(r => r.EntryId == entryId)
.Select(r => r.Data)
.FirstOrDefault());

public static readonly Func<FilesDbContext, int, IEnumerable<string>, IAsyncEnumerable<DbFilesProperties>> FilesPropertiesAsync =
Microsoft.EntityFrameworkCore.EF.CompileAsyncQuery(
(FilesDbContext ctx, int tenantId, IEnumerable<string> filesIds) =>
ctx.FilesProperties
.Where(r => r.TenantId == tenantId)
.Where(r => filesIds.Contains(r.EntryId)));

public static readonly Func<FilesDbContext, int, string, Task<int>> DeleteFilesPropertiesAsync =
Microsoft.EntityFrameworkCore.EF.CompileAsyncQuery(
Expand Down
13 changes: 13 additions & 0 deletions products/ASC.Files/Core/Core/EF/Queries/LinkQueries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public Task<string> LinkedIdAsync(int tenantId, string sourceId, Guid id)
return LinkQueries.LinkedIdAsync(this, tenantId, sourceId, id);
}

[PreCompileQuery([PreCompileQuery.DefaultInt, null, PreCompileQuery.DefaultGuid])]
public IAsyncEnumerable<DbFilesLink> FilesLinksAsync(int tenantId, IEnumerable<string> sourceIds, Guid id)
{
return LinkQueries.FilesLinksAsync(this, tenantId, sourceIds, id);
}

[PreCompileQuery([PreCompileQuery.DefaultInt, null, PreCompileQuery.DefaultGuid])]
public Task<DbFilesLink> FileLinkAsync(int tenantId, string sourceId, Guid id)
Expand Down Expand Up @@ -73,6 +78,14 @@ static file class LinkQueries
.OrderByDescending(r => r)
.LastOrDefault());

public static readonly Func<FilesDbContext, int, IEnumerable<string>, Guid, IAsyncEnumerable<DbFilesLink>> FilesLinksAsync =
Microsoft.EntityFrameworkCore.EF.CompileAsyncQuery(
(FilesDbContext ctx, int tenantId, IEnumerable<string> sourceIds, Guid id) =>
ctx.FilesLink
.Where(r => r.TenantId == tenantId && sourceIds.Contains(r.SourceId) && r.LinkedFor == id)
.GroupBy(r => r.SourceId)
.Select(g => g.OrderByDescending(r => r.LinkedId).LastOrDefault()));

public static readonly Func<FilesDbContext, int, string, Guid, Task<DbFilesLink>> FileLinkAsync =
Microsoft.EntityFrameworkCore.EF.CompileAsyncQuery(
(FilesDbContext ctx, int tenantId, string sourceId, Guid id) =>
Expand Down
8 changes: 8 additions & 0 deletions products/ASC.Files/Core/Core/Entries/File.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,4 +236,12 @@ public string ConvertedExtension
}

public DateTime? LastOpened { get; set; }
public FormInfo<T> FormInfo { get; set; }
}

public record FormInfo<T>
{
public T LinkedId { get; init; }
public EntryProperties<T> Properties { get; init; }
public static FormInfo<T> Empty => new();
}
8 changes: 7 additions & 1 deletion products/ASC.Files/Core/Core/FileStorageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1656,8 +1656,14 @@ public async IAsyncEnumerable<File<T>> GetFileHistoryAsync<T>(T fileId)
{
throw new InvalidOperationException(FilesCommonResource.ErrorMessage_SecurityException_ReadFile);
}

var history = await fileDao.GetFileHistoryAsync(fileId).ToListAsync();

var t1 = entryStatusManager.SetFileStatusAsync(history);
var t2 = entryStatusManager.SetFormInfoAsync(history);
await Task.WhenAll(t1, t2);

await foreach (var r in fileDao.GetFileHistoryAsync(fileId))
foreach (var r in history)
{
await entryStatusManager.SetFileStatusAsync(r);
yield return r;
Expand Down
5 changes: 5 additions & 0 deletions products/ASC.Files/Core/Core/Thirdparty/ThirdPartyFileDao.cs
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,11 @@ public Task<EntryProperties<string>> GetProperties(string fileId)
return Task.FromResult<EntryProperties<string>>(null);
}

public Task<Dictionary<string, EntryProperties<string>>> GetPropertiesAsync(IEnumerable<string> filesIds)
{
return Task.FromResult<Dictionary<string, EntryProperties<string>>>(null);
}

public Task SaveProperties(string fileId, EntryProperties<string> entryProperties)
{
return Task.CompletedTask;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ public Task<EntryProperties<string>> GetProperties(string fileId)
{
return Task.FromResult<EntryProperties<string>>(null);
}

public Task<Dictionary<string, EntryProperties<string>>> GetPropertiesAsync(IEnumerable<string> filesIds)
{
return Task.FromResult<Dictionary<string, EntryProperties<string>>>(null);
}

public Task SaveProperties(string fileId, EntryProperties<string> entryProperties)
{
Expand Down
83 changes: 72 additions & 11 deletions products/ASC.Files/Core/Utils/EntryManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,58 @@ public async Task SetIsFavoriteFoldersAsync<T>(IEnumerable<Folder<T>> folders)
folder.IsFavorite = true;
}
}

public async Task SetFormInfoAsync<T>(IEnumerable<File<T>> files)
{
if (!files.Any())
{
return;
}

var pdfs = new List<File<T>>();

foreach (var file in files)
{
var extension = FileUtility.GetFileExtension(file.Title);
var fileType = FileUtility.GetFileTypeByExtention(extension);

if (fileType != FileType.Pdf)
{
continue;
}

if (!file.ProviderEntry)
{
pdfs.Add(file);
}
else
{
file.FormInfo = FormInfo<T>.Empty;
}
}

if (pdfs.Count == 0)
{
return;
}

var linkDao = daoFactory.GetLinkDao<T>();
var fileDao = daoFactory.GetFileDao<T>();

var ids = pdfs.Select(f => f.Id);

var linkedIdsMap = await linkDao.GetLinkedIdsAsync(ids);
var entryPropertiesMap = await fileDao.GetPropertiesAsync(ids);

foreach (var pdf in pdfs)
{
pdf.FormInfo = new FormInfo<T>
{
LinkedId = linkedIdsMap.GetValueOrDefault(pdf.Id),
Properties = entryPropertiesMap.GetValueOrDefault(pdf.Id)
};
}
}
}

[Scope]
Expand Down Expand Up @@ -404,7 +456,6 @@ public class EntryManager(IDaoFactory daoFactory,
var allFoldersCountTask = folderDao.GetFoldersCountAsync(parent.Id, foldersFilterType, subjectGroup, subjectId, foldersSearchText, withSubfolders, excludeSubject, roomId);
var allFilesCountTask = fileDao.GetFilesCountAsync(parent.Id, filesFilterType, subjectGroup, subjectId, filesSearchText, fileExtension, searchInContent, withSubfolders, excludeSubject, roomId);
var filesToUpdate = new List<File<T>>();


if (room is { FolderType: FolderType.VirtualDataRoom, SettingsIndexing: true })
{
Expand Down Expand Up @@ -508,10 +559,12 @@ public class EntryManager(IDaoFactory daoFactory,
}

var fileStatusTask = entryStatusManager.SetFileStatusAsync(filesToUpdate);
var formInfoTask = entryStatusManager.SetFormInfoAsync(filesToUpdate);

var tagsNewTask = fileMarker.SetTagsNewAsync(parent, entries);
var originsTask = SetOriginsAsync(parent, entries);

await Task.WhenAll(fileStatusTask, tagsNewTask, originsTask);
await Task.WhenAll(fileStatusTask, tagsNewTask, originsTask, formInfoTask);

total = await allFoldersCountTask + await allFilesCountTask;

Expand Down Expand Up @@ -627,7 +680,10 @@ public class EntryManager(IDaoFactory daoFactory,
var t2 = entryStatusManager.SetIsFavoriteFoldersAsync(internalFolders);
var t3 = entryStatusManager.SetFileStatusAsync(thirdPartyFiles);
var t4 = entryStatusManager.SetIsFavoriteFoldersAsync(thirdPartyFolders);
await Task.WhenAll(t1, t2, t3, t4);
var t5 = entryStatusManager.SetFormInfoAsync(internalFiles);
var t6 = entryStatusManager.SetFormInfoAsync(thirdPartyFiles);

await Task.WhenAll(t1, t2, t3, t4, t5, t6);

return (data, total);

Expand Down Expand Up @@ -2063,6 +2119,7 @@ await folderDao.GetFolderAsync(inProcessFormFolderId)

await InitFormFillingProperties(folder.Id, Path.GetFileNameWithoutExtension(file.Title), file.Id, inProcessFormFolderId, readyFormFolderId, folder.CreateBy, properties, fileDao, folderDao);
}

public async Task<(T readyFormFolderId, T inProcessFolderId)> InitSystemFormFillingFolders<T>(T formFillingRoomId, IFolderDao<T> folderDao, Guid createBy)
{
var readyFormFolder = serviceProvider.GetService<Folder<T>>();
Expand All @@ -2084,6 +2141,7 @@ await folderDao.GetFolderAsync(inProcessFormFolderId)

return (await readyFormFolderTask, await inProcessFolderTask);
}

private async Task<T> CreateFormFillingFolder<T>(string sourceTitle, T parentId, FolderType folderType, Guid createBy, IFolderDao<T> folderDao)
{
var folder = serviceProvider.GetService<Folder<T>>();
Expand All @@ -2094,18 +2152,20 @@ private async Task<T> CreateFormFillingFolder<T>(string sourceTitle, T parentId,

return await folderDao.SaveFolderAsync(folder);
}

private async Task<T> CreateCsvResult<T>(T resultsFolderId, Guid createBy, string sourceTitle, IFileDao<T> fileDao)
{
using var textStream = new MemoryStream(Encoding.UTF8.GetBytes(""));
var csvFile = serviceProvider.GetService<File<T>>();
csvFile.ParentId = resultsFolderId;
csvFile.Title = Global.ReplaceInvalidCharsAndTruncate(sourceTitle + ".csv");
csvFile.CreateBy = createBy;
var csvFile = serviceProvider.GetService<File<T>>();
csvFile.ParentId = resultsFolderId;
csvFile.Title = Global.ReplaceInvalidCharsAndTruncate(sourceTitle + ".csv");
csvFile.CreateBy = createBy;

var file = await fileDao.SaveFileAsync(csvFile, textStream, false);
var file = await fileDao.SaveFileAsync(csvFile, textStream, false);

return file.Id;
}
return file.Id;
}

private async Task<EntryProperties<T>> InitFormFillingProperties<T>(T roomId, string sourceTitle, T sourceFileId, T inProcessFormFolderId, T readyFormFolderId, Guid createBy, EntryProperties<T> properties, IFileDao<T> fileDao, IFolderDao<T> folderDao)
{
var templatesFolderTask = CreateFormFillingFolder(sourceTitle, inProcessFormFolderId, FolderType.FormFillingFolderInProgress, createBy, folderDao);
Expand All @@ -2128,7 +2188,8 @@ private async Task<EntryProperties<T>> InitFormFillingProperties<T>(T roomId, st
await fileDao.SaveProperties(sourceFileId, properties);

return properties;
}
}

private async Task SetOriginsAsync(IFolder parent, IEnumerable<FileEntry> entries)
{
if (parent.FolderType != FolderType.TRASH || !entries.Any())
Expand Down
13 changes: 8 additions & 5 deletions products/ASC.Files/Core/Utils/FileMarker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ public class FileMarker(
RoomsNotificationSettingsHelper roomsNotificationSettingsHelper,
FileMarkerCache fileMarkerCache,
IDistributedLockProvider distributedLockProvider,
FileMarkerHelper fileMarkerHelper)
FileMarkerHelper fileMarkerHelper,
EntryStatusManager entryStatusManager)
{
private const string CacheKeyFormat = "MarkedAsNew/{0}/folder_{1}";
private const string LockKey = "file_marker";
Expand Down Expand Up @@ -972,18 +973,20 @@ private async Task<Dictionary<FileEntry<T>, Tag>> GetEntryTagsAsync<T>(IEnumerab
var filesTags = tags.Where(t => t.EntryType == FileEntryType.File).ToDictionary(t => (T)t.EntryId);
var foldersTags = tags.Where(t => t.EntryType == FileEntryType.Folder).ToDictionary(t => (T)t.EntryId);

var files = fileDao.GetFilesAsync(filesTags.Keys);
var folders = folderDao.GetFoldersAsync(foldersTags.Keys);
var files = await fileDao.GetFilesAsync(filesTags.Keys).ToListAsync();
var folders = await folderDao.GetFoldersAsync(foldersTags.Keys).ToListAsync();

await foreach (var file in files)
await entryStatusManager.SetFormInfoAsync(files);

foreach (var file in files)
{
if (filesTags.TryGetValue(file.Id, out var tag))
{
entryTags[file] = tag;
}
}

await foreach (var folder in folders)
foreach (var folder in folders)
{
if (foldersTags.TryGetValue(folder.Id, out var tag))
{
Expand Down

0 comments on commit 150502a

Please sign in to comment.