private bool SetNoScript(CacheItem <TCacheValue> item, StackRedis.When when, bool sync = false)
        {
            return(this.Retry(() =>
            {
                var fullKey = GetKey(item.Key, item.Region);
                var value = this.ToRedisValue(item.Value);

                StackRedis.HashEntry[] metaValues = new[]
                {
                    new StackRedis.HashEntry(HashFieldType, item.ValueType.AssemblyQualifiedName),
                    new StackRedis.HashEntry(HashFieldExpirationMode, (int)item.ExpirationMode),
                    new StackRedis.HashEntry(HashFieldExpirationTimeout, (long)item.ExpirationTimeout.TotalMilliseconds),
                    new StackRedis.HashEntry(HashFieldCreated, item.CreatedUtc.Ticks),
                    new StackRedis.HashEntry(HashFieldUsesDefaultExp, item.UsesExpirationDefaults)
                };

                var flags = sync ? StackRedis.CommandFlags.None : StackRedis.CommandFlags.FireAndForget;

                var setResult = this.connection.Database.HashSet(fullKey, HashFieldValue, value, when, flags);

                // setResult from fire and forget is alwys false, so we have to assume it works...
                setResult = flags == StackRedis.CommandFlags.FireAndForget ? true : setResult;

                if (setResult)
                {
                    if (!string.IsNullOrWhiteSpace(item.Region))
                    {
                        // setting region lookup key if region is being used
                        this.connection.Database.HashSet(item.Region, fullKey, "regionKey", StackRedis.When.Always, StackRedis.CommandFlags.FireAndForget);
                    }

                    // set the additional fields in case sliding expiration should be used in this
                    // case we have to store the expiration mode and timeout on the hash, too so
                    // that we can extend the expiration period every time we do a get
                    if (metaValues != null)
                    {
                        this.connection.Database.HashSet(fullKey, metaValues, flags);
                    }

                    if (item.ExpirationMode != ExpirationMode.None && item.ExpirationMode != ExpirationMode.Default)
                    {
                        this.connection.Database.KeyExpire(fullKey, item.ExpirationTimeout, StackRedis.CommandFlags.FireAndForget);
                    }
                    else
                    {
                        // bugfix #9
                        this.connection.Database.KeyPersist(fullKey, StackRedis.CommandFlags.FireAndForget);
                    }
                }

                return setResult;
            }));
        }
#pragma warning disable CSE0003
        private bool Set(CacheItem <TCacheValue> item, StackRedis.When when, bool sync = false)
        {
            // TODO: move the whole logic into a script to make it atomic
            return(this.Retry(() =>
            {
                var fullKey = GetKey(item.Key, item.Region);
                var value = this.ToRedisValue(item.Value);

                StackRedis.HashEntry[] metaValues = new[]
                {
                    new StackRedis.HashEntry(HashFieldType, item.ValueType.AssemblyQualifiedName),
                    new StackRedis.HashEntry(HashFieldExpirationMode, (int)item.ExpirationMode),
                    new StackRedis.HashEntry(HashFieldExpirationTimeout, item.ExpirationTimeout.Ticks),
                    new StackRedis.HashEntry(HashFieldCreated, item.CreatedUtc.Ticks)
                };

                var flags = sync ? StackRedis.CommandFlags.None : StackRedis.CommandFlags.FireAndForget;

                var setResult = this.Database.HashSet(fullKey, HashFieldValue, value, when, flags);

                // setResult from fire and forget is alwys false, so we have to assume it works...
                setResult = flags == StackRedis.CommandFlags.FireAndForget ? true : setResult;

                if (setResult)
                {
                    // update region lookup
                    if (!string.IsNullOrWhiteSpace(item.Region))
                    {
                        this.Database.HashSet(item.Region, item.Key, "regionKey", when, StackRedis.CommandFlags.FireAndForget);
                    }

                    // set the additional fields in case sliding expiration should be used in this
                    // case we have to store the expiration mode and timeout on the hash, too so
                    // that we can extend the expiration period every time we do a get
                    if (metaValues != null)
                    {
                        this.Database.HashSet(fullKey, metaValues, flags);
                    }

                    if (item.ExpirationMode != ExpirationMode.None)
                    {
                        this.Database.KeyExpire(fullKey, item.ExpirationTimeout, StackRedis.CommandFlags.FireAndForget);
                    }
                    else
                    {
                        // bugfix #9
                        this.Database.KeyExpire(fullKey, default(TimeSpan?), StackRedis.CommandFlags.FireAndForget);
                    }
                }

                return setResult;
            }));
        }
Example #3
0
        private bool Set(CacheItem <TCacheValue> item, StackRedis.When when, bool sync = false)
        {
            if (!this.isLuaAllowed)
            {
                return(this.SetNoScript(item, when, sync));
            }

            var fullKey = GetKey(item.Key, item.Region);
            var value   = this.ToRedisValue(item.Value);

            var flags = sync ? StackRedis.CommandFlags.None : StackRedis.CommandFlags.FireAndForget;

            // ARGV [1]: value, [2]: type, [3]: expirationMode, [4]: expirationTimeout(millis), [5]: created(ticks)
            var parameters = new StackRedis.RedisValue[]
            {
                value,
                item.ValueType.AssemblyQualifiedName,
                (int)item.ExpirationMode,
                item.ExpirationTimeout.TotalMilliseconds,
                item.CreatedUtc.Ticks
            };

            StackRedis.RedisResult result;
            if (when == StackRedis.When.NotExists)
            {
                result = this.Eval(ScriptType.Add, fullKey, parameters, flags);
            }
            else
            {
                result = this.Eval(ScriptType.Put, fullKey, parameters, flags);
            }

            if (result == null)
            {
                if (flags.HasFlag(StackRedis.CommandFlags.FireAndForget))
                {
                    // put runs via fire and forget, so we don't get a result back
                    return(true);
                }

                // should never happen, something went wrong with the script
                throw new InvalidOperationException("Something went wrong adding an item, result must not be null.");
            }
            else
            {
                if (result.IsNull && when == StackRedis.When.NotExists)
                {
                    // add failed because element exists already
                    return(false);
                }

                var resultValue = (StackRedis.RedisValue)result;

                if (resultValue.HasValue && resultValue.ToString().Equals("OK", StringComparison.OrdinalIgnoreCase))
                {
                    // Added successfully:
                    if (!string.IsNullOrWhiteSpace(item.Region))
                    {
                        // now update region lookup if region is set
                        // we cannot do that within the lua because the region could be on another cluster node!
                        this.connection.Database.HashSet(item.Region, fullKey, "regionKey", when, StackRedis.CommandFlags.FireAndForget);
                    }

                    return(true);
                }

                return(false);
            }
        }