Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Caching of compiled rules. #63

Open
balajiforgithub opened this issue Apr 29, 2019 · 2 comments
Open

Caching of compiled rules. #63

balajiforgithub opened this issue Apr 29, 2019 · 2 comments

Comments

@balajiforgithub
Copy link

Hi,
I am using Flee.Net45 library for evaluating expressions in my application.

As rule compilation is taking time, can we cache the compiled rules to bypass the rule compilation process?

Sample code :
_expressionContext.CompileDynamic("expression")

Appreciate your help.

Thanks,
Balaji.

@PeterKnealeBizCover
Copy link

I'm just experimenting with how to solve the same issue and this seems to work nicely

	public class Rule
	{
		public string Id {get;set;}
		public string Expression {get;set;}
	}

	public interface IExpressionCache
    {
        IGenericExpression<bool> GetExpression(Rule rule, Context context);
    }

    public interface IExpressionCompiler
    {
        IGenericExpression<bool> Compiler(string expression, Context context);
        bool Execute(IGenericExpression<bool> compiled, Context context);
    }

    public class ExpressionCache : IExpressionCache
    {
        private readonly IExpressionCompiler _engine;
        private readonly ICache _cache;

        private static object locker = new object();

        public ExpressionCache(IExpressionCompiler engine, ICache cache)
        {
            _engine = engine;
            _cache = cache;
        }

        public IGenericExpression<bool> GetExpression(Rule rule, Context context)
        {
            var key = $"rule_{rule.Id}";

            // https://en.wikipedia.org/wiki/Double-checked_locking
            var compiled = _cache.Get<IGenericExpression<bool>>(key);
            if (compiled == null) // 1st check
            {
                lock (locker) // Enter critical section
                {
                    compiled = _cache.Get<IGenericExpression<bool>>(key);
                    if (compiled == null) // 2nd (double) check
                    {
                        // Create a new context and cache it
                        compiled = _engine.Compiler(rule.Expression, context);
                        _cache.Set(key, compiled);
                    }
                }
            }
            return compiled;
        }
    }


    public class ExpressionCompiler : IExpressionCompiler
    {
        private const string _contextVariableName = "Context";

        public IGenericExpression<bool> Compiler(string expression, Context context)
        {
            var ec = new ExpressionContext();
            ec.Variables.Add(_contextVariableName, context);
            return ec.CompileGeneric<bool>(expression);
        }

        public bool Execute(IGenericExpression<bool> compiled, Context context)
        {
            compiled.Context.Variables[_contextVariableName] = context;
            return compiled.Evaluate();
        }
    }

	public interface ICache
    {
        T Get<T>(string key);
        void Set<T>(string key, T value);
    }

    /// <summary>
    /// Naive cache
    /// TODO: configure 
    /// </summary>
    public class Cache : ICache
    {
        private readonly IMemoryCache _cache;

        public Cache(IMemoryCache cache)
        {
            _cache = cache;
        }

        public T Get<T>(string key)
        {
            return _cache.Get<T>(key);
        }

        public void Set<T>(string key, T value)
        {
            _cache.Set(key, value, TimeSpan.FromSeconds(5));
        }
    }

@hunkydoryrepair
Copy link
Contributor

I've also implemented a cache with a simple Dictionary. I think the application would best know how to do the caching

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants