Improved online search performance when doing local operations (#584)
* Improved online search performance when doing local operations * Retruning an empty list on no item searches. * Fixed an issue with batch imap downloads. --------- Co-authored-by: Burak Kaan Köse <bkaankose@outlook.com>
This commit is contained in:
@@ -61,6 +61,7 @@ public interface IDefaultChangeProcessor
|
||||
|
||||
Task UpdateCalendarDeltaSynchronizationToken(Guid calendarId, string deltaToken);
|
||||
Task<MailCopy> GetMailCopyAsync(string mailCopyId);
|
||||
Task<List<MailCopy>> GetMailCopiesAsync(IEnumerable<string> mailCopyIds);
|
||||
Task CreateMailRawAsync(MailAccount account, MailItemFolder mailItemFolder, NewMailItemPackage package);
|
||||
Task DeleteUserMailCacheAsync(Guid accountId);
|
||||
|
||||
@@ -73,6 +74,7 @@ public interface IDefaultChangeProcessor
|
||||
/// <param name="folderId">Folder's local id.</param>
|
||||
/// <returns>Whether mail exists in the folder or not.</returns>
|
||||
Task<bool> IsMailExistsInFolderAsync(string messageId, Guid folderId);
|
||||
Task<List<string>> AreMailsExistsAsync(IEnumerable<string> mailCopyIds);
|
||||
}
|
||||
|
||||
public interface IGmailChangeProcessor : IDefaultChangeProcessor
|
||||
@@ -139,9 +141,15 @@ public class DefaultChangeProcessor(IDatabaseService databaseService,
|
||||
public Task<bool> IsMailExistsAsync(string messageId)
|
||||
=> MailService.IsMailExistsAsync(messageId);
|
||||
|
||||
public Task<List<string>> AreMailsExistsAsync(IEnumerable<string> mailCopyIds)
|
||||
=> MailService.AreMailsExistsAsync(mailCopyIds);
|
||||
|
||||
public Task<MailCopy> GetMailCopyAsync(string mailCopyId)
|
||||
=> MailService.GetSingleMailItemAsync(mailCopyId);
|
||||
|
||||
public Task<List<MailCopy>> GetMailCopiesAsync(IEnumerable<string> mailCopyIds)
|
||||
=> MailService.GetMailItemsAsync(mailCopyIds);
|
||||
|
||||
public Task ChangeMailReadStatusAsync(string mailCopyId, bool isRead)
|
||||
=> MailService.ChangeReadStatusAsync(mailCopyId, isRead);
|
||||
|
||||
|
||||
@@ -1021,7 +1021,7 @@ public class GmailSynchronizer : WinoSynchronizer<IClientServiceRequest, Message
|
||||
|
||||
string pageToken = null;
|
||||
|
||||
var messagesToDownload = new List<Message>();
|
||||
List<Message> messagesToDownload = [];
|
||||
|
||||
do
|
||||
{
|
||||
@@ -1030,7 +1030,7 @@ public class GmailSynchronizer : WinoSynchronizer<IClientServiceRequest, Message
|
||||
// Ignore the folders if the query starts with these keywords.
|
||||
// User is trying to list everything.
|
||||
}
|
||||
else if (folders?.Any() ?? false)
|
||||
else if (folders?.Count > 0)
|
||||
{
|
||||
request.LabelIds = folders.Select(a => a.RemoteFolderId).ToList();
|
||||
}
|
||||
@@ -1044,49 +1044,23 @@ public class GmailSynchronizer : WinoSynchronizer<IClientServiceRequest, Message
|
||||
if (response.Messages == null) break;
|
||||
|
||||
// Handle skipping manually
|
||||
foreach (var message in response.Messages)
|
||||
{
|
||||
messagesToDownload.Add(message);
|
||||
}
|
||||
messagesToDownload.AddRange(response.Messages);
|
||||
|
||||
pageToken = response.NextPageToken;
|
||||
} while (!string.IsNullOrEmpty(pageToken));
|
||||
|
||||
// Do not download messages that exists, but return them for listing.
|
||||
|
||||
var messageIds = messagesToDownload.Select(a => a.Id).ToList();
|
||||
var messageIds = messagesToDownload.Select(a => a.Id);
|
||||
|
||||
List<string> downloadRequireMessageIds = new();
|
||||
|
||||
foreach (var messageId in messageIds)
|
||||
{
|
||||
var exists = await _gmailChangeProcessor.IsMailExistsAsync(messageId).ConfigureAwait(false);
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
downloadRequireMessageIds.Add(messageId);
|
||||
}
|
||||
}
|
||||
var downloadRequireMessageIds = messageIds.Except(await _gmailChangeProcessor.AreMailsExistsAsync(messageIds));
|
||||
|
||||
// Download missing messages.
|
||||
await BatchDownloadMessagesAsync(downloadRequireMessageIds, cancellationToken);
|
||||
|
||||
// Get results from database and return.
|
||||
|
||||
var searchResults = new List<MailCopy>();
|
||||
|
||||
foreach (var messageId in messageIds)
|
||||
{
|
||||
var copy = await _gmailChangeProcessor.GetMailCopyAsync(messageId).ConfigureAwait(false);
|
||||
|
||||
if (copy == null) continue;
|
||||
|
||||
searchResults.Add(copy);
|
||||
}
|
||||
|
||||
return searchResults;
|
||||
|
||||
// TODO: Return the search result ids.
|
||||
return await _gmailChangeProcessor.GetMailCopiesAsync(messageIds);
|
||||
}
|
||||
|
||||
public override async Task DownloadMissingMimeMessageAsync(IMailItem mailItem,
|
||||
|
||||
@@ -84,19 +84,13 @@ public abstract class ImapSynchronizationStrategyBase : IImapSynchronizerStrateg
|
||||
// Fetch the new mails in batch.
|
||||
|
||||
var batchedMessageIds = newMessageIds.Batch(50).ToList();
|
||||
var downloadTasks = new List<Task>();
|
||||
|
||||
// Create tasks for each batch.
|
||||
foreach (var group in batchedMessageIds)
|
||||
{
|
||||
downloadedMessageIds.AddRange(group.Select(a => MailkitClientExtensions.CreateUid(Folder.Id, a.Id)));
|
||||
var task = DownloadMessagesAsync(synchronizer, remoteFolder, new UniqueIdSet(group), cancellationToken);
|
||||
downloadTasks.Add(task);
|
||||
await DownloadMessagesAsync(synchronizer, remoteFolder, Folder, new UniqueIdSet(group), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// Wait for all batches to complete.
|
||||
await Task.WhenAll(downloadTasks).ConfigureAwait(false);
|
||||
|
||||
return downloadedMessageIds;
|
||||
}
|
||||
|
||||
@@ -167,6 +161,7 @@ public abstract class ImapSynchronizationStrategyBase : IImapSynchronizerStrateg
|
||||
|
||||
public async Task DownloadMessagesAsync(IImapSynchronizer synchronizer,
|
||||
IMailFolder folder,
|
||||
MailItemFolder localFolder,
|
||||
UniqueIdSet uniqueIdSet,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -178,7 +173,7 @@ public abstract class ImapSynchronizationStrategyBase : IImapSynchronizerStrateg
|
||||
|
||||
var creationPackage = new ImapMessageCreationPackage(summary, mimeMessage);
|
||||
|
||||
var mailPackages = await synchronizer.CreateNewMailPackagesAsync(creationPackage, Folder, cancellationToken).ConfigureAwait(false);
|
||||
var mailPackages = await synchronizer.CreateNewMailPackagesAsync(creationPackage, localFolder, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (mailPackages != null)
|
||||
{
|
||||
@@ -187,7 +182,7 @@ public abstract class ImapSynchronizationStrategyBase : IImapSynchronizerStrateg
|
||||
// Local draft is mapped. We don't need to create a new mail copy.
|
||||
if (package == null) continue;
|
||||
|
||||
await MailService.CreateMailAsync(Folder.MailAccountId, package).ConfigureAwait(false);
|
||||
await MailService.CreateMailAsync(localFolder.MailAccountId, package).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -639,52 +639,48 @@ public class ImapSynchronizer : WinoSynchronizer<ImapRequest, ImapMessageCreatio
|
||||
{
|
||||
client = await _clientPool.GetClientAsync().ConfigureAwait(false);
|
||||
|
||||
var searchResults = new List<MailCopy>();
|
||||
List<string> searchResultFolderMailUids = new();
|
||||
List<MailCopy> searchResults = [];
|
||||
List<string> searchResultFolderMailUids = [];
|
||||
|
||||
foreach (var folder in folders)
|
||||
{
|
||||
var remoteFolder = await client.GetFolderAsync(folder.RemoteFolderId).ConfigureAwait(false);
|
||||
var remoteFolder = await client.GetFolderAsync(folder.RemoteFolderId, cancellationToken).ConfigureAwait(false);
|
||||
await remoteFolder.OpenAsync(FolderAccess.ReadOnly, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// Look for subject and body.
|
||||
var query = SearchQuery.BodyContains(queryText).Or(SearchQuery.SubjectContains(queryText));
|
||||
|
||||
var searchResultsInFolder = await remoteFolder.SearchAsync(query, cancellationToken).ConfigureAwait(false);
|
||||
var nonExisttingUniqueIds = new List<UniqueId>();
|
||||
Dictionary<string, UniqueId> searchResultsIdsInFolder = [];
|
||||
|
||||
foreach (var searchResultId in searchResultsInFolder)
|
||||
{
|
||||
var folderMailUid = MailkitClientExtensions.CreateUid(folder.Id, searchResultId.Id);
|
||||
searchResultFolderMailUids.Add(folderMailUid);
|
||||
|
||||
bool exists = await _imapChangeProcessor.IsMailExistsAsync(folderMailUid);
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
nonExisttingUniqueIds.Add(searchResultId);
|
||||
}
|
||||
searchResultsIdsInFolder.Add(folderMailUid, searchResultId);
|
||||
}
|
||||
|
||||
if (nonExisttingUniqueIds.Any())
|
||||
// Populate no foundIds
|
||||
var foundIds = await _imapChangeProcessor.AreMailsExistsAsync(searchResultsIdsInFolder.Select(a => a.Key));
|
||||
var notFoundIds = searchResultsIdsInFolder.Keys.Except(foundIds);
|
||||
|
||||
List<UniqueId> nonExistingUniqueIds = [];
|
||||
foreach (var nonExistingId in notFoundIds)
|
||||
{
|
||||
nonExistingUniqueIds.Add(searchResultsIdsInFolder[nonExistingId]);
|
||||
}
|
||||
|
||||
if (nonExistingUniqueIds.Count != 0)
|
||||
{
|
||||
var syncStrategy = _imapSynchronizationStrategyProvider.GetSynchronizationStrategy(client);
|
||||
await syncStrategy.DownloadMessagesAsync(this, remoteFolder, new UniqueIdSet(nonExisttingUniqueIds, SortOrder.Ascending), cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await syncStrategy.DownloadMessagesAsync(this, remoteFolder, folder as MailItemFolder, new UniqueIdSet(nonExistingUniqueIds, SortOrder.Ascending), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await remoteFolder.CloseAsync().ConfigureAwait(false);
|
||||
await remoteFolder.CloseAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
foreach (var messageId in searchResultFolderMailUids)
|
||||
{
|
||||
var copy = await _imapChangeProcessor.GetMailCopyAsync(messageId).ConfigureAwait(false);
|
||||
|
||||
if (copy == null) continue;
|
||||
|
||||
searchResults.Add(copy);
|
||||
}
|
||||
|
||||
return searchResults;
|
||||
return await _imapChangeProcessor.GetMailCopiesAsync(searchResultFolderMailUids);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -700,8 +696,6 @@ public class ImapSynchronizer : WinoSynchronizer<ImapRequest, ImapMessageCreatio
|
||||
|
||||
_clientPool.Release(client);
|
||||
}
|
||||
|
||||
return new List<MailCopy>();
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<string>> SynchronizeFolderInternalAsync(MailItemFolder folder, CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -1054,18 +1054,7 @@ public class OutlookSynchronizer : WinoSynchronizer<RequestInformation, Message,
|
||||
}
|
||||
|
||||
// Get results from database and return.
|
||||
var searchResults = new List<MailCopy>();
|
||||
|
||||
foreach (var messageId in existingMessageIds)
|
||||
{
|
||||
var copy = await _outlookChangeProcessor.GetMailCopyAsync(messageId).ConfigureAwait(false);
|
||||
|
||||
if (copy == null) continue;
|
||||
|
||||
searchResults.Add(copy);
|
||||
}
|
||||
|
||||
return searchResults;
|
||||
return await _outlookChangeProcessor.GetMailCopiesAsync(existingMessageIds);
|
||||
}
|
||||
|
||||
private async Task<MimeMessage> DownloadMimeMessageAsync(string messageId, CancellationToken cancellationToken = default)
|
||||
|
||||
Reference in New Issue
Block a user