Exemplo n.º 1
0
        public static void TransactionOperator()
        {
            db.StringSet("name", "张三");
            db.StringSet("age", 90);

            string name = db.StringGet("name");
            string age  = db.StringGet("age");

            Console.WriteLine("name:" + name);
            Console.WriteLine("age:" + age);


            ITransaction trans = db.CreateTransaction();

            //锁定RedisKey=name RedisValue=张三的缓存
            trans.AddCondition(Condition.StringEqual("name", name));
            Console.WriteLine("begin trans");
            trans.StringSetAsync("name", "Tom");

            //执行任务前修改
            db.StringSet("name", "zhuyong");

            bool isExec = trans.Execute(); //提交事物,name才会修改成功 name = Tom

            Console.WriteLine("事物执行结果:" + isExec);


            Console.WriteLine("name:" + name);
            Console.WriteLine("age:" + age);

            Console.WriteLine("end trans");
        }
Exemplo n.º 2
0
        private void AddModifyEntryCommands(ITransaction transaction, StateEntry stateEntry)
        {
            var compositePrimaryKeyValues =
                string.Join(
                    PropertyValueSeparator,
                    stateEntry.EntityType.GetKey().Properties.Select(p => EncodeKeyValue(stateEntry, p)));

            var redisPrimaryKeyIndexKeyName = string.Format(CultureInfo.InvariantCulture, PrimaryKeyIndexNameFormat, stateEntry.EntityType.Name);
            var redisDataKeyName            = string.Format(CultureInfo.InvariantCulture, DataHashNameFormat, stateEntry.EntityType.Name, compositePrimaryKeyValues);

            transaction.AddCondition(Condition.KeyExists(redisPrimaryKeyIndexKeyName));

            // first delete all the hash entries which have changed to null
            var changingToNullEntries = stateEntry.EntityType.Properties
                                        .Where(p => stateEntry.IsPropertyModified(p) && stateEntry[p] == null)
                                        .Select(p => (RedisValue)p.Name).ToArray();

            transaction.HashDeleteAsync(redisDataKeyName, changingToNullEntries);

            // now update all the other entries
            var updatedEntries = stateEntry.EntityType.Properties
                                 .Where(p => stateEntry.IsPropertyModified(p) && stateEntry[p] != null)
                                 .Select(p => new HashEntry(p.Name, EncodeAsBytes(stateEntry[p]))).ToArray();

            transaction.HashSetAsync(redisDataKeyName, updatedEntries);
        }
 /// <inheritdoc />
 public Task <bool> SetHashFieldIfHashExistsAsync(string hashKey, string fieldKey, string value) => ExecuteRedisCommandAsync(() =>
 {
     IDatabase db     = GetRedisDatabase();
     ITransaction txn = db.CreateTransaction();
     txn.AddCondition(Condition.KeyExists(hashKey));
     txn.HashSetAsync(hashKey, fieldKey, value); // Do not await on this since the result isn't known until the transaction completes
     return(txn.ExecuteAsync());
 });
 /// <inheritdoc />
 public Task SortedSetAddItemByScoreIfKeyExistsAsync(string setName, string memberToAdd, double score) => ExecuteRedisCommandAsync(() =>
 {
     IDatabase db     = GetRedisDatabase();
     ITransaction txn = db.CreateTransaction();
     txn.AddCondition(Condition.KeyExists(setName));
     txn.SortedSetAddAsync(setName, memberToAdd, score); // Do not await on this since the result isn't known until the transaction completes
     return(txn.ExecuteAsync());
 });
 /// <summary>
 /// Add a precondition for this transaction.
 /// </summary>
 /// <param name="condition">Precondition</param>
 public void AddCondition(Condition condition)
 {
     if (condition == null)
     {
         throw new ArgumentNullException(nameof(condition));
     }
     _baseTransaction.AddCondition(condition);
 }
 /// <inheritdoc />
 public Task <bool> SetHashFieldFlagAsync(string hashKey, string fieldKey) => ExecuteRedisCommandAsync(() =>
 {
     IDatabase db     = GetRedisDatabase();
     ITransaction txn = db.CreateTransaction();
     txn.AddCondition(Condition.HashEqual(hashKey, fieldKey, 0));
     txn.HashIncrementAsync(hashKey, fieldKey);
     return(txn.ExecuteAsync());
 });
Exemplo n.º 7
0
        public void AddTransactionCondition(Condition condition)
        {
            ITransaction context = CallContext.GetData(KEY_WORD_REDIS_CONTEXT) as ITransaction;

            if (context == null)
            {
                throw new InvalidOperationException("Redis of transaction not find!");
            }
            context.AddCondition(condition);
        }
Exemplo n.º 8
0
        public async Task ExecCompletes_Issue943()
        {
            int hashHit = 0, hashMiss = 0, expireHit = 0, expireMiss = 0;

            using (var conn = Create())
            {
                var db = conn.GetDatabase();
                for (int i = 0; i < 40000; i++)
                {
                    RedisKey key = Me();
                    await db.KeyDeleteAsync(key);

                    HashEntry[] hashEntries = new HashEntry[]
                    {
                        new HashEntry("blah", DateTime.UtcNow.ToString("R"))
                    };
                    ITransaction    transaction  = db.CreateTransaction();
                    ConditionResult keyNotExists = transaction.AddCondition(Condition.KeyNotExists(key));
                    Task            hashSetTask  = transaction.HashSetAsync(key, hashEntries);
                    Task <bool>     expireTask   = transaction.KeyExpireAsync(key, TimeSpan.FromSeconds(30));
                    bool            committed    = await transaction.ExecuteAsync();

                    if (committed)
                    {
                        if (hashSetTask.IsCompleted)
                        {
                            hashHit++;
                        }
                        else
                        {
                            hashMiss++;
                        }
                        if (expireTask.IsCompleted)
                        {
                            expireHit++;
                        }
                        else
                        {
                            expireMiss++;
                        }
                        await hashSetTask;
                        await expireTask;
                    }
                }
            }

            Writer.WriteLine($"hash hit: {hashHit}, miss: {hashMiss}; expire hit: {expireHit}, miss: {expireMiss}");
            Assert.Equal(0, hashMiss);
            Assert.Equal(0, expireMiss);
        }
Exemplo n.º 9
0
        public async Task <BigInteger> GetNonce(string address)
        {
            HexBigInteger nodeNonce = await Web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(address);

            // The final nonce
            BigInteger finalNonce = nodeNonce.Value;

            // Get the key and add the nonce if it doesn't exist
            string nonceKey = $"{AddressPrefix}{address}";

            bool success;

            do
            {
                // Get the current nonce from redis
                string redisNonce = RedisClient.Get(nonceKey); // redisDb.StringGet(nonceKey);

                // If the nonce doesn't exist in the database
                if (redisNonce == null || nodeNonce.Value > BigInteger.Parse(redisNonce))
                {
                    // Set the nonce in redis to the next one after the node nonce
                    ITransaction redisTransaction = RedisClient.CreateTransaction();
                    redisTransaction.AddCondition(Condition.StringEqual(nonceKey, redisNonce));
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                    redisTransaction.StringSetAsync(nonceKey, (nodeNonce.Value + 1).ToString(), NonceExpiration);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                    finalNonce = nodeNonce;
                    success    = await redisTransaction.ExecuteAsync();
                }
                else
                {
                    // The final nonce is set to the one retrieved from the ethereum node
                    // If the nodeNonce is lower than the one from redis, use the redis nonce as the final
                    // and increment the nonce in redis

                    BigInteger   redisNonceBigInt = BigInteger.Parse(redisNonce);
                    ITransaction redisTransaction = RedisClient.CreateTransaction();
                    redisTransaction.AddCondition(Condition.StringEqual(nonceKey, redisNonce));
                    finalNonce = redisNonceBigInt;
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                    redisTransaction.StringIncrementAsync(nonceKey);
                    redisTransaction.KeyExpireAsync(nonceKey, NonceExpiration);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                    success = await redisTransaction.ExecuteAsync();
                }
            } while (!success); // TODO: add max number of retries

            return(finalNonce);
        }
Exemplo n.º 10
0
        public void TransTest()
        {
            //测试结果-事实没有保证一致性
            string custKey = "lockRedis";

            trans.AddCondition(Condition.HashNotExists(custKey, "UniqueID"));
            trans.HashSetAsync(custKey, "UniqueID", Guid.NewGuid().ToString());
            var task = trans.StringSetAsync("testhashset108", DateTime.Now.ToString()).ContinueWith(t =>
            {
                trans.StringSetAsync("testhashset109", DateTime.Now.ToString());

                //  var a1 = trans.HashGetAllAsync("testhashset16");
            });

            trans.Execute();
        }
Exemplo n.º 11
0
        private static void TryAddCondition(ITransaction transaction, When when, string key)
        {
            var condition = when switch
            {
                When.NotExists => Condition.KeyNotExists(key),
                When.Exists => Condition.KeyExists(key),
                _ => null
            };

            if (condition is null)
            {
                return;
            }

            transaction.AddCondition(condition);
        }
    }
Exemplo n.º 12
0
        private void AddModifyEntryCommands(ITransaction transaction, StateEntry stateEntry)
        {
            var compositePrimaryKeyValues =
                ConstructKeyValue(stateEntry, (se, prop) => stateEntry.OriginalValues[prop]);

            var redisPrimaryKeyIndexKeyName = ConstructRedisPrimaryKeyIndexKeyName(stateEntry.EntityType);
            var redisDataKeyName            = ConstructRedisDataKeyName(stateEntry.EntityType, compositePrimaryKeyValues);

            transaction.AddCondition(Condition.KeyExists(redisPrimaryKeyIndexKeyName));

            // first delete all the hash entries which have changed to null
            var changingToNullEntries = stateEntry.EntityType.Properties
                                        .Where(p => stateEntry.IsPropertyModified(p) && stateEntry[p] == null)
                                        .Select(p => (RedisValue)p.Name).ToArray();

            transaction.HashDeleteAsync(redisDataKeyName, changingToNullEntries);

            // now update all the other entries
            var updatedEntries = stateEntry.EntityType.Properties
                                 .Where(p => stateEntry.IsPropertyModified(p) && stateEntry[p] != null)
                                 .Select(p => new HashEntry(p.Name, EncodeAsBytes(stateEntry[p]))).ToArray();

            transaction.HashSetAsync(redisDataKeyName, updatedEntries);
        }
Exemplo n.º 13
0
 public static void InsertName(this ITransaction trans, string name, long accid)
 {
     trans.AddCondition(Condition.KeyNotExists(GetKeyLordName(name)));
     trans.StringSetAsync(GetKeyLordName(name), accid);
 }
Exemplo n.º 14
0
        //未封装的写法
        public static void Test()
        {
            ConnectionMultiplexer _conn    = ConnectionMultiplexer.Connect("49.233.144.115:6379,password=DingMing1997,allowadmin=true"); //初始化
            IDatabase             database = _conn.GetDatabase(1);                                                                       //指定连接库 1

            #region String

            database.StringSet("name", "苍");                               //设置StringSet(key, value)
            string str = database.StringGet("name");                       //结果:苍
            database.StringSet("name_two", str, TimeSpan.FromSeconds(10)); //设置时间,10s后过期。

            //存取对象(对象需要序列化转成字符串,再存进库中)
            //创建对象
            Demo demo = new Demo()
            {
                Name   = "苍",
                Age    = 18,
                Height = 1.83
            };
            string demojson = JsonConvert.SerializeObject(demo);//序列化
            database.StringSet("model", demojson);
            string model = database.StringGet("model");
            demo = JsonConvert.DeserializeObject <Demo>(model);//反序列化

            //StringIncrement增量、StringDecrement减量(默认值同为1)
            double increment = 0;
            double decrement = 0;
            for (int i = 0; i < 3; i++)
            {
                increment = database.StringIncrement("Increment", 2);//增量,每次+2
                Console.WriteLine("Increment Key:{0},Value:{1}", "Increment", increment);
            }
            for (int i = 0; i < 3; i++)
            {
                decrement = database.StringDecrement("Decrement");//减量,每次-1
                Console.WriteLine("Decrement Key:{0},Value:{1}", "Decrement", decrement);
            }

            #endregion

            #region List

            //Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部或者尾部
            //一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
            for (int i = 0; i < 10; i++)
            {
                database.ListRightPush("list", i);//入队,先进先出,这里是从底部插入数据
            }
            for (int i = 10; i < 20; i++)
            {
                database.ListLeftPush("list", i);         //入栈,先进后出,这里是从顶部插入数据
            }
            var length = database.ListLength("list");     //长度 20

            var rightPop = database.ListRightPop("list"); //出队,这里是从底部拿出数据
            Console.WriteLine("模拟出队 Key:{0},Value:{1}", "list", rightPop);

            var leftpop = database.ListLeftPop("list");//出栈,这里是从顶部拿出数据
            Console.WriteLine("模拟出栈 Key:{0},Value:{1}", "list", leftpop);

            var list = database.ListRange("list");
            Console.WriteLine("list Key :{0},Value:{1}", "list", list);

            #endregion List

            #region Hash

            //Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。
            //Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)。
            //Hash 的存储,给我的感觉类似于关系型数据库。以下面的例子为例,存储一个 user 对象(关系型数据库里的表名), cang、shan、yun (关系型数据库里的数据的主键、唯一值),json(字段)
            string json = JsonConvert.SerializeObject(demo);//序列化
            database.HashSet("user", "cang", json);
            database.HashSet("user", "shan", json);
            database.HashSet("user", "yun", json);

            //获取Model
            string hashcang = database.HashGet("user", "cang");
            demo = JsonConvert.DeserializeObject <Demo>(hashcang);//反序列化

            //获取List
            RedisValue[] values   = database.HashValues("user");//获取所有value
            IList <Demo> demolist = new List <Demo>();
            foreach (var item in values)
            {
                Demo hashmodel = JsonConvert.DeserializeObject <Demo>(item);
                demolist.Add(hashmodel);
            }

            #endregion Hash

            #region 发布订阅

            //Redis 发布订阅(pub/sub)是一种消息通信模式,可以用于消息的传输,Redis的发布订阅机制包括三个部分,发布者,订阅者和Channel。适宜做在线聊天、消息推送等。
            //发布者和订阅者都是Redis客户端,Channel则为Redis服务器端,发布者将消息发送到某个的频道,订阅了这个频道的订阅者就能接收到这条消息,客户端可以订阅任意数量的频道

            ISubscriber sub = _conn.GetSubscriber();

            //订阅 Channel1 频道
            sub.Subscribe("Channel1", new Action <RedisChannel, RedisValue>((channel, message) =>
            {
                Console.WriteLine("Channel1" + " 订阅收到消息:" + message);
            }));

            for (int i = 0; i < 10; i++)
            {
                sub.Publish("Channel1", "msg" + i);//向频道 Channel1 发送信息
                if (i == 2)
                {
                    sub.Unsubscribe("Channel1");//取消订阅
                }
            }

            #endregion 发布订阅

            #region 事务

            //事物开启后,会在调用 Execute 方法时把相应的命令操作封装成一个请求发送给 Redis 一起执行。
            string name = database.StringGet("name");
            string age  = database.StringGet("age");

            //这里通过CreateTransaction函数(multi)来创建一个事物,调用其Execute函数(exec)提交事物。
            //其中的 "Condition.StringEqual("name", name)" 就相当于Redis命令中的watch name。
            ITransaction tran = database.CreateTransaction();       //创建事物
            tran.AddCondition(Condition.StringEqual("name", name)); //乐观锁
            tran.StringSetAsync("name", "海");
            tran.StringSetAsync("age", 25);
            database.StringSet("name", "Cang"); //此时更改name值,提交事物的时候会失败。
            bool committed = tran.Execute();    //提交事物,true成功,false回滚。
            //因为提交事物的过程中,name 值被修改,所以造成了回滚,所有给 name 赋值海,age 赋值25都失败了。

            #endregion 事务

            #region Batch

            //batch会把所需要执行的命令打包成一条请求发到Redis,然后一起等待返回结果。减少网络开销。
            var batch = database.CreateBatch();

            //批量写
            Task t1 = batch.StringSetAsync("name", "羽");
            Task t2 = batch.StringSetAsync("age", 22);
            batch.Execute();
            Task.WaitAll(t1, t2);
            Console.WriteLine("Age:" + database.StringGet("age"));
            Console.WriteLine("Name:" + database.StringGet("name"));

            //批量写
            for (int i = 0; i < 100000; i++)
            {
                batch.StringSetAsync("age" + i, i);
            }
            batch.Execute();

            //批量读
            List <Task <RedisValue> > valueList = new List <Task <RedisValue> >();
            for (int i = 0; i < 10000; i++)
            {
                Task <RedisValue> tres = batch.StringGetAsync("age" + i);
                valueList.Add(tres);
            }
            batch.Execute();
            foreach (var redisValue in valueList)
            {
                string value = redisValue.Result;//取出对应的value值
            }

            #endregion

            #region Lock(分布式锁)

            //由于Redis是单线程模型,命令操作原子性,所以利用这个特性可以很容易的实现分布式锁。
            //lock_key表示的是redis数据库中该锁的名称,不可重复。
            //token用来标识谁拥有该锁并用来释放锁。
            //TimeSpan表示该锁的有效时间。10秒后自动释放,避免死锁。
            RedisValue token = Environment.MachineName;
            if (database.LockTake("lock_key", token, TimeSpan.FromSeconds(10)))
            {
                try
                {
                    //TODO:开始做你需要的事情
                    Thread.Sleep(5000);
                }
                finally
                {
                    database.LockRelease("lock_key", token);//释放锁
                }
            }

            #endregion
        }
Exemplo n.º 15
0
 /// <summary>
 /// 事务执行的条件
 /// </summary>
 /// <param name="trans"></param>
 /// <param name="condition"></param>
 /// <returns></returns>
 public ConditionResult TransCondition(ITransaction trans, Condition condition)
 {
     return(trans.AddCondition(condition));
 }
Exemplo n.º 16
0
        private Storage GetRedis(string key, string region)
        {
            try
            {
                DateTime  now      = DateTime.UtcNow;
                IDatabase database = Redis.GetDatabase();
                RedisKey  redisKey = MakeKey(key, region);

                ITransaction getTransaction = database.CreateTransaction();
                getTransaction.AddCondition(Condition.KeyExists(redisKey));
                Task <HashEntry[]> hashTask = getTransaction.HashGetAllAsync(redisKey);

                //if the transaction didn't execute it's because the hash doesn't exist or the :sliding-expired key has expired
                if (!getTransaction.Execute(CommandFlags.None))
                {
                    return(null);
                }

                HashEntry[] values = hashTask.Result;

                HashEntry version                = values.FirstOrDefault(v => v.Name == Hashes.Version);
                HashEntry cachedDateTicks        = values.FirstOrDefault(v => v.Name == Hashes.CachedDateTicks);
                HashEntry lastValidatedTicks     = values.FirstOrDefault(v => v.Name == Hashes.LastValidatedDateTicks);
                HashEntry serializedValue        = values.FirstOrDefault(v => v.Name == Hashes.Value);
                HashEntry lastAccessedTicks      = values.FirstOrDefault(v => v.Name == Hashes.LastAccessedDateTicks);
                HashEntry slidingExpirationTicks = values.FirstOrDefault(v => v.Name == Hashes.SlidingExpirationTicks);

                if (cachedDateTicks == null || !cachedDateTicks.Value.HasValue)
                {
                    return(null);
                }

                DateTime cacheDate         = new DateTime((long)cachedDateTicks.Value);
                DateTime?lastValidatedDate = lastValidatedTicks == null ||
                                             !lastValidatedTicks.Value.HasValue ||
                                             (long)lastValidatedTicks.Value == -1L ? default(DateTime?) : new DateTime((long)lastValidatedTicks.Value);
                DateTime?lastAccessedDate = lastAccessedTicks == null ||
                                            !lastAccessedTicks.Value.HasValue ||
                                            (long)lastValidatedTicks.Value == -1L ? default(DateTime?) : new DateTime((long)lastAccessedTicks.Value);
                TimeSpan?slidingExpiration = slidingExpirationTicks == null ||
                                             !slidingExpirationTicks.Value.HasValue ||
                                             (long)slidingExpirationTicks.Value == -1L ? default(TimeSpan?) : TimeSpan.FromTicks((long)slidingExpirationTicks.Value);

                string value = serializedValue == null ? null : (string)serializedValue.Value;

                //Note: need to take one off of version to conform to initial version = 0 standard
                long ver = version == null ? 0L : (((long?)version.Value) - 1).GetValueOrDefault();

                //mark the record as updated and re-set the sliding expiration date
                ITransaction markUpdatedTransaction = database.CreateTransaction();
                markUpdatedTransaction.HashSetAsync(redisKey, Hashes.LastAccessedDateTicks, now.Ticks);
                if (slidingExpirationTicks != null)
                {
                    markUpdatedTransaction.KeyExpireAsync(redisKey, now + slidingExpiration);
                }

                markUpdatedTransaction.Execute();

                return(new Storage
                {
                    CachedDate = cacheDate,
                    LastValidatedDate = lastValidatedDate.GetValueOrDefault(cacheDate),
                    SerializedValue = value,
                    Version = ver
                });
            }
            catch (StackExchange.Redis.RedisException x)
            {
                throw ExceptionFactory.CachingFailed(CacheOperation.Get, x);
            }
        }
Exemplo n.º 17
0
        public IVersionedData UpsertInternal(IVersionedDataKind kind, IVersionedData newItem)
        {
            IDatabase db      = _redis.GetDatabase();
            string    baseKey = ItemsKey(kind);

            while (true)
            {
                string oldJson;
                try
                {
                    oldJson = db.HashGet(baseKey, newItem.Key);
                }
                catch (RedisTimeoutException e)
                {
                    Log.ErrorFormat("Timeout in update when reading {0} from {1}: {2}", newItem.Key, baseKey, e.ToString());
                    throw;
                }
                IVersionedData oldItem    = (oldJson == null) ? null : FeatureStoreHelpers.UnmarshalJson(kind, oldJson);
                int            oldVersion = (oldJson == null) ? -1 : oldItem.Version;
                if (oldVersion >= newItem.Version)
                {
                    Log.DebugFormat("Attempted to {0} key: {1} version: {2} with a version that is" +
                                    " the same or older: {3} in \"{4}\"",
                                    newItem.Deleted ? "delete" : "update",
                                    newItem.Key, oldVersion, newItem.Version, kind.GetNamespace());
                    return(oldItem);
                }

                // This hook is used only in unit tests
                _updateHook?.Invoke();

                // Note that transactions work a bit differently in StackExchange.Redis than in other
                // Redis clients. The same Redis connection is shared across all threads, so it can't
                // set a WATCH at the moment we start the transaction. Instead, it saves up all of
                // the actions we send during the transaction, and replays them all within a MULTI
                // when the transaction. AddCondition() is this client's way of doing a WATCH, and it
                // can only refer to the whole value, not to a JSON property of the value; that's why
                // we kept track of the whole value in "oldJson".
                ITransaction txn = db.CreateTransaction();
                txn.AddCondition(oldJson == null ? Condition.HashNotExists(baseKey, newItem.Key) :
                                 Condition.HashEqual(baseKey, newItem.Key, oldJson));

                txn.HashSetAsync(baseKey, newItem.Key, JsonConvert.SerializeObject(newItem));

                try
                {
                    bool success = txn.Execute();
                    if (!success)
                    {
                        // The watch was triggered, we should retry
                        Log.Debug("Concurrent modification detected, retrying");
                        continue;
                    }
                }
                catch (RedisTimeoutException e)
                {
                    Log.ErrorFormat("Timeout on update of {0} in {1}: {2}", newItem.Key, baseKey, e.ToString());
                    throw;
                }
                return(newItem);
            }
        }