optimized updating new tags

This commit is contained in:
Maksim Chegulov 2023-08-30 14:13:18 +03:00
parent 4eb5aaa2c0
commit 4632b44767
3 changed files with 215 additions and 163 deletions

View File

@ -46,6 +46,7 @@ public interface ITagDao<T>
Task<TagInfo> SaveTagInfoAsync(TagInfo tagInfo); Task<TagInfo> SaveTagInfoAsync(TagInfo tagInfo);
Task UpdateNewTags(IEnumerable<Tag> tag, Guid createdBy = default); Task UpdateNewTags(IEnumerable<Tag> tag, Guid createdBy = default);
Task UpdateNewTags(Tag tag); Task UpdateNewTags(Tag tag);
Task IncrementNewTagsAsync(IEnumerable<Tag> tags, Guid createdBy = default);
Task RemoveTagsAsync(IEnumerable<int> tagsIds); Task RemoveTagsAsync(IEnumerable<int> tagsIds);
Task RemoveTagsAsync(FileEntry<T> entry, IEnumerable<int> tagsIds); Task RemoveTagsAsync(FileEntry<T> entry, IEnumerable<int> tagsIds);
Task RemoveTags(IEnumerable<Tag> tag); Task RemoveTags(IEnumerable<Tag> tag);

View File

@ -468,6 +468,45 @@ internal abstract class BaseTagDao<T> : AbstractDao
return t; return t;
} }
public async Task IncrementNewTagsAsync(IEnumerable<Tag> tags, Guid createdBy = default)
{
if (tags == null || !tags.Any())
{
return;
}
try
{
await _semaphore.WaitAsync();
await using var filesDbContext = _dbContextFactory.CreateDbContext();
var strategy = filesDbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
await using var internalFilesDbContext = _dbContextFactory.CreateDbContext();
await using var tx = await internalFilesDbContext.Database.BeginTransactionAsync();
var createOn = _tenantUtil.DateTimeToUtc(_tenantUtil.DateTimeNow());
var tenantId = TenantID;
foreach (var tagsGroup in tags.GroupBy(t => new { t.EntryId, t.EntryType }))
{
var mappedId = (await MappingIDAsync(tagsGroup.Key.EntryId)).ToString();
await Queries.IncrementNewTagsAsync(filesDbContext, tenantId, tagsGroup.Select(t => t.Id), tagsGroup.Key.EntryType,
mappedId, createdBy, createOn);
}
await tx.CommitAsync();
});
}
finally
{
_semaphore.Release();
}
}
public async Task UpdateNewTags(IEnumerable<Tag> tags, Guid createdBy = default) public async Task UpdateNewTags(IEnumerable<Tag> tags, Guid createdBy = default)
{ {
if (tags == null || !tags.Any()) if (tags == null || !tags.Any())
@ -1323,4 +1362,18 @@ static file class Queries
.Where(r => r.TenantId == tenantId) .Where(r => r.TenantId == tenantId)
.Where(r => tagsIds.Contains(r.Id)) .Where(r => tagsIds.Contains(r.Id))
.ExecuteDelete()); .ExecuteDelete());
public static readonly Func<FilesDbContext, int, IEnumerable<int>, FileEntryType, string, Guid, DateTime, Task<int>>
IncrementNewTagsAsync = Microsoft.EntityFrameworkCore.EF.CompileAsyncQuery(
(FilesDbContext ctx, int tenantId, IEnumerable<int> tagsIds, FileEntryType tagEntryType, string mappedId, Guid createdBy,
DateTime createOn) =>
ctx.TagLink
.Where(r => r.TenantId == tenantId)
.Where(r => tagsIds.Contains(r.TagId))
.Where(r => r.EntryType == tagEntryType)
.Where(r => r.EntryId == mappedId)
.ExecuteUpdate(f => f
.SetProperty(p => p.CreateBy, createdBy)
.SetProperty(p => p.CreateOn, createOn)
.SetProperty(p => p.Count, p => p.Count + 1)));
} }

View File

@ -25,7 +25,7 @@
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Web.Files.Utils; namespace ASC.Web.Files.Utils;
[Singletone] [Singletone]
public class FileMarkerHelper public class FileMarkerHelper
{ {
@ -33,7 +33,7 @@ public class FileMarkerHelper
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
private readonly ILogger _logger; private readonly ILogger _logger;
public DistributedTaskQueue Tasks { get; set; } public DistributedTaskQueue Tasks { get; set; }
public FileMarkerHelper( public FileMarkerHelper(
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
ILogger<FileMarkerHelper> logger, ILogger<FileMarkerHelper> logger,
@ -43,12 +43,12 @@ public class FileMarkerHelper
_logger = logger; _logger = logger;
Tasks = queueFactory.CreateQueue(CUSTOM_DISTRIBUTED_TASK_QUEUE_NAME); Tasks = queueFactory.CreateQueue(CUSTOM_DISTRIBUTED_TASK_QUEUE_NAME);
} }
internal void Add<T>(AsyncTaskData<T> taskData) internal void Add<T>(AsyncTaskData<T> taskData)
{ {
Tasks.EnqueueTask(async (d, c) => await ExecMarkFileAsNewAsync(taskData), taskData); Tasks.EnqueueTask(async (d, c) => await ExecMarkFileAsNewAsync(taskData), taskData);
} }
private async Task ExecMarkFileAsNewAsync<T>(AsyncTaskData<T> obj) private async Task ExecMarkFileAsNewAsync<T>(AsyncTaskData<T> obj)
{ {
try try
@ -64,14 +64,14 @@ public class FileMarkerHelper
} }
} }
} }
[Scope(Additional = typeof(FileMarkerExtention))] [Scope(Additional = typeof(FileMarkerExtention))]
public class FileMarker public class FileMarker
{ {
private readonly ICache _cache; private readonly ICache _cache;
private const string CacheKeyFormat = "MarkedAsNew/{0}/folder_{1}"; private const string CacheKeyFormat = "MarkedAsNew/{0}/folder_{1}";
private readonly TenantManager _tenantManager; private readonly TenantManager _tenantManager;
private readonly UserManager _userManager; private readonly UserManager _userManager;
private readonly IDaoFactory _daoFactory; private readonly IDaoFactory _daoFactory;
@ -106,14 +106,14 @@ public class FileMarker
_roomsNotificationSettingsHelper = roomsNotificationSettingsHelper; _roomsNotificationSettingsHelper = roomsNotificationSettingsHelper;
_cache = cache; _cache = cache;
} }
internal async Task ExecMarkFileAsNewAsync<T>(AsyncTaskData<T> obj, SocketManager socketManager) internal async Task ExecMarkFileAsNewAsync<T>(AsyncTaskData<T> obj, SocketManager socketManager)
{ {
await _tenantManager.SetCurrentTenantAsync(obj.TenantID); await _tenantManager.SetCurrentTenantAsync(obj.TenantID);
var folderDao = _daoFactory.GetFolderDao<T>(); var folderDao = _daoFactory.GetFolderDao<T>();
T parentFolderId; T parentFolderId;
if (obj.FileEntry.FileEntryType == FileEntryType.File) if (obj.FileEntry.FileEntryType == FileEntryType.File)
{ {
parentFolderId = ((File<T>)obj.FileEntry).ParentId; parentFolderId = ((File<T>)obj.FileEntry).ParentId;
@ -122,26 +122,26 @@ public class FileMarker
{ {
parentFolderId = ((Folder<T>)obj.FileEntry).Id; parentFolderId = ((Folder<T>)obj.FileEntry).Id;
} }
var parentFolders = await folderDao.GetParentFoldersAsync(parentFolderId).Reverse().ToListAsync(); var parentFolders = await folderDao.GetParentFoldersAsync(parentFolderId).Reverse().ToListAsync();
var userIDs = obj.UserIDs; var userIDs = obj.UserIDs;
var userEntriesData = new Dictionary<Guid, List<FileEntry>>(); var userEntriesData = new Dictionary<Guid, List<FileEntry>>();
if (obj.FileEntry.RootFolderType == FolderType.BUNCH) if (obj.FileEntry.RootFolderType == FolderType.BUNCH)
{ {
if (userIDs.Count == 0) if (userIDs.Count == 0)
{ {
return; return;
} }
var projectsFolder = await _globalFolder.GetFolderProjectsAsync<T>(_daoFactory); var projectsFolder = await _globalFolder.GetFolderProjectsAsync<T>(_daoFactory);
parentFolders.Add(await folderDao.GetFolderAsync(projectsFolder)); parentFolders.Add(await folderDao.GetFolderAsync(projectsFolder));
var entries = new List<FileEntry> { obj.FileEntry }; var entries = new List<FileEntry> { obj.FileEntry };
entries = entries.Concat(parentFolders).ToList(); entries = entries.Concat(parentFolders).ToList();
userIDs.ForEach(userID => userIDs.ForEach(userID =>
{ {
if (userEntriesData.TryGetValue(userID, out var value)) if (userEntriesData.TryGetValue(userID, out var value))
@ -152,19 +152,20 @@ public class FileMarker
{ {
userEntriesData.Add(userID, entries); userEntriesData.Add(userID, entries);
} }
RemoveFromCahce(projectsFolder, userID); RemoveFromCahce(projectsFolder, userID);
}); });
} }
else else
{ {
var filesSecurity = _fileSecurity; var filesSecurity = _fileSecurity;
if (userIDs.Count == 0) if (userIDs.Count == 0)
{ {
var guids = await filesSecurity.WhoCanReadAsync(obj.FileEntry); var guids = await filesSecurity.WhoCanReadAsync(obj.FileEntry);
userIDs = guids.Where(x => x != obj.CurrentAccountId).ToList(); userIDs = guids.Where(x => x != obj.CurrentAccountId).ToList();
} }
if (obj.FileEntry.ProviderEntry) if (obj.FileEntry.ProviderEntry)
{ {
userIDs = await userIDs.ToAsyncEnumerable().WhereAwait(async u => !await _userManager.IsUserAsync(u)).ToListAsync(); userIDs = await userIDs.ToAsyncEnumerable().WhereAwait(async u => !await _userManager.IsUserAsync(u)).ToListAsync();
@ -203,15 +204,15 @@ public class FileMarker
{ {
userEntriesData.Add(id, new List<FileEntry> { parentFolder }); userEntriesData.Add(id, new List<FileEntry> { parentFolder });
} }
} }
} }
if (obj.FileEntry.RootFolderType == FolderType.USER) if (obj.FileEntry.RootFolderType == FolderType.USER)
{ {
var folderDaoInt = _daoFactory.GetFolderDao<int>(); var folderDaoInt = _daoFactory.GetFolderDao<int>();
var folderShare = await folderDaoInt.GetFolderAsync(await _globalFolder.GetFolderShareAsync(_daoFactory)); var folderShare = await folderDaoInt.GetFolderAsync(await _globalFolder.GetFolderShareAsync(_daoFactory));
foreach (var userID in userIDs) foreach (var userID in userIDs)
{ {
var userFolderId = await folderDaoInt.GetFolderIDUserAsync(false, userID); var userFolderId = await folderDaoInt.GetFolderIDUserAsync(false, userID);
@ -219,13 +220,13 @@ public class FileMarker
{ {
continue; continue;
} }
Folder<int> rootFolder = null; Folder<int> rootFolder = null;
if (obj.FileEntry.ProviderEntry) if (obj.FileEntry.ProviderEntry)
{ {
rootFolder = obj.FileEntry.RootCreateBy == userID rootFolder = obj.FileEntry.RootCreateBy == userID
? await folderDaoInt.GetFolderAsync(userFolderId) ? await folderDaoInt.GetFolderAsync(userFolderId)
: folderShare; : folderShare;
} }
else if (!Equals(obj.FileEntry.RootId, userFolderId)) else if (!Equals(obj.FileEntry.RootId, userFolderId))
{ {
@ -235,12 +236,12 @@ public class FileMarker
{ {
RemoveFromCahce(userFolderId, userID); RemoveFromCahce(userFolderId, userID);
} }
if (rootFolder == null) if (rootFolder == null)
{ {
continue; continue;
} }
if (userEntriesData.TryGetValue(userID, out var value)) if (userEntriesData.TryGetValue(userID, out var value))
{ {
value.Add(rootFolder); value.Add(rootFolder);
@ -249,7 +250,7 @@ public class FileMarker
{ {
userEntriesData.Add(userID, new List<FileEntry> { rootFolder }); userEntriesData.Add(userID, new List<FileEntry> { rootFolder });
} }
RemoveFromCahce(rootFolder.Id, userID); RemoveFromCahce(rootFolder.Id, userID);
} }
} }
@ -257,7 +258,7 @@ public class FileMarker
{ {
var commonFolderId = await _globalFolder.GetFolderCommonAsync(this, _daoFactory); var commonFolderId = await _globalFolder.GetFolderCommonAsync(this, _daoFactory);
userIDs.ForEach(userID => RemoveFromCahce(commonFolderId, userID)); userIDs.ForEach(userID => RemoveFromCahce(commonFolderId, userID));
if (obj.FileEntry.ProviderEntry) if (obj.FileEntry.ProviderEntry)
{ {
var commonFolder = await folderDao.GetFolderAsync(await _globalFolder.GetFolderCommonAsync<T>(this, _daoFactory)); var commonFolder = await folderDao.GetFolderAsync(await _globalFolder.GetFolderCommonAsync<T>(this, _daoFactory));
@ -271,7 +272,7 @@ public class FileMarker
{ {
userEntriesData.Add(userID, new List<FileEntry> { commonFolder }); userEntriesData.Add(userID, new List<FileEntry> { commonFolder });
} }
RemoveFromCahce(commonFolderId, userID); RemoveFromCahce(commonFolderId, userID);
}); });
} }
@ -338,7 +339,7 @@ public class FileMarker
RemoveFromCahce(rootFolder.Id, userID); RemoveFromCahce(rootFolder.Id, userID);
} }
} }
userIDs.ForEach(userID => userIDs.ForEach(userID =>
{ {
if (userEntriesData.TryGetValue(userID, out var value)) if (userEntriesData.TryGetValue(userID, out var value))
@ -351,67 +352,64 @@ public class FileMarker
} }
}); });
} }
var tagDao = _daoFactory.GetTagDao<T>(); var tagDao = _daoFactory.GetTagDao<T>();
var newTags = new List<Tag>(); var newTags = new List<Tag>();
var updateTags = new List<Tag>(); var updateTags = new List<Tag>();
try try
{ {
await _semaphore.WaitAsync(); await _semaphore.WaitAsync();
foreach (var userID in userEntriesData.Keys) foreach (var userId in userEntriesData.Keys)
{
if (await tagDao.GetNewTagsAsync(userID, obj.FileEntry).AnyAsync())
{ {
continue; if (await tagDao.GetNewTagsAsync(userId, obj.FileEntry).AnyAsync())
} {
continue;
var entries = userEntriesData[userID].Distinct().ToList(); }
await GetNewTagsAsync(userID, entries.OfType<FileEntry<int>>().ToList());
await GetNewTagsAsync(userID, entries.OfType<FileEntry<string>>().ToList());
}
if (updateTags.Count > 0) var entries = userEntriesData[userId].Distinct().ToList();
{
await tagDao.UpdateNewTags(updateTags, obj.CurrentAccountId); await GetNewTagsAsync(userId, entries.OfType<FileEntry<int>>().ToList());
} await GetNewTagsAsync(userId, entries.OfType<FileEntry<string>>().ToList());
}
if (newTags.Count > 0)
{ if (updateTags.Count > 0)
await tagDao.SaveTags(newTags, obj.CurrentAccountId); {
} await tagDao.IncrementNewTagsAsync(updateTags, obj.CurrentAccountId);
} }
catch
{ if (newTags.Count > 0)
throw; {
await tagDao.SaveTags(newTags, obj.CurrentAccountId);
}
} }
finally finally
{ {
_semaphore.Release(); _semaphore.Release();
} }
await Task.WhenAll(ExecMarkAsNewRequest(updateTags.Concat(newTags), socketManager)); await Task.WhenAll(ExecMarkAsNewRequest(updateTags.Concat(newTags), socketManager));
async Task GetNewTagsAsync<T1>(Guid userID, List<FileEntry<T1>> entries) return;
async Task GetNewTagsAsync<T1>(Guid userId, List<FileEntry<T1>> entries)
{ {
var tagDao1 = _daoFactory.GetTagDao<T1>(); var tagDao1 = _daoFactory.GetTagDao<T1>();
var exist = await tagDao1.GetNewTagsAsync(userID, entries).ToListAsync(); var exist = await tagDao1.GetNewTagsAsync(userId, entries).ToListAsync();
var update = exist.Where(t => t.EntryType == FileEntryType.Folder).ToList(); var update = exist.Where(t => t.EntryType == FileEntryType.Folder).ToList();
update.ForEach(t => t.Count++);
updateTags.AddRange(update); updateTags.AddRange(update);
entries.ForEach(entry => entries.ForEach(entry =>
{ {
if (entry != null && exist.All(tag => tag != null && !tag.EntryId.Equals(entry.Id))) if (entry != null && exist.All(tag => tag != null && !tag.EntryId.Equals(entry.Id)))
{ {
newTags.Add(Tag.New(userID, entry)); newTags.Add(Tag.New(userId, entry));
} }
}); });
} }
} }
public async ValueTask MarkAsNewAsync<T>(FileEntry<T> fileEntry, List<Guid> userIDs = null) public async ValueTask MarkAsNewAsync<T>(FileEntry<T> fileEntry, List<Guid> userIDs = null)
{ {
if (fileEntry == null) if (fileEntry == null)
@ -420,36 +418,36 @@ public class FileMarker
} }
userIDs ??= new List<Guid>(); userIDs ??= new List<Guid>();
var taskData = _serviceProvider.GetService<AsyncTaskData<T>>(); var taskData = _serviceProvider.GetService<AsyncTaskData<T>>();
taskData.FileEntry = (FileEntry<T>)fileEntry.Clone(); taskData.FileEntry = (FileEntry<T>)fileEntry.Clone();
taskData.UserIDs = userIDs; taskData.UserIDs = userIDs;
if (fileEntry.RootFolderType == FolderType.BUNCH && userIDs.Count == 0) if (fileEntry.RootFolderType == FolderType.BUNCH && userIDs.Count == 0)
{ {
var folderDao = _daoFactory.GetFolderDao<T>(); var folderDao = _daoFactory.GetFolderDao<T>();
var path = await folderDao.GetBunchObjectIDAsync(fileEntry.RootId); var path = await folderDao.GetBunchObjectIDAsync(fileEntry.RootId);
var projectID = path.Split('/').Last(); var projectID = path.Split('/').Last();
if (string.IsNullOrEmpty(projectID)) if (string.IsNullOrEmpty(projectID))
{ {
return; return;
} }
var whoCanRead = await _fileSecurity.WhoCanReadAsync(fileEntry); var whoCanRead = await _fileSecurity.WhoCanReadAsync(fileEntry);
var projectTeam = whoCanRead.Where(x => x != _authContext.CurrentAccount.ID).ToList(); var projectTeam = whoCanRead.Where(x => x != _authContext.CurrentAccount.ID).ToList();
if (projectTeam.Count == 0) if (projectTeam.Count == 0)
{ {
return; return;
} }
taskData.UserIDs = projectTeam; taskData.UserIDs = projectTeam;
} }
_serviceProvider.GetService<FileMarkerHelper>().Add(taskData); _serviceProvider.GetService<FileMarkerHelper>().Add(taskData);
} }
public async ValueTask RemoveMarkAsNewAsync<T>(FileEntry<T> fileEntry, Guid userID = default) public async ValueTask RemoveMarkAsNewAsync<T>(FileEntry<T> fileEntry, Guid userID = default)
{ {
if (fileEntry == null) if (fileEntry == null)
@ -458,41 +456,41 @@ public class FileMarker
} }
userID = userID.Equals(default) ? _authContext.CurrentAccount.ID : userID; userID = userID.Equals(default) ? _authContext.CurrentAccount.ID : userID;
var tagDao = _daoFactory.GetTagDao<T>(); var tagDao = _daoFactory.GetTagDao<T>();
var internalFolderDao = _daoFactory.GetFolderDao<int>(); var internalFolderDao = _daoFactory.GetFolderDao<int>();
var folderDao = _daoFactory.GetFolderDao<T>(); var folderDao = _daoFactory.GetFolderDao<T>();
if (!await tagDao.GetNewTagsAsync(userID, fileEntry).AnyAsync()) if (!await tagDao.GetNewTagsAsync(userID, fileEntry).AnyAsync())
{ {
return; return;
} }
T folderID; T folderID;
int valueNew; int valueNew;
var userFolderId = await internalFolderDao.GetFolderIDUserAsync(false, userID); var userFolderId = await internalFolderDao.GetFolderIDUserAsync(false, userID);
var privacyFolderId = await internalFolderDao.GetFolderIDPrivacyAsync(false, userID); var privacyFolderId = await internalFolderDao.GetFolderIDPrivacyAsync(false, userID);
var removeTags = new List<Tag>(); var removeTags = new List<Tag>();
if (fileEntry.FileEntryType == FileEntryType.File) if (fileEntry.FileEntryType == FileEntryType.File)
{ {
folderID = ((File<T>)fileEntry).ParentId; folderID = ((File<T>)fileEntry).ParentId;
removeTags.Add(Tag.New(userID, fileEntry)); removeTags.Add(Tag.New(userID, fileEntry));
valueNew = 1; valueNew = 1;
} }
else else
{ {
folderID = fileEntry.Id; folderID = fileEntry.Id;
var listTags = await tagDao.GetNewTagsAsync(userID, (Folder<T>)fileEntry, true).ToListAsync(); var listTags = await tagDao.GetNewTagsAsync(userID, (Folder<T>)fileEntry, true).ToListAsync();
valueNew = listTags.FirstOrDefault(tag => tag.EntryId.Equals(fileEntry.Id)).Count; valueNew = listTags.FirstOrDefault(tag => tag.EntryId.Equals(fileEntry.Id)).Count;
if (Equals(fileEntry.Id, userFolderId) || Equals(fileEntry.Id, await _globalFolder.GetFolderCommonAsync(this, _daoFactory)) || Equals(fileEntry.Id, await _globalFolder.GetFolderShareAsync(_daoFactory))) if (Equals(fileEntry.Id, userFolderId) || Equals(fileEntry.Id, await _globalFolder.GetFolderCommonAsync(this, _daoFactory)) || Equals(fileEntry.Id, await _globalFolder.GetFolderShareAsync(_daoFactory)))
{ {
var folderTags = listTags.Where(tag => tag.EntryType == FileEntryType.Folder); var folderTags = listTags.Where(tag => tag.EntryType == FileEntryType.Folder);
foreach (var tag in folderTags) foreach (var tag in folderTags)
{ {
var folderEntry = await folderDao.GetFolderAsync((T)tag.EntryId); var folderEntry = await folderDao.GetFolderAsync((T)tag.EntryId);
@ -500,15 +498,15 @@ public class FileMarker
{ {
listTags.Remove(tag); listTags.Remove(tag);
listTags.AddRange(await tagDao.GetNewTagsAsync(userID, folderEntry, true).ToListAsync()); listTags.AddRange(await tagDao.GetNewTagsAsync(userID, folderEntry, true).ToListAsync());
} }
} }
} }
removeTags.AddRange(listTags); removeTags.AddRange(listTags);
} }
var parentFolders = await folderDao.GetParentFoldersAsync(folderID).Reverse().ToListAsync(); var parentFolders = await folderDao.GetParentFoldersAsync(folderID).Reverse().ToListAsync();
var rootFolder = parentFolders.LastOrDefault(); var rootFolder = parentFolders.LastOrDefault();
int rootFolderId = default; int rootFolderId = default;
int cacheFolderId = default; int cacheFolderId = default;
@ -561,24 +559,24 @@ public class FileMarker
{ {
cacheFolderId = await _globalFolder.GetFolderShareAsync(_daoFactory); cacheFolderId = await _globalFolder.GetFolderShareAsync(_daoFactory);
} }
var updateTags = new List<Tag>(); var updateTags = new List<Tag>();
if (!rootFolderId.Equals(default)) if (!rootFolderId.Equals(default))
{ {
await UpdateRemoveTags(await internalFolderDao.GetFolderAsync(rootFolderId)); await UpdateRemoveTags(await internalFolderDao.GetFolderAsync(rootFolderId));
} }
if (!cacheFolderId.Equals(default)) if (!cacheFolderId.Equals(default))
{ {
RemoveFromCahce(cacheFolderId, userID); RemoveFromCahce(cacheFolderId, userID);
} }
foreach (var parentFolder in parentFolders) foreach (var parentFolder in parentFolders)
{ {
await UpdateRemoveTags(parentFolder); await UpdateRemoveTags(parentFolder);
} }
if (updateTags.Count > 0) if (updateTags.Count > 0)
{ {
await tagDao.UpdateNewTags(updateTags); await tagDao.UpdateNewTags(updateTags);
@ -604,11 +602,11 @@ public class FileMarker
var tagDao = _daoFactory.GetTagDao<TFolder>(); var tagDao = _daoFactory.GetTagDao<TFolder>();
var newTags = tagDao.GetNewTagsAsync(userID, folder); var newTags = tagDao.GetNewTagsAsync(userID, folder);
var parentTag = await newTags.FirstOrDefaultAsync(); var parentTag = await newTags.FirstOrDefaultAsync();
if (parentTag != null) if (parentTag != null)
{ {
parentTag.Count -= valueNew; parentTag.Count -= valueNew;
if (parentTag.Count > 0) if (parentTag.Count > 0)
{ {
updateTags.Add(parentTag); updateTags.Add(parentTag);
@ -620,21 +618,21 @@ public class FileMarker
} }
} }
} }
public async Task RemoveMarkAsNewForAllAsync<T>(FileEntry<T> fileEntry) public async Task RemoveMarkAsNewForAllAsync<T>(FileEntry<T> fileEntry)
{ {
IAsyncEnumerable<Guid> userIDs; IAsyncEnumerable<Guid> userIDs;
var tagDao = _daoFactory.GetTagDao<T>(); var tagDao = _daoFactory.GetTagDao<T>();
var tags = tagDao.GetTagsAsync(fileEntry.Id, fileEntry.FileEntryType == FileEntryType.File ? FileEntryType.File : FileEntryType.Folder, TagType.New); var tags = tagDao.GetTagsAsync(fileEntry.Id, fileEntry.FileEntryType == FileEntryType.File ? FileEntryType.File : FileEntryType.Folder, TagType.New);
userIDs = tags.Select(tag => tag.Owner).Distinct(); userIDs = tags.Select(tag => tag.Owner).Distinct();
await foreach (var userID in userIDs) await foreach (var userID in userIDs)
{ {
await RemoveMarkAsNewAsync(fileEntry, userID); await RemoveMarkAsNewAsync(fileEntry, userID);
} }
} }
public async Task<int> GetRootFoldersIdMarkedAsNewAsync<T>(T rootId) public async Task<int> GetRootFoldersIdMarkedAsNewAsync<T>(T rootId)
{ {
@ -647,24 +645,24 @@ public class FileMarker
var requestTag = await requestTags.FirstOrDefaultAsync(tag => tag.EntryId.Equals(rootId)); var requestTag = await requestTags.FirstOrDefaultAsync(tag => tag.EntryId.Equals(rootId));
var count = requestTag == null ? 0 : requestTag.Count; var count = requestTag == null ? 0 : requestTag.Count;
InsertToCahce(rootId, count); InsertToCahce(rootId, count);
return count; return count;
} }
else if (fromCache > 0) else if (fromCache > 0)
{ {
return fromCache; return fromCache;
} }
return 0; return 0;
} }
public IAsyncEnumerable<FileEntry> MarkedItemsAsync<T>(Folder<T> folder) public IAsyncEnumerable<FileEntry> MarkedItemsAsync<T>(Folder<T> folder)
{ {
if (folder == null) if (folder == null)
{ {
throw new ArgumentNullException(nameof(folder), FilesCommonResource.ErrorMassage_FolderNotFound); throw new ArgumentNullException(nameof(folder), FilesCommonResource.ErrorMassage_FolderNotFound);
} }
return InternalMarkedItemsAsync(folder); return InternalMarkedItemsAsync(folder);
} }
@ -675,67 +673,67 @@ public class FileMarker
throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ViewFolder);
} }
if (folder.RootFolderType == FolderType.TRASH && !Equals(folder.Id, await _globalFolder.GetFolderTrashAsync(_daoFactory))) if (folder.RootFolderType == FolderType.TRASH && !Equals(folder.Id, await _globalFolder.GetFolderTrashAsync(_daoFactory)))
{ {
throw new SecurityException(FilesCommonResource.ErrorMassage_ViewTrashItem); throw new SecurityException(FilesCommonResource.ErrorMassage_ViewTrashItem);
} }
var tagDao = _daoFactory.GetTagDao<T>();
var providerFolderDao = _daoFactory.GetFolderDao<string>();
var providerTagDao = _daoFactory.GetTagDao<string>();
var tags = await (tagDao.GetNewTagsAsync(_authContext.CurrentAccount.ID, folder, true) ?? AsyncEnumerable.Empty<Tag>()).ToListAsync();
var tagDao = _daoFactory.GetTagDao<T>();
var providerFolderDao = _daoFactory.GetFolderDao<string>();
var providerTagDao = _daoFactory.GetTagDao<string>();
var tags = await (tagDao.GetNewTagsAsync(_authContext.CurrentAccount.ID, folder, true) ?? AsyncEnumerable.Empty<Tag>()).ToListAsync();
if (!tags.Any()) if (!tags.Any())
{ {
yield break; yield break;
} }
if (Equals(folder.Id, await _globalFolder.GetFolderMyAsync(this, _daoFactory)) || if (Equals(folder.Id, await _globalFolder.GetFolderMyAsync(this, _daoFactory)) ||
Equals(folder.Id, await _globalFolder.GetFolderCommonAsync(this, _daoFactory)) || Equals(folder.Id, await _globalFolder.GetFolderCommonAsync(this, _daoFactory)) ||
Equals(folder.Id, await _globalFolder.GetFolderShareAsync(_daoFactory)) || Equals(folder.Id, await _globalFolder.GetFolderShareAsync(_daoFactory)) ||
Equals(folder.Id, await _globalFolder.GetFolderVirtualRoomsAsync(_daoFactory))) Equals(folder.Id, await _globalFolder.GetFolderVirtualRoomsAsync(_daoFactory)))
{ {
var folderTags = tags.Where(tag => tag.EntryType == FileEntryType.Folder && (tag.EntryId is string)); var folderTags = tags.Where(tag => tag.EntryType == FileEntryType.Folder && (tag.EntryId is string));
var providerFolderTags = new List<KeyValuePair<Tag, Folder<string>>>(); var providerFolderTags = new List<KeyValuePair<Tag, Folder<string>>>();
foreach (var tag in folderTags) foreach (var tag in folderTags)
{
var pair = new KeyValuePair<Tag, Folder<string>>(tag, await providerFolderDao.GetFolderAsync(tag.EntryId.ToString()));
if (pair.Value != null && pair.Value.ProviderEntry)
{
providerFolderTags.Add(pair);
}
}
providerFolderTags.Reverse();
foreach (var providerFolderTag in providerFolderTags)
{ {
tags.AddRange(await providerTagDao.GetNewTagsAsync(_authContext.CurrentAccount.ID, providerFolderTag.Value, true).ToListAsync()); var pair = new KeyValuePair<Tag, Folder<string>>(tag, await providerFolderDao.GetFolderAsync(tag.EntryId.ToString()));
if (pair.Value != null && pair.Value.ProviderEntry)
{
providerFolderTags.Add(pair);
}
}
providerFolderTags.Reverse();
foreach (var providerFolderTag in providerFolderTags)
{
tags.AddRange(await providerTagDao.GetNewTagsAsync(_authContext.CurrentAccount.ID, providerFolderTag.Value, true).ToListAsync());
} }
} }
tags = tags tags = tags
.Where(r => !Equals(r.EntryId, folder.Id)) .Where(r => !Equals(r.EntryId, folder.Id))
.Distinct() .Distinct()
.ToList(); .ToList();
//TODO: refactoring //TODO: refactoring
var entryTagsProvider = await GetEntryTagsAsync<string>(tags.Where(r => r.EntryId is string).ToAsyncEnumerable()); var entryTagsProvider = await GetEntryTagsAsync<string>(tags.Where(r => r.EntryId is string).ToAsyncEnumerable());
var entryTagsInternal = await GetEntryTagsAsync<int>(tags.Where(r => r.EntryId is int).ToAsyncEnumerable()); var entryTagsInternal = await GetEntryTagsAsync<int>(tags.Where(r => r.EntryId is int).ToAsyncEnumerable());
foreach (var entryTag in entryTagsInternal) foreach (var entryTag in entryTagsInternal)
{ {
var parentEntry = entryTagsInternal.Keys var parentEntry = entryTagsInternal.Keys
.FirstOrDefault(entryCountTag => Equals(entryCountTag.Id, entryTag.Key.ParentId)); .FirstOrDefault(entryCountTag => Equals(entryCountTag.Id, entryTag.Key.ParentId));
if (parentEntry != null) if (parentEntry != null)
{ {
entryTagsInternal[parentEntry].Count -= entryTag.Value.Count; entryTagsInternal[parentEntry].Count -= entryTag.Value.Count;
} }
} }
foreach (var entryTag in entryTagsProvider) foreach (var entryTag in entryTagsProvider)
{ {
if (int.TryParse(entryTag.Key.ParentId, out var fId)) if (int.TryParse(entryTag.Key.ParentId, out var fId))
@ -746,20 +744,20 @@ public class FileMarker
if (parentEntryInt != null) if (parentEntryInt != null)
{ {
entryTagsInternal[parentEntryInt].Count -= entryTag.Value.Count; entryTagsInternal[parentEntryInt].Count -= entryTag.Value.Count;
} }
continue; continue;
} }
var parentEntry = entryTagsProvider.Keys var parentEntry = entryTagsProvider.Keys
.FirstOrDefault(entryCountTag => Equals(entryCountTag.Id, entryTag.Key.ParentId)); .FirstOrDefault(entryCountTag => Equals(entryCountTag.Id, entryTag.Key.ParentId));
if (parentEntry != null) if (parentEntry != null)
{ {
entryTagsProvider[parentEntry].Count -= entryTag.Value.Count; entryTagsProvider[parentEntry].Count -= entryTag.Value.Count;
} }
} }
await foreach (var r in GetResultAsync(entryTagsInternal)) await foreach (var r in GetResultAsync(entryTagsInternal))
{ {
yield return r; yield return r;
@ -772,28 +770,28 @@ public class FileMarker
async IAsyncEnumerable<FileEntry> GetResultAsync<TEntry>(Dictionary<FileEntry<TEntry>, Tag> entryTags) async IAsyncEnumerable<FileEntry> GetResultAsync<TEntry>(Dictionary<FileEntry<TEntry>, Tag> entryTags)
{ {
foreach (var entryTag in entryTags) foreach (var entryTag in entryTags)
{ {
if (!string.IsNullOrEmpty(entryTag.Key.Error)) if (!string.IsNullOrEmpty(entryTag.Key.Error))
{
await RemoveMarkAsNewAsync(entryTag.Key);
continue;
}
if (entryTag.Value.Count > 0)
{ {
yield return entryTag.Key; await RemoveMarkAsNewAsync(entryTag.Key);
} continue;
} }
}
if (entryTag.Value.Count > 0)
{
yield return entryTag.Key;
}
}
}
} }
private async Task<Dictionary<FileEntry<T>, Tag>> GetEntryTagsAsync<T>(IAsyncEnumerable<Tag> tags) private async Task<Dictionary<FileEntry<T>, Tag>> GetEntryTagsAsync<T>(IAsyncEnumerable<Tag> tags)
{ {
var fileDao = _daoFactory.GetFileDao<T>(); var fileDao = _daoFactory.GetFileDao<T>();
var folderDao = _daoFactory.GetFolderDao<T>(); var folderDao = _daoFactory.GetFolderDao<T>();
var entryTags = new Dictionary<FileEntry<T>, Tag>(); var entryTags = new Dictionary<FileEntry<T>, Tag>();
await foreach (var tag in tags) await foreach (var tag in tags)
{ {
var entry = tag.EntryType == FileEntryType.File var entry = tag.EntryType == FileEntryType.File
@ -817,7 +815,7 @@ public class FileMarker
var tagDao = _daoFactory.GetTagDao<T>(); var tagDao = _daoFactory.GetTagDao<T>();
var folderDao = _daoFactory.GetFolderDao<T>(); var folderDao = _daoFactory.GetFolderDao<T>();
var totalTags = await tagDao.GetNewTagsAsync(_authContext.CurrentAccount.ID, parent, false).ToListAsync(); var totalTags = await tagDao.GetNewTagsAsync(_authContext.CurrentAccount.ID, parent, false).ToListAsync();
if (totalTags.Count <= 0) if (totalTags.Count <= 0)
{ {
return; return;
@ -977,13 +975,13 @@ public class FileMarker
} }
} }
} }
private void InsertToCahce(object folderId, int count) private void InsertToCahce(object folderId, int count)
{ {
var key = string.Format(CacheKeyFormat, _authContext.CurrentAccount.ID, folderId); var key = string.Format(CacheKeyFormat, _authContext.CurrentAccount.ID, folderId);
_cache.Insert(key, count.ToString(), TimeSpan.FromMinutes(10)); _cache.Insert(key, count.ToString(), TimeSpan.FromMinutes(10));
} }
private int GetCountFromCahce(object folderId) private int GetCountFromCahce(object folderId)
{ {
var key = string.Format(CacheKeyFormat, _authContext.CurrentAccount.ID, folderId); var key = string.Format(CacheKeyFormat, _authContext.CurrentAccount.ID, folderId);
@ -991,12 +989,12 @@ public class FileMarker
return count == null ? -1 : int.Parse(count); return count == null ? -1 : int.Parse(count);
} }
private void RemoveFromCahce(object folderId) private void RemoveFromCahce(object folderId)
{ {
RemoveFromCahce(folderId, _authContext.CurrentAccount.ID); RemoveFromCahce(folderId, _authContext.CurrentAccount.ID);
} }
private void RemoveFromCahce(object folderId, Guid userId) private void RemoveFromCahce(object folderId, Guid userId)
{ {
var key = string.Format(CacheKeyFormat, userId, folderId); var key = string.Format(CacheKeyFormat, userId, folderId);
@ -1018,7 +1016,7 @@ public class FileMarker
} }
} }
} }
[Transient] [Transient]
public class AsyncTaskData<T> : DistributedTask public class AsyncTaskData<T> : DistributedTask
{ {
@ -1027,13 +1025,13 @@ public class AsyncTaskData<T> : DistributedTask
TenantID = tenantManager.GetCurrentTenant().Id; TenantID = tenantManager.GetCurrentTenant().Id;
CurrentAccountId = authContext.CurrentAccount.ID; CurrentAccountId = authContext.CurrentAccount.ID;
} }
public int TenantID { get; private set; } public int TenantID { get; private set; }
public FileEntry<T> FileEntry { get; set; } public FileEntry<T> FileEntry { get; set; }
public List<Guid> UserIDs { get; set; } public List<Guid> UserIDs { get; set; }
public Guid CurrentAccountId { get; set; } public Guid CurrentAccountId { get; set; }
} }
public static class FileMarkerExtention public static class FileMarkerExtention
{ {
public static void Register(DIHelper services) public static void Register(DIHelper services)
@ -1043,4 +1041,4 @@ public static class FileMarkerExtention
services.TryAdd<AsyncTaskData<string>>(); services.TryAdd<AsyncTaskData<string>>();
} }
} }