Exemplo n.º 1
0
        /// <summary>
        /// Gets by the tenant identifier.
        /// </summary>
        private TColl GetByTenantId(Guid tenantId)
        {
            // Check if it exists; if so then return.
            if (_dict.TryGetValue(tenantId, out CacheValue <TColl> cv) && !cv.Policy.HasExpired())
            {
                return(cv.Value);
            }

            // Lock against the key to minimise concurrent gets (which could be expensive).
            lock (_keyLock.Lock(tenantId))
            {
                if (_dict.TryGetValue(tenantId, out cv) && !cv.Policy.HasExpired())
                {
                    return(cv.Value);
                }

                var coll = GetCollectionInternal();

                var policy = (ICachePolicy)GetPolicy().Clone();
                policy.Reset();

                cv = _dict.GetOrAdd(tenantId, new CacheValue <TColl> {
                    Policy = policy, Value = coll
                });
                return(cv.Value);
            }
        }
Exemplo n.º 2
0
        public bool Match(CartRuleContext context, RuleExpression expression)
        {
            var sessionKey = context.SessionKey;
            var lockKey    = "rule:cart:carttotalrule:" + sessionKey.ToString();

            if (KeyedLock.IsLockHeld(lockKey))
            {
                return(false);
            }

            // We must prevent the rule from indirectly calling itself. It would cause a stack overflow on cart page.
            using (KeyedLock.Lock(lockKey))
            {
                var cart = _shoppingCartService.GetCartItems(context.Customer, ShoppingCartType.ShoppingCart, context.Store.Id);

                var cartTotal = ((decimal?)_orderTotalCalculationService.GetShoppingCartTotal(cart)) ?? decimal.Zero;

                // Currency values must be rounded, otherwise unexpected results may occur.
                var money = new Money(cartTotal, context.WorkContext.WorkingCurrency);
                cartTotal = money.RoundedAmount;

                var result = expression.Operator.Match(cartTotal, expression.Value);
                return(result);
            }
        }
Exemplo n.º 3
0
        public bool Match(CartRuleContext context, RuleExpression expression)
        {
            var lockKey = $"rule:cart:cartsubtotalrule:{Thread.CurrentThread.ManagedThreadId}-{expression.Id}";

            if (KeyedLock.IsLockHeld(lockKey))
            {
                //$"locked: {lockKey}".Dump();
                return(false);
            }

            // We must prevent the rule from indirectly calling itself. It would cause a stack overflow on cart page.
            using (KeyedLock.Lock(lockKey))
            {
                var cart = _shoppingCartService.GetCartItems(context.Customer, ShoppingCartType.ShoppingCart, context.Store.Id);

                _orderTotalCalculationService.GetShoppingCartSubTotal(cart, out _, out _, out var cartSubtotal, out _);

                // Currency values must be rounded, otherwise unexpected results may occur.
                var money = new Money(cartSubtotal, context.WorkContext.WorkingCurrency);
                cartSubtotal = money.RoundedAmount;

                var result = expression.Operator.Match(cartSubtotal, expression.Value);
                //$"unlocked {result}: {lockKey}".Dump();
                return(result);
            }
        }
Exemplo n.º 4
0
        public T Get <T>(string key, Func <T> acquirer, TimeSpan?duration = null, bool independent = false)
        {
            if (TryGet(key, independent, out T value))
            {
                return(value);
            }

            if (_scopeAccessor.Value.HasScope(key))
            {
                throw new LockRecursionException(LockRecursionExceptionMessage.FormatInvariant(key));
            }

            // Get the (semaphore) locker specific to this key
            using (KeyedLock.Lock("cache:" + key, TimeSpan.FromMinutes(1)))
            {
                // Atomic operation must be outer locked
                if (!TryGet(key, independent, out value))
                {
                    using (_scopeAccessor.Value.BeginScope(key))
                    {
                        value = acquirer();
                        Put(key, value, duration, _scopeAccessor.Value.Current.Dependencies);
                        return(value);
                    }
                }
            }

            return(value);
        }
Exemplo n.º 5
0
        public void LockOnSameKey2()
        {
            var kl = new KeyedLock <int>();
            var cd = new ConcurrentDictionary <int, int>();

            var inLock = false;

            Parallel.ForEach(new int[] { 1, 1, 1, 1, 1, 1 }, (key) =>
            {
                TestContext.WriteLine($"{System.Threading.Thread.CurrentThread.ManagedThreadId} X");

                kl.Lock <int>(key, () =>
                {
                    Assert.IsFalse(inLock);

                    inLock = true;
                    TestContext.WriteLine($"{System.Threading.Thread.CurrentThread.ManagedThreadId} XX");
                    System.Threading.Thread.Sleep(10);
                    TestContext.WriteLine($"{System.Threading.Thread.CurrentThread.ManagedThreadId} XXX");
                    inLock = false;
                    return(key);
                });

                TestContext.WriteLine($"{System.Threading.Thread.CurrentThread.ManagedThreadId} XXXX");
            });
        }
Exemplo n.º 6
0
        public CachedAssetEntry InsertAsset(string virtualPath, IEnumerable <string> virtualPathDependencies, string content, params string[] processorCodes)
        {
            if (!_isEnabled)
            {
                return(null);
            }

            Guard.NotEmpty(virtualPath, nameof(virtualPath));
            Guard.NotEmpty(content, nameof(content));

            var cacheDirectoryName = ResolveCacheDirectoryName(virtualPath, out string themeName, out int storeId);

            using (KeyedLock.Lock(BuildLockKey(cacheDirectoryName)))
            {
                CacheFolder.CreateDirectory(cacheDirectoryName);

                try
                {
                    // Save main content file
                    // TODO: determine correct file extension
                    CreateFileFromEntries(cacheDirectoryName, "asset.css", new[] { content });

                    // Save dependencies file
                    var deps = ResolveVirtualPathDependencies(virtualPath, virtualPathDependencies, themeName);
                    CreateFileFromEntries(cacheDirectoryName, "asset.dependencies", deps);

                    // Save hash file
                    var currentHash = BundleTable.VirtualPathProvider.GetFileHash(virtualPath, deps);
                    CreateFileFromEntries(cacheDirectoryName, "asset.hash", new[] { currentHash });

                    // Save codes file
                    CreateFileFromEntries(cacheDirectoryName, "asset.pcodes", processorCodes);

                    var entry = new CachedAssetEntry
                    {
                        Content                 = content,
                        HashCode                = currentHash,
                        OriginalVirtualPath     = virtualPath,
                        VirtualPathDependencies = deps,
                        PhysicalPath            = CacheFolder.MapPath(cacheDirectoryName),
                        ThemeName               = themeName,
                        StoreId                 = storeId,
                        ProcessorCodes          = processorCodes
                    };

                    SetupEvictionObserver(entry);

                    Logger.DebugFormat("Succesfully inserted asset '{0}' to cache.", virtualPath);

                    return(entry);
                }
                catch (Exception ex)
                {
                    Logger.ErrorFormat(ex, "Error while inserting asset '{0}' to the asset cache.", virtualPath);
                    InvalidateAssetInternal(cacheDirectoryName, themeName, storeId);
                }
            }

            return(null);
        }
Exemplo n.º 7
0
        public T Get <T>(string key, Func <T> acquirer, TimeSpan?duration = null, bool independent = false, bool allowRecursion = false)
        {
            if (TryGet(key, independent, out T value))
            {
                return(value);
            }

            if (!allowRecursion && _scopeAccessor.Value.HasScope(key))
            {
                throw new LockRecursionException(LockRecursionExceptionMessage.FormatInvariant(key));
            }

            // Get the (semaphore) locker specific to this key
            using (KeyedLock.Lock("cache:" + key, TimeSpan.FromSeconds(5)))
            {
                // Atomic operation must be outer locked
                if (!TryGet(key, independent, out value))
                {
                    var scope = !allowRecursion?_scopeAccessor.Value.BeginScope(key) : ActionDisposable.Empty;

                    using (scope)
                    {
                        value = acquirer();
                        var dependencies = !allowRecursion ? _scopeAccessor.Value.Current?.Dependencies : (IEnumerable <string>)null;
                        Put(key, value, duration, dependencies);
                        return(value);
                    }
                }
            }

            return(value);
        }
Exemplo n.º 8
0
        public virtual DbCacheEntry Put(string key, object value, IEnumerable <string> dependentEntitySets, TimeSpan?duration)
        {
            if (!Enabled || IsToxic(dependentEntitySets))
            {
                return(null);
            }

            key = HashKey(key);

            using (KeyedLock.Lock(key))
            {
                var entitySets = dependentEntitySets.Distinct().ToArray();
                var entry      = new DbCacheEntry
                {
                    Key         = key,
                    Value       = value,
                    EntitySets  = entitySets,
                    CachedOnUtc = DateTime.UtcNow,
                    Duration    = duration
                };

                _cache.Put(key, entry);

                foreach (var entitySet in entitySets)
                {
                    var lookup = GetLookupSet(entitySet);
                    lookup.Add(key);
                }

                return(entry);
            }
        }
Exemplo n.º 9
0
        public virtual bool TryGet(string key, out object value)
        {
            value = null;

            if (!Enabled)
            {
                return(false);
            }

            key = HashKey(key);
            var now = DateTime.UtcNow;

            var entry = _cache.Get <DbCacheEntry>(key, independent: true);

            if (entry != null)
            {
                if (entry.HasExpired(now))
                {
                    using (KeyedLock.Lock(key))
                    {
                        InvalidateItemUnlocked(entry);
                    }
                }
                else
                {
                    value = entry.Value;
                    return(true);
                }
            }

            return(false);
        }
Exemplo n.º 10
0
        public virtual void InvalidateItem(string key)
        {
            if (!Enabled)
            {
                return;
            }

            Guard.NotEmpty(key, nameof(key));

            using (KeyedLock.Lock(key))
            {
                InvalidateItemUnlocked(key);
            }
        }
Exemplo n.º 11
0
        public bool InvalidateAsset(string virtualPath)
        {
            Guard.NotEmpty(virtualPath, nameof(virtualPath));

            var cacheDirectoryName = ResolveCacheDirectoryName(virtualPath, out string themeName, out int storeId);

            using (KeyedLock.Lock(BuildLockKey(cacheDirectoryName)))
            {
                if (CacheFolder.DirectoryExists(cacheDirectoryName))
                {
                    return(InvalidateAssetInternal(cacheDirectoryName, themeName, storeId));
                }

                return(false);
            }
        }
Exemplo n.º 12
0
        public string Build(BundleType type, IEnumerable <string> files)
        {
            if (files == null || !files.Any())
            {
                return(string.Empty);
            }

            var bundleVirtualPath = this.GetBundleVirtualPath(type, files);
            var bundleFor         = BundleTable.Bundles.GetBundleFor(bundleVirtualPath);

            if (bundleFor == null)
            {
                using (KeyedLock.Lock("BundleBuilder.Build." + bundleVirtualPath))
                {
                    bundleFor = BundleTable.Bundles.GetBundleFor(bundleVirtualPath);
                    if (bundleFor == null)
                    {
                        var nullOrderer = new NullOrderer();

                        Bundle bundle = (type == BundleType.Script) ?
                                        new CustomScriptBundle(bundleVirtualPath) as Bundle :
                                        new SmartStyleBundle(bundleVirtualPath) as Bundle;
                        bundle.Orderer = nullOrderer;

                        bundle.Include(files.ToArray());

                        BundleTable.Bundles.Add(bundle);
                    }
                }
            }

            if (type == BundleType.Script)
            {
                return(Scripts.Render(bundleVirtualPath).ToString());

                //// Uncomment this if you want to bypass asset caching on mobile browsers
                //return Scripts.RenderFormat("<script src='{0}?" + CommonHelper.GenerateRandomDigitCode(5) + "'></script>",
                //	files.Select(x => VirtualPathUtility.ToAppRelative(x)).ToArray()).ToString();
            }

            return(Styles.Render(bundleVirtualPath).ToString());
        }
Exemplo n.º 13
0
        public void LockOnDifferentKey2()
        {
            var kl = new KeyedLock <int>();
            var cd = new ConcurrentDictionary <int, int>();

            var inLock1 = false;
            var inLock2 = false;

            Parallel.ForEach(new int[] { 1, 2, 1, 2, 1, 2 }, (key) =>
            {
                TestContext.WriteLine($"{System.Threading.Thread.CurrentThread.ManagedThreadId} X");

                kl.Lock <int>(key, () =>
                {
                    if (key == 1)
                    {
                        Assert.IsFalse(inLock1);

                        inLock1 = true;
                        TestContext.WriteLine($"{System.Threading.Thread.CurrentThread.ManagedThreadId} XX");
                        System.Threading.Thread.Sleep(10);
                        TestContext.WriteLine($"{System.Threading.Thread.CurrentThread.ManagedThreadId} XXX");
                        inLock1 = false;
                    }
                    else
                    {
                        Assert.IsFalse(inLock2);

                        inLock2 = true;
                        TestContext.WriteLine($"{System.Threading.Thread.CurrentThread.ManagedThreadId} XX");
                        System.Threading.Thread.Sleep(10);
                        TestContext.WriteLine($"{System.Threading.Thread.CurrentThread.ManagedThreadId} XXX");
                        inLock2 = false;
                    }

                    return(key);
                });

                TestContext.WriteLine($"{System.Threading.Thread.CurrentThread.ManagedThreadId} XXXX");
            });
        }
Exemplo n.º 14
0
        public CachedAssetEntry GetAsset(string virtualPath)
        {
            if (!_isEnabled)
            {
                return(null);
            }

            Guard.NotEmpty(virtualPath, nameof(virtualPath));

            var cacheDirectoryName = ResolveCacheDirectoryName(virtualPath, out string themeName, out int storeId);

            if (CacheFolder.DirectoryExists(cacheDirectoryName))
            {
                try
                {
                    var deps = CacheFolder.ReadFile(CacheFolder.Combine(cacheDirectoryName, "asset.dependencies"));
                    var hash = CacheFolder.ReadFile(CacheFolder.Combine(cacheDirectoryName, "asset.hash"));

                    if (!TryValidate(virtualPath, deps, hash, out IEnumerable <string> parsedDeps, out string currentHash))
                    {
                        Logger.DebugFormat("Invalidating cached asset for '{0}' because it is not valid anymore.", virtualPath);
                        InvalidateAssetInternal(cacheDirectoryName, themeName, storeId);
                        return(null);
                    }

                    // TODO: determine correct file extension
                    var content = CacheFolder.ReadFile(CacheFolder.Combine(cacheDirectoryName, "asset.css"));
                    if (content == null)
                    {
                        using (KeyedLock.Lock(BuildLockKey(cacheDirectoryName)))
                        {
                            InvalidateAssetInternal(cacheDirectoryName, themeName, storeId);
                            return(null);
                        }
                    }

                    var codes = ParseFileContent(CacheFolder.ReadFile(CacheFolder.Combine(cacheDirectoryName, "asset.pcodes")));

                    var entry = new CachedAssetEntry
                    {
                        Content                 = content,
                        HashCode                = currentHash,
                        OriginalVirtualPath     = virtualPath,
                        VirtualPathDependencies = parsedDeps,
                        PhysicalPath            = CacheFolder.MapPath(cacheDirectoryName),
                        ThemeName               = themeName,
                        StoreId                 = storeId,
                        ProcessorCodes          = codes.ToArray()
                    };

                    SetupEvictionObserver(entry);

                    Logger.DebugFormat("Succesfully read asset '{0}' from cache.", virtualPath);

                    return(entry);
                }
                catch (Exception ex)
                {
                    Logger.ErrorFormat(ex, "Error while resolving asset '{0}' from the asset cache.", virtualPath);
                }
            }

            return(null);
        }
Exemplo n.º 15
0
        private IAsset TranslateInternal(IAsset asset)
        {
            IAsset result;
            var    chronometer = EngineContext.Current.Resolve <IChronometer>();

            using (chronometer.Step("Translate asset {0}".FormatInvariant(asset.VirtualPath)))
            {
                bool validationMode = ThemeHelper.IsStyleValidationRequest();

                if (validationMode || !TryGetCachedAsset(asset, out result))
                {
                    using (KeyedLock.Lock("CachedAsset:" + asset.VirtualPath))
                    {
                        if (validationMode || !TryGetCachedAsset(asset, out result))
                        {
                            using (chronometer.Step("Compile asset {0}".FormatInvariant(asset.VirtualPath)))
                            {
                                result = _inner.Translate(asset);

                                var cachedAsset = new CachedAsset
                                {
                                    AssetTypeCode           = AssetTypeCode.Css,
                                    IsStylesheet            = true,
                                    Minified                = result.Minified,
                                    Combined                = result.Combined,
                                    Content                 = result.Content,
                                    OriginalAssets          = asset.OriginalAssets,
                                    VirtualPath             = asset.VirtualPath,
                                    VirtualPathDependencies = result.VirtualPathDependencies,
                                    Url = asset.Url
                                };

                                result = AssetTranslorUtil.PostProcessAsset(cachedAsset, this.IsDebugMode);

                                if (!validationMode)
                                {
                                    var pCodes = new List <string>(3);
                                    if (cachedAsset.Minified)
                                    {
                                        pCodes.Add(DefaultAssetCache.MinificationCode);
                                    }
                                    if (cachedAsset.RelativePathsResolved)
                                    {
                                        pCodes.Add(DefaultAssetCache.UrlRewriteCode);
                                    }
                                    if (cachedAsset.Autoprefixed)
                                    {
                                        pCodes.Add(DefaultAssetCache.AutoprefixCode);
                                    }

                                    AssetCache.InsertAsset(
                                        cachedAsset.VirtualPath,
                                        cachedAsset.VirtualPathDependencies,
                                        cachedAsset.Content,
                                        pCodes.ToArray());
                                }
                            }
                        }
                    }
                }
            }

            return(result);
        }