《Redis实战》-Josiah L.Carlson 的python的源代码翻译成C# 第二章

    class TestCh02
    {
        public int LIMIT = 10000000;
        public bool QUIT = false;

        CSRedisClient _conn;
        public TestCh02()
        {
            _conn = new CSRedis.CSRedisClient("127.0.0.1:6379,defaultDatabase=14,poolsize=500,ssl=false,writeBuffer=10240");
        }

        public string check_token(CSRedisClient conn, string token)
        {
            return conn.HGet("login:", 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, item));
                conn.ZRemRangeByRank("viewed:" + token, 0, -26);
                conn.ZIncrBy("viewed:", item, -1);
            }
        }

        public void clean_sessions(object obj)
        {
            CSRedisClient conn = obj as CSRedisClient;
            while (!QUIT)
            {
                var size = conn.ZCard("recent:");
                if (size <= LIMIT)
                {
                    Thread.Sleep(1000);
                    continue;
                }

                var end_index = Math.Min(size - LIMIT, 100);
                var tokens = conn.ZRange("recent:", 0, end_index - 1);

                List<string> session_keys = new List<string>();
                foreach (var token in tokens)
                {
                    session_keys.Add("viewed:" + token);
                }

                conn.Del(session_keys.ToArray());
                conn.HDel("login:", tokens);
                conn.ZRem("recent:", tokens);
            }
        }

        public void add_to_cart(CSRedisClient conn, string session, string item, int count)
        {
            if (count <= 0)
                conn.HDel("cart:" + session, item);
            else
                conn.HSet("cart:" + session, item, count);
        }

        public void clean_full_sessions(object obj)
        {
            CSRedisClient conn = obj as CSRedisClient;
            while (!QUIT)
            {
                var size = conn.ZCard("recent:");
                if (size <= LIMIT)
                {
                    Thread.Sleep(1000);
                    continue;
                }

                var end_index = Math.Min(size - LIMIT, 100);
                var sessions = conn.ZRange("recent:", 0, end_index - 1);

                List<string> session_keys = new List<string>();
                foreach (var sess in sessions)
                {
                    session_keys.Add("viewed:" + sess);
                    session_keys.Add("cart:" + sess);
                }

                conn.Del(session_keys.ToArray());
                conn.HDel("login:", sessions);
                conn.ZRem("recent:", sessions);
            }
        }

        public string cache_request(CSRedisClient conn, string request, Func<string, string> callback)
        {
            if (!can_cache(conn, request))
            {
                return callback(request); ;
            }

            var page_key = "cache:" + hash_request(request);
            var content = conn.Get(page_key);

            if (string.IsNullOrEmpty(content))
            {
                content = callback(request);
                conn.Set(page_key, content, 300);
            }

            return content;
        }

        public void schedule_row_cache(CSRedisClient conn, string row_id, int delay)
        {
            conn.ZAdd("delay:", (delay, row_id));
            conn.ZAdd("schedule:", ((decimal)(DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds, row_id));
        }

        public void cache_rows(object obj)
        {
            CSRedisClient conn = obj as CSRedisClient;
            while (!QUIT)
            {
                var next = conn.ZRangeWithScores("schedule:", 0, 0);
                var now = (DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds;
                if (next != null && next[0].score > (decimal)now)
                {
                    Thread.Sleep(50);
                    continue;
                }

                var row_id = next[0].member;
                var delay = conn.ZScore("delay:", row_id) ?? 0;
                if (delay <= 0)
                {
                    conn.ZRem("delay:", row_id);
                    conn.ZRem("schedule:", row_id);
                    conn.Del("inv:" + row_id);
                }

                var row = new Inventory(row_id);
                conn.ZAdd("schedule:", ((decimal)now + delay, row_id));
                conn.Set("inv:" + row_id, Newtonsoft.Json.JsonConvert.SerializeObject(row.to_dict()));
            }
        }

        public void rescale_viewed(CSRedisClient conn)
        {
            while (!QUIT)
            {
                conn.ZRemRangeByRank("viewed:", 20000, -1);
                conn.ZInterStore("viewed:", new decimal[] { (decimal)0.5 }, RedisAggregate.Max, "viewed:");
                Thread.Sleep(300000);
            }
        }

        public bool can_cache(CSRedisClient conn, string request)
        {
            var item_id = extract_item_id(request);
            if (string.IsNullOrEmpty(item_id) || is_dynamic(request))
                return false;

            var rank = conn.ZRank("viewed:", item_id);

            return rank.HasValue && rank.Value < 10000;
        }

        public string extract_item_id(string request)
        {
            NameValueCollection nameValueCollection;
            string url;
            UrlHelper.ParseUrl(request, out url, out nameValueCollection);
            return nameValueCollection.Get("item");
        }

        public bool is_dynamic(string request)
        {
            NameValueCollection nameValueCollection;
            string url;
            UrlHelper.ParseUrl(request, out url, out nameValueCollection);
            return !string.IsNullOrEmpty(nameValueCollection.Get("_"));
        }

        public string hash_request(string request)
        {
            return request.GetHashCode().ToString();
        }

        public void tearDown()
        {
            var conn = _conn;
            var to_del = conn.Keys("login:*").Union(conn.Keys("recent:*")).Union(conn.Keys("viewed:*")).Union(conn.Keys("cart:*")).Union(conn.Keys("cache:*")).Union(conn.Keys("delay:*")).Union(conn.Keys("schedule:*")).Union(conn.Keys("inv:*")).ToArray();
            conn.Del(to_del);

            QUIT = false;
            LIMIT = 10000000;
        }

        public void test_login_cookies()
        {
            var conn = _conn;
            var token = Guid.NewGuid().ToString();

            update_token(conn, token, "username", "itemX");
            Console.WriteLine("We just logged-in/updated token:" + token);
            Console.WriteLine("For user:" + "username");
            Console.WriteLine();

            Console.WriteLine("What username do we get when we look-up that token?");
            var r = check_token(conn, token);
            Console.WriteLine(r);
            Console.WriteLine();

            Console.WriteLine("Let's drop the maximum number of cookies to 0 to clean them out");
            Console.WriteLine("We will start a thread to do the cleaning, while we stop it later");

            LIMIT = 0;
            Thread thread = new Thread(new ParameterizedThreadStart(clean_sessions));//创建线程
            thread.Start(conn);                                                           //启动线程
            Thread.Sleep(1000);
            QUIT = true;
            Thread.Sleep(2000);

            var s = conn.HLen("login:");
            Console.WriteLine("The current number of sessions still available is:" + s);
        }

        public void test_shopping_cart_cookies()
        {
            var conn = _conn;
            var token = Guid.NewGuid().ToString();

            Console.WriteLine("We'll refresh our session...");
            update_token(conn, token, "username", "itemX");
            Console.WriteLine("And add an item to the shopping cart");
            add_to_cart(conn, token, "itemY", 3);
            var r = conn.HGetAll("cart:" + token);
            Console.WriteLine("Our shopping cart currently has:" + PrintHelper.Dictionary2String(r));
            Console.WriteLine();

            Console.WriteLine("Let's clean out our sessions and carts");

            LIMIT = 0;
            Thread thread = new Thread(new ParameterizedThreadStart(clean_full_sessions));//创建线程
            thread.Start(conn);                                                           //启动线程
            Thread.Sleep(1000);
            QUIT = true;
            Thread.Sleep(2000);

            r = conn.HGetAll("cart:" + token);
            Console.WriteLine("Our shopping cart now contains:" + PrintHelper.Dictionary2String(r));
        }

        public void test_cache_request()
        {
            var conn = _conn;
            var token = Guid.NewGuid().ToString();

            Func<string, string> callback = (request) => { return "content for " + request; };

            update_token(conn, token, "username", "itemX");
            var url = "http://test.com/?item=itemX";
            Console.WriteLine("We are going to cache a simple request against" + url);
            var result = cache_request(conn, url, callback);
            Console.WriteLine("We got initial content:" + result);
            Console.WriteLine();

            Console.WriteLine("To test that we've cached the request, we'll pass a bad callback");
            var result2 = cache_request(conn, url, null);
            Console.WriteLine("We ended up getting the same response!" + result2);

        }

        public void test_cache_rows()
        {
            var conn = _conn;

            Console.WriteLine("First, let's schedule caching of itemX every 5 seconds");
            schedule_row_cache(conn, "itemX", 5);
            Console.WriteLine("Our schedule looks like:");
            var s = conn.ZRangeWithScores("schedule:", 0, -1);
            Console.WriteLine(PrintHelper.ValueTuple2String(s));

            Console.WriteLine("We'll start a caching thread that will cache the data...");
            Thread thread = new Thread(new ParameterizedThreadStart(cache_rows));
            thread.Start(conn);
            Thread.Sleep(1000);
            Console.WriteLine("Our cached data looks like:");
            var r = conn.Get("inv:itemX");
            Console.WriteLine(r);
            Console.WriteLine();
            Console.WriteLine("We'll check again in 5 seconds...");
            Thread.Sleep(5000);
            Console.WriteLine("Notice that the data has changed...");
            var r2 = conn.Get("inv:itemX");
            Console.WriteLine(r2);
            Console.WriteLine();

            Console.WriteLine("Let's force un-caching");
            schedule_row_cache(conn, "itemX", -1);
            Thread.Sleep(1000);
            r = conn.Get("inv:itemX");
            Console.WriteLine("The cache was cleared?" + r);
            Console.WriteLine();

            QUIT = true;
            Thread.Sleep(2000);
        }

    }

    public class Inventory
    {
        public string id { get; set; }
        public string data { get; set; }
        public decimal cached { get; set; }
        public Inventory(string id)
        {
            this.id = id;
        }

        public Inventory get(string id)
        {
            return new Inventory(id);
        }

        public Dictionary<string, object> to_dict()
        {
            return new Dictionary<string, object>()
            {
                { "id", this.id },
                { "data", "data to cache..."},
                { "cached", (decimal)(DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds },
            };
        }



    }

    public class UrlHelper
    {
        /// <summary>
        /// 分析 url 字符串中的参数信息
        /// </summary>
        /// <param name="url">输入的 URL</param>
        /// <param name="baseUrl">输出 URL 的基础部分</param>
        /// <param name="nvc">输出分析后得到的 (参数名,参数值) 的集合</param>
        public static void ParseUrl(string url, out string baseUrl, out NameValueCollection nvc)
        {
            if (url == null)
                throw new ArgumentNullException("url");
            nvc = new NameValueCollection();
            baseUrl = "";
            if (url == "")
                return;
            int questionMarkIndex = url.IndexOf('?');
            if (questionMarkIndex == -1)
            {
                baseUrl = url;
                return;
            }
            baseUrl = url.Substring(0, questionMarkIndex);
            if (questionMarkIndex == url.Length - 1)
                return;
            string ps = url.Substring(questionMarkIndex + 1);
            // 开始分析参数对  
            Regex re = new Regex(@"(^|&)?(\w+)=([^&]+)(&|$)?", RegexOptions.Compiled);
            MatchCollection mc = re.Matches(ps);
            foreach (Match m in mc)
            {
                nvc.Add(m.Result("$2").ToLower(), m.Result("$3"));
            }
        }

    }
View Code

源码码下载地址 AIStudio.ConSole.Redis (gitee.com)

posted @ 2020-11-30 22:16  竹天笑  阅读(89)  评论(0编辑  收藏  举报