Exemple #1
0
        /// <summary>
        /// Add/update an entry in the cache
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">Key used to locate value in the cache</param>
        /// <param name="value"></param>
        /// <param name="ttl"></param>
        public void Set <T>(string key, T value, TimeSpan ttl)
        {
            // parameter validation

            if (string.IsNullOrWhiteSpace(key))
            {
                throw new ArgumentNullException(nameof(key));
            }
            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }
            if (ttl.TotalSeconds < 1)
            {
                throw new ArgumentNullException(nameof(ttl));
            }

            // Get the current timestamp before we do anything else.  Decrement it by one so any sync messages processed during
            // this method call will force an immediate expiration of the key's hash slot

            var timestamp = Stopwatch.GetTimestamp() - 1;

            var keyHashSlot = HashSlotCalculator.CalculateHashSlot(key);

            byte[] serializedData = null;

            // Serialize the data and write to Redis

            using (MemoryStream ms = new MemoryStream())
            {
                _serializationProvider.Serialize <T>(ms, value);
                serializedData = ms.ToArray();
            }

            // Execute the Redis SET and PUBLISH operations in one round trip using Lua
            // (Could use StackExchange.Redis batch here, instead)

            string luaScript = @"
        redis.call('SET', KEYS[1], ARGV[1], 'EX',  ARGV[2])
        redis.call('PUBLISH', ARGV[3], ARGV[4])
      ";

            var scriptArgs = new RedisValue[4];

            scriptArgs[0] = serializedData;
            scriptArgs[1] = ttl.TotalSeconds;
            scriptArgs[2] = SYNC_CHANNEL_NAME;
            scriptArgs[3] = DataSyncMessage.Create(_instanceId, keyHashSlot).Serialize();

            _redisDb.ScriptEvaluate(luaScript, new RedisKey[] { key }, scriptArgs);

            // Update the in-process cache

            _inProcessCache.Set(key, new LocalCacheEntry <T>(keyHashSlot, timestamp, value), DateTimeOffset.UtcNow.Add(ttl));
        }
Exemple #2
0
        /// <summary>
        /// Message handler for hash key invalidation messages
        /// </summary>
        /// <param name="channel">Redis pub/sub channel name</param>
        /// <param name="message">Pub/sub message</param>
        private void DataSynchronizationMessageHandler(RedisChannel channel, RedisValue message)
        {
            // Early out, if channel name doesn't match our sync channel

            if (string.Compare(channel, SYNC_CHANNEL_NAME, StringComparison.InvariantCultureIgnoreCase) != 0)
            {
                return;
            }

            // otherwise, deserialize the message

            var dataSyncMessage = DataSyncMessage.Deserialize(message);

            // and update the appropriate _lastUpdated element with the current timestamp
            // Invalidate.Exchange() would make more sense here, but the lock statement
            // makes the purpose more evident for an example

            lock (_lastUpdated)
            {
                _lastUpdated[dataSyncMessage.KeyHashSlot] = Stopwatch.GetTimestamp();
            }
        }