コード例 #1
0
        private Rank GetRank(BConcurrentKey keyHint)
        {
            var Rank = Ranks.GetOrAdd(keyHint, (key) => new Rank());

            lock (Rank)
            {
                long now = Zeze.Util.Time.NowUnixMillis;
                if (now - Rank.BuildTime < RebuildTime)
                {
                    return(Rank);
                }
                // rebuild
                List <BRankList> datas = new List <BRankList>();
                int cocurrentLevel     = GetConcurrentLevel(keyHint.RankType);
                for (int i = 0; i < cocurrentLevel; ++i)
                {
                    var concurrentKey = new BConcurrentKey(
                        keyHint.RankType, i,
                        keyHint.TimeType, keyHint.Year, keyHint.Offset);
                    var rank = _trank.GetOrAdd(concurrentKey);
                    datas.Add(rank);
                }
                int countNeed = GetRankCount(keyHint.RankType);
                switch (datas.Count)
                {
                case 0:
                    Rank.TableValue = new BRankList();
                    break;

                case 1:
                    Rank.TableValue = datas[0].Copy();
                    break;

                default:
                    // 合并过程中,结果是新的 BRankList,List中的 BRankValue 引用到表中。
                    // 最后 Copy 一次。
                    BRankList current = datas[0];
                    for (int i = 1; i < datas.Count; ++i)
                    {
                        current = Merge(current, datas[i]);
                        if (current.RankList.Count > countNeed)
                        {
                            // 合并中间结果超过需要的数量可以先删除。
                            // 第一个current直接引用table.data,不能删除。
                            current.RankList.RemoveRange(countNeed, current.RankList.Count - countNeed);
                        }
                    }
                    Rank.TableValue = current.Copy();     // current 可能还直接引用第一个,虽然逻辑上不大可能。先Copy。
                    break;
                }
                Rank.BuildTime = now;
                if (Rank.TableValue.RankList.Count > countNeed) // 再次删除多余的结果。
                {
                    Rank.TableValue.RankList.RemoveRange(countNeed, Rank.TableValue.RankList.Count - countNeed);
                }
            }
            return(Rank);
        }
コード例 #2
0
        // 使用异步方案构建rank。
        private void GetRankAsync(BConcurrentKey keyHint, System.Action <Rank> callback)
        {
            if (Ranks.TryGetValue(keyHint, out var rank))
            {
                long now = Zeze.Util.Time.NowUnixMillis;
                if (now - rank.BuildTime < RebuildTime)
                {
                    callback(rank);
                    return;
                }
            }
            // 异步方式没法锁住Rank,所以并发的情况下,可能多次去获取数据,多次构建,多次覆盖Ranks的cache。
            int countNeed       = GetRankCount(keyHint.RankType);
            int concurrentLevel = GetConcurrentLevel(keyHint.RankType);

            RunGetRank(keyHint,
                       // Action OnHashResult
                       (sessionId, hash, returnCode, BRankList) =>
            {
                App.Server.TryGetManualContext <ModuleRedirectAllContext>(sessionId)
                ?.ProcessHash(hash, () => new Rank(), (rank) =>
                {
                    if (returnCode != Procedure.Success)         // 只有处理成功的结果才是有效的。
                    {
                        return(returnCode);
                    }
                    if (rank.TableValue == null)
                    {
                        rank.TableValue = BRankList.CopyIfManaged();         // 本地实现的时候可能返回受管理的数据Bean,此时需要拷贝。
                    }
                    else
                    {
                        rank.TableValue = Merge(rank.TableValue, BRankList);
                    }
                    if (rank.TableValue.RankList.Count > countNeed)         // 合并中间结果超过需要的数量可以先删除。
                    {
                        rank.TableValue.RankList.RemoveRange(countNeed, rank.TableValue.RankList.Count - countNeed);
                    }
                    return(Procedure.Success);
                });
            },
                       // Action OnHashEnd
                       (context) =>
            {
                if (context.HashCodes.Count > 0)
                {
                    // 一般是超时发生时还有未返回结果的hash分组。
                    logger.Warn($"OnHashEnd: timeout with hashs: {context.HashCodes}");
                }

                var rank       = context.UserState as Rank;
                rank.BuildTime = Zeze.Util.Time.NowUnixMillis;
                Ranks[keyHint] = rank;     // 覆盖最新的数据到缓存里面。
                callback(rank);
            }
                       );
        }
コード例 #3
0
        public const long RebuildTime = 5 * 60 * 1000; // 5 min

        private BRankList Merge(BRankList left, BRankList right)
        {
            BRankList result     = new BRankList();
            int       indexLeft  = 0;
            int       indexRight = 0;

            while (indexLeft < left.RankList.Count && indexRight < right.RankList.Count)
            {
                if (left.RankList[indexLeft].Value >= right.RankList[indexRight].Value)
                {
                    result.RankList.Add(left.RankList[indexLeft]);
                    ++indexLeft;
                }
                else
                {
                    result.RankList.Add(right.RankList[indexRight]);
                    ++indexRight;
                }
            }
            // 下面两种情况不会同时存在,同时存在"在上面"处理。
            if (indexLeft < left.RankList.Count)
            {
                while (indexLeft < left.RankList.Count)
                {
                    result.RankList.Add(left.RankList[indexLeft]);
                    ++indexLeft;
                }
            }
            else if (indexRight < right.RankList.Count)
            {
                while (indexRight < right.RankList.Count)
                {
                    result.RankList.Add(right.RankList[indexRight]);
                    ++indexRight;
                }
            }
            return(result);
        }