You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Actual behavior
In FindAccessTokenAsync and FilterWithLogging, inefficient Linq is used when filtering the token collection resulting in unnecessary List object allocation.
Possible solution
Main tasks:
Replace IReadOnlyList with List in accessor and filtering methods.
In FilterWithLogging, replace list = list.Where(predicate).ToList(); with list.RemoveAll(e => !predicate(e));
Investigate if the same changes have to be made on other methods, like the refresh token filtering.
(optional) Investigate using SegmentedList instead of List
Run performance tests
Additional context / logs / screenshots / links to code
Context from conversation:
Notice there are 4+ branches, all from a single method. Here is the source code in MSAL library:
List<MsalAccessTokenCacheItem> tokenCacheItems = GetAllAccessTokensWithNoLocks(true, partitionKey);
requestParams.RequestContext.Logger.Always($"[FindAccessTokenAsync] Discovered {tokenCacheItems.Count} access tokens in cache using partition key: {partitionKey}");
if (tokenCacheItems.Count == 0)
{
logger.Verbose("No access tokens found in the cache. Skipping filtering. ");
requestParams.RequestContext.ApiEvent.CacheInfo = CacheRefreshReason.NoCachedAccessToken;
if (AcquireTokenInLongRunningOboWasCalled(requestParams))
{
logger.Error("[FindAccessTokenAsync] AcquireTokenInLongRunningProcess was called and OBO token was not found in the cache.");
throw new MsalClientException(MsalError.OboCacheKeyNotInCacheError, MsalErrorMessage.OboCacheKeyNotInCache);
}
return null;
}
FilterByHomeAccountTenantOrAssertion(requestParams, tokenCacheItems);
FilterByTokenType(requestParams, tokenCacheItems);
FilterByScopes(requestParams, tokenCacheItems);
await FilterByEnvironmentAsync(requestParams, tokenCacheItems).ConfigureAwait(false);
Now you just need a single list, with much reduced LOH allocations. The single list can either be reused or switched to use segmented list. So no LOH allocation is totally achievable.
Given that we’re doing multiple levels of filtering, it’s even possible to apply the most effective filter first, and/or combine them into a single stage filtering.
I said quite a few times that Linq.Enumerable is total disregard of proper data structure and algorithm design. The flip side of the story is you need precise selection/craftmanship in your data structure and algorithm design.
The text was updated successfully, but these errors were encountered:
Which version of MSAL.NET are you using?
4.40.0
Actual behavior
In FindAccessTokenAsync and FilterWithLogging, inefficient Linq is used when filtering the token collection resulting in unnecessary List object allocation.
Possible solution
Main tasks:
IReadOnlyList
withList
in accessor and filtering methods.FilterWithLogging
, replacelist = list.Where(predicate).ToList();
withlist.RemoveAll(e => !predicate(e));
SegmentedList
instead ofList
Additional context / logs / screenshots / links to code
Context from conversation:
The text was updated successfully, but these errors were encountered: