using AIStudio.ConSole.Redis.Core; using CSRedis; using System; using System.Collections.Generic; using System.IO; using System.Text; namespace AIStudio.ConSole.Redis.Ch04 { class TestCh04 { /******************************************************************************************************** # <start id="_1313_14472_8342"/> def list_item(conn, itemid, sellerid, price): inventory = "inventory:%s"%sellerid item = "%s.%s" % (itemid, sellerid) end = time.time() + 5 pipe = conn.pipeline() while time.time() < end: try: pipe.watch(inventory) #A if not pipe.sismember(inventory, itemid):#B pipe.unwatch() #E return None pipe.multi() #C pipe.zadd("market:", {item: price }) #C pipe.srem(inventory, itemid) #C pipe.execute() #F return True except redis.exceptions.WatchError: #D pass #D return False # <end id="_1313_14472_8342"/> *********************************************************************************************************/ #region list_item public bool list_item(CSRedisClient conn, string itemid, string sellerid, decimal price) { var inventory = $"inventory:{sellerid}"; var item = $"{itemid}.{sellerid}"; var end = DateTime.Now.AddSeconds(5); var pipe = conn.StartPipe(); while (DateTime.Now < end) { try { if (conn.SIsMember(inventory, itemid) != true) continue; pipe.ZAdd("market:", (price, item)); pipe.SRem(inventory, itemid); pipe.EndPipe(); return true; } catch (Exception) { continue; } } return false; } #endregion /******************************************************************************************************** # <start id="_1313_14472_8353"/> def purchase_item(conn, buyerid, itemid, sellerid, lprice): buyer = "users:%s"%buyerid seller = "users:%s" % sellerid item = "%s.%s"%(itemid, sellerid) inventory = "inventory:%s" % buyerid end = time.time() + 10 pipe = conn.pipeline() while time.time() < end: try: pipe.watch("market:", buyer) #A price = pipe.zscore("market:", item) #B funds = int (pipe.hget(buyer, "funds")) #B if price != lprice or price > funds: #B pipe.unwatch() #B return None pipe.multi() #C pipe.hincrby(seller, "funds", int (price)) #C pipe.hincrby(buyer, "funds", int (-price)) #C pipe.sadd(inventory, itemid) #C pipe.zrem("market:", item) #C pipe.execute() #C return True except redis.exceptions.WatchError: #D pass #D return False # <end id="_1313_14472_8353"/> *********************************************************************************************************/ public bool purchase_item(CSRedisClient conn, string buyerid, string itemid, string sellerid, decimal lprice) { var buyer = $"users:{buyerid}"; var seller = $"users:{sellerid}"; var item = $"{itemid}.{sellerid}"; var inventory = $"inventory:{sellerid}"; var end = DateTime.Now.AddSeconds(10); var pipe = conn.StartPipe(); while (DateTime.Now < end) { try { var price = conn.ZScore("market:", item); var funds = conn.HGet(buyer, "funds"); if (price != lprice || price > decimal.Parse(funds)) { return false; } pipe.HIncrBy(seller, "funds", (long)price); pipe.HIncrBy(buyer, "funds", (long)-price); pipe.SAdd(inventory, itemid); pipe.ZRem("market:", item); pipe.EndPipe(); return true; } catch { continue; } } return false; } /******************************************************************************************************** # <start id="update-token"/> def update_token(conn, token, user, item=None): timestamp = time.time() #A conn.hset('login:', token, user) #B conn.zadd('recent:', {token: timestamp}) #C if item: conn.zadd('viewed:' + token, {item: timestamp}) #D conn.zremrangebyrank('viewed:' + token, 0, -26) #E conn.zincrby('viewed:', -1, item) #F # <end id="update-token"/> *********************************************************************************************************/ #region update-token public void update_token(CSRedisClient conn, string token, string user, string item = null) { var timestamp = (DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds; conn.HSet("login:", token, user); conn.ZAdd("recent:", ((decimal)timestamp, token)); if (!string.IsNullOrEmpty(item)) { conn.ZAdd("viewed:" + token, ((decimal)timestamp, token)); conn.ZRemRangeByRank("viewed:" + token, 0, -26); conn.ZIncrBy("viewed:", item, -1); } } #endregion /******************************************************************************************************** # <start id="update-token-pipeline"/> def update_token_pipeline(conn, token, user, item= None): timestamp = time.time() pipe = conn.pipeline(False) #A pipe.hset('login:', token, user) pipe.zadd('recent:', {token: timestamp }) if item: pipe.zadd('viewed:' + token, {item: timestamp }) pipe.zremrangebyrank('viewed:' + token, 0, -26) pipe.zincrby('viewed:', -1, item) pipe.execute() #B # <end id="update-token-pipeline"/> *********************************************************************************************************/ #region update-token-pipeline public void update_token_pipeline(CSRedisClient conn, string token, string user, string item = null) { var timestamp = (DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds; var pipe = conn.StartPipe(); pipe.HSet("login:", token, user); pipe.ZAdd("recent:", ((decimal)timestamp, token)); if (!string.IsNullOrEmpty(item)) { pipe.ZAdd("viewed:" + token, ((decimal)timestamp, token)); pipe.ZRemRangeByRank("viewed:" + token, 0, -26); pipe.ZIncrBy("viewed:", item, -1); } pipe.EndPipe(); } #endregion /******************************************************************************************************** # <start id="simple-pipeline-benchmark-code"/> def benchmark_update_token(conn, duration): for function in (update_token, update_token_pipeline): #A count = 0 #B start = time.time() #B end = start + duration #B while time.time() < end: count += 1 function(conn, 'token', 'user', 'item') #C delta = time.time() - start #D print(function.__name__, count, delta, count / delta) #E # <end id="simple-pipeline-benchmark-code"/> *********************************************************************************************************/ #region simple-pipeline-benchmark-code public void simple_pipeline_benchmark_code(CSRedisClient conn, int duration) { foreach (var function in new Action<CSRedisClient, string, string, string>[] { update_token, update_token_pipeline }) { int count = 0; var start = DateTime.Now; var end = start.AddSeconds(duration); while (DateTime.Now < end) { count += 1; function(conn, "token", "user", "item"); } var delta = (DateTime.Now - start).TotalSeconds; Console.WriteLine($"{function.Method.Name}, {count}, {delta}, {count / delta}"); } } #endregion /******************************************************************************************************** def test_list_item(self): import pprint conn = self.conn print("We need to set up just enough state so that a user can list an item") seller = 'userX' item = 'itemX' conn.sadd('inventory:' + seller, item) i = conn.smembers('inventory:' + seller) print("The user's inventory has:", i) self.assertTrue(i) print() print("Listing the item...") l = list_item(conn, item, seller, 10) print("Listing the item succeeded?", l) self.assertTrue(l) r = conn.zrange('market:', 0, -1, withscores = True) print("The market contains:") pprint.pprint(r) self.assertTrue(r) self.assertTrue(any(x[0] == b'itemX.userX' for x in r)) *********************************************************************************************************/ public void test_list_item(CSRedisClient conn) { Console.WriteLine("We need to set up just enough state so that a user can list an item"); var seller = "userX"; var item = "itemX"; conn.SAdd("inventory:" + seller, item); var i = conn.SMembers("inventory:" + seller); Console.WriteLine("The user's inventory has:{i}"); Console.WriteLine(); Console.WriteLine("Listing the item..."); var l = list_item(conn, item, seller, 10); Console.WriteLine($"Listing the item succeeded?{l}"); var r = conn.ZRangeWithScores("market:", 0, -1); Console.WriteLine($"The market contains:{PrintHelper.ValueTuple2String(r)}"); } /******************************************************************************************************** def test_purchase_item(self): self.test_list_item() conn = self.conn print("We need to set up just enough state so a user can buy an item") buyer = 'userY' conn.hset('users:userY', 'funds', 125) r = conn.hgetall('users:userY') print("The user has some money:", r) self.assertTrue(r) self.assertTrue(r.get(b'funds')) print() print("Let's purchase an item") p = purchase_item(conn, 'userY', 'itemX', 'userX', 10) print("Purchasing an item succeeded?", p) self.assertTrue(p) r = conn.hgetall('users:userY') print("Their money is now:", r) self.assertTrue(r) i = conn.smembers('inventory:' + buyer) print("Their inventory is now:", i) self.assertTrue(i) self.assertTrue(b'itemX' in i) self.assertEqual(conn.zscore('market:', 'itemX.userX'), None) *********************************************************************************************************/ #region public void test_purchase_item(CSRedisClient conn) { Console.WriteLine("We need to set up just enough state so a user can buy an item"); var buyer = "userY"; conn.HSet("users:userY", "funds", 125); var r = conn.HGetAll("users:userY"); Console.WriteLine($"The user has some money:{PrintHelper.Dictionary2String(r)}"); Console.WriteLine(); Console.WriteLine("Let's purchase an item"); var p = purchase_item(conn, "userY", "itemX", "userX", 10); Console.WriteLine($"Purchasing an item succeeded?{p}"); r = conn.HGetAll("users:userY"); Console.WriteLine($"Their money is now:{PrintHelper.Dictionary2String(r)}"); var i = conn.SMembers("inventory:" + buyer); Console.WriteLine("Their inventory is now:", PrintHelper.StringArray2String(i)); } #endregion public void Test() { var conn = new CSRedis.CSRedisClient("127.0.0.1:6379,defaultDatabase=0,poolsize=500,ssl=false,writeBuffer=10240"); simple_pipeline_benchmark_code(conn, 5); test_list_item(conn); test_purchase_item(conn); } } }