Skip to content

Commit

Permalink
Prevent user attributes dictionary from being created multiple times …
Browse files Browse the repository at this point in the history
…per evaluation
  • Loading branch information
adams85 committed Nov 7, 2023
1 parent 1fb9f2d commit 0522f72
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 18 deletions.
15 changes: 10 additions & 5 deletions src/ConfigCatClient/Evaluation/EvaluateContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using ConfigCat.Client.Utils;

namespace ConfigCat.Client.Evaluation;
Expand All @@ -7,11 +8,15 @@ internal struct EvaluateContext
{
public readonly string Key;
public readonly Setting Setting;
public readonly User? User;
public readonly IReadOnlyDictionary<string, Setting> Settings;

private readonly User? user;

[MemberNotNullWhen(true, nameof(UserAttributes))]
public readonly bool IsUserAvailable => this.user is not null;

private IReadOnlyDictionary<string, string>? userAttributes;
public IReadOnlyDictionary<string, string>? UserAttributes => this.userAttributes ??= this.User?.GetAllAttributes();
public IReadOnlyDictionary<string, string>? UserAttributes => this.userAttributes ??= this.user?.GetAllAttributes();

private List<string>? visitedFlags;
public List<string> VisitedFlags => this.visitedFlags ??= new List<string>();
Expand All @@ -25,7 +30,7 @@ public EvaluateContext(string key, Setting setting, User? user, IReadOnlyDiction
{
this.Key = key;
this.Setting = setting;
this.User = user;
this.user = user;
this.Settings = settings;

this.userAttributes = null;
Expand All @@ -35,9 +40,9 @@ public EvaluateContext(string key, Setting setting, User? user, IReadOnlyDiction
}

public EvaluateContext(string key, Setting setting, ref EvaluateContext dependentFlagContext)
: this(key, setting, dependentFlagContext.User, dependentFlagContext.Settings)
: this(key, setting, dependentFlagContext.user, dependentFlagContext.Settings)
{
this.userAttributes = dependentFlagContext.userAttributes;
this.userAttributes = dependentFlagContext.UserAttributes;
this.visitedFlags = dependentFlagContext.VisitedFlags; // crucial to use the property here to make sure the list is created!
this.LogBuilder = dependentFlagContext.LogBuilder;
}
Expand Down
21 changes: 8 additions & 13 deletions src/ConfigCatClient/Evaluation/RolloutEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public EvaluateResult Evaluate<T>(T defaultValue, ref EvaluateContext context, [

logBuilder.Append($"Evaluating '{context.Key}'");

if (context.User is not null)
if (context.IsUserAvailable)
{
logBuilder.Append($" for User '{context.UserAttributes.Serialize()}'");
}
Expand Down Expand Up @@ -173,7 +173,7 @@ private bool TryEvaluatePercentageOptions(PercentageOption[] percentageOptions,
{
var logBuilder = context.LogBuilder;

if (context.User is null)
if (!context.IsUserAvailable)
{
logBuilder?.NewLine("Skipping % options because the User Object is missing.");

Expand All @@ -187,14 +187,9 @@ private bool TryEvaluatePercentageOptions(PercentageOption[] percentageOptions,
return false;
}

string? percentageOptionsAttributeValue;
var percentageOptionsAttributeName = context.Setting.PercentageOptionsAttribute;
if (percentageOptionsAttributeName is null)
{
percentageOptionsAttributeName = nameof(User.Identifier);
percentageOptionsAttributeValue = context.User.Identifier;
}
else if (!context.UserAttributes!.TryGetValue(percentageOptionsAttributeName, out percentageOptionsAttributeValue))
var percentageOptionsAttributeName = context.Setting.PercentageOptionsAttribute ?? nameof(User.Identifier);

if (!context.UserAttributes.TryGetValue(percentageOptionsAttributeName, out var percentageOptionsAttributeValue))
{
logBuilder?.NewLine().Append($"Skipping % options because the User.{percentageOptionsAttributeName} attribute is missing.");

Expand Down Expand Up @@ -334,7 +329,7 @@ private bool EvaluateUserCondition(UserCondition condition, string contextSalt,
var logBuilder = context.LogBuilder;
logBuilder?.AppendUserCondition(condition);

if (context.User is null)
if (!context.IsUserAvailable)
{
if (!context.IsMissingUserObjectLogged)
{
Expand All @@ -348,7 +343,7 @@ private bool EvaluateUserCondition(UserCondition condition, string contextSalt,

var userAttributeName = condition.ComparisonAttribute ?? throw new InvalidOperationException("Comparison attribute name is missing.");

if (!(context.UserAttributes!.TryGetValue(userAttributeName, out var userAttributeValue) && userAttributeValue.Length > 0))
if (!(context.UserAttributes.TryGetValue(userAttributeName, out var userAttributeValue) && userAttributeValue.Length > 0))
{
this.logger.UserObjectAttributeIsMissing(condition.ToString(), context.Key, userAttributeName);
error = string.Format(CultureInfo.InvariantCulture, MissingUserAttributeError, userAttributeName);
Expand Down Expand Up @@ -783,7 +778,7 @@ private bool EvaluateSegmentCondition(SegmentCondition condition, ref EvaluateCo
var logBuilder = context.LogBuilder;
logBuilder?.AppendSegmentCondition(condition);

if (context.User is null)
if (!context.IsUserAvailable)
{
if (!context.IsMissingUserObjectLogged)
{
Expand Down

0 comments on commit 0522f72

Please sign in to comment.