-module(rankWork). -behavior(gen_srv). -include("ranks.hrl"). -export([ start_link/1 , mUpdateScore/3 , mUpdateInfo/2 , mGetRankInfo/5 ]). -export([ init/1 , handleCall/3 , handleCast/2 , handleInfo/2 , terminate/2 , code_change/3 ]). -record(state, {}). %% ******************************************** API ******************************************************************* start_link(SrvName) -> gen_srv:start_link({local, SrvName}, ?MODULE, [], []). %% ******************************************** callback ************************************************************** init(_Args) -> {ok, #state{}}. handleCall(_Msg, _State, _FROM) -> {reply, ok}. handleCast(_Msg, _State) -> kpS. handleInfo(_Msg, _State) -> kpS. terminate(_Reason, _State) -> ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. %% ****************************************************** logic ******************************************************** mUpdateScore(Key, RankType, Score) -> {_RankLimit, RankMax} = ?ranksLimit:getV(RankType), RankPos = ?ranksCfg:getV(RankType), case ets:lookup(etsRankInfo, Key) of [RankRecord] -> OldScore = element(RankPos, RankRecord), ets:delete(RankType, OldScore), RankSize = ets:info(RankType, size), case RankSize >= RankMax of true -> FirstKey = ets:first(RankType), case Score > FirstKey of true -> ets:insert(RankType, Score), ets:delete(RankType, FirstKey); _ -> ignore end; _ -> ets:insert(RankType, Score) end, ets:update_element(etsRankInfo, Key, {RankPos, Score}); _ -> %% 插入新的数据 RankSize = ets:info(RankType, size), case RankSize >= RankMax of true -> FirstKey = ets:first(RankType), case Score > FirstKey of true -> ets:insert(RankType, Score), ets:delete(RankType, FirstKey), NewRecord = #etsRankRecord{key = Key}, RankRecord = setelement(RankPos, NewRecord, Score), ets:insert(etsRankInfo, RankRecord); _ -> ignore end; _ -> ets:insert(RankType, Score), NewRecord = #etsRankRecord{key = Key}, RankRecord = setelement(RankPos, NewRecord, Score), ets:insert(etsRankInfo, RankRecord) end end, {mayReply, ok}. mUpdateInfo(Key, RecordKvs) -> ets:update_element(etsRankInfo, Key, RecordKvs), {mayReply, ok}. mGetRankInfo(RankType, MyKey, Cnt, Page, PageInfo) -> {RankLimit, _RankMax} = ?ranksLimit:getV(RankType), %% 请求第一页的时候 附加上自己的排名 SelfRank = case Page of 0 -> case ets:lookup_element(etsRankInfo, MyKey) of [RankRecord] -> RankPos = ?ranksCfg:getV(RankType), CurScore = element(RankPos, RankRecord), MyIndex = ets:select_count(RankType, [{{'$1', '$2'}, [{'>=', '$1', CurScore}], [true]}]), max(RankLimit, MyIndex); _ -> -1 end; _ -> 0 end, MS = case PageInfo == 0 orelse PageInfo of true -> [{'$1', [], ['$1']}]; <<"">> -> [{'$1', [], ['$1']}]; _ -> try binary_to_term(PageInfo) of KeyTerm when KeyTerm == <<"">>; KeyTerm == "" -> [{'$1', [], ['$1']}]; KeyTerm -> % ets:fun2ms(fun({K, _V} = T) when K < KeyTerm -> T end) [{{'$1', '$2'}, [{'<', '$1', KeyTerm}], ['$_']}] catch _C:_R -> [{'$1', [], ['$1']}] end end, case ets:select_reverse(RankType, MS, Cnt) of '$end_of_table' -> {true, {<<"">>, []}}; {KeyIds, '$end_of_table'} -> {true, SelfRank, makeRankData(KeyIds, Cnt * Page + 1)}; {KeyIds, _NextKey} -> Length = length(KeyIds), if Length < Cnt -> {true, SelfRank, makeRankData(KeyIds, Cnt * Page + 1)}; true -> NewCurCnt = Page * Cnt + Length, case NewCurCnt >= RankLimit of true -> {true, SelfRank, makeRankData(KeyIds, Cnt * Page + 1)}; _ -> {false, SelfRank, makeRankData(KeyIds, Cnt * Page + 1)} end end end. makeRankData(KeyIds, Idx) -> makeRankData(KeyIds, Idx, <<"">>, []). makeRankData([], _Idx, LastKey, Acc) -> case LastKey of <<"">> -> {LastKey, lists:reverse(Acc)}; _ -> {erlang:term_to_binary(LastKey), lists:reverse(Acc)} end; makeRankData([{CurKey, Score} | KeyIds], Idx, LastKey, Acc) -> case ets:lookup(ets_pub_rank_info, CurKey) of [OneData] -> makeRankData(KeyIds, Idx + 1, CurKey, [#rankInfo{rank = Idx, key = CurKey, publicInfo = element(?publicInfoPos, OneData), rankTypeScore = Score} | Acc]); _ -> makeRankData(KeyIds, Idx, LastKey, Acc) end.