• 之前数据库读写模型的实现


    之前有个数据库读写的设想,然后就实现了一下,实现花的时间比预期的要长,昨天没有弄完,今天又加班弄了一会。但还是有很多很不满意的地方,包括测试也没有做到位。明天回家看孩子,再整就得下周二了,到时候再好好调整下。

    重点看game_db_sup后面的,game_db_sup监督了4个behaviour。
    eredis_pool_sup是github上现成的第三方库,主要负责redis的读写,主要是有poolboy和erdis的东西一起完成的。
    game_db_cache是个gen_server,主要负责配置表从mysql=>redis一些具体需求的映射初始化,之所以写成gen_server主要还是为了方便热更新。
    game_db_queue是一个redis=>mysql同步用的消息队列,gen_server。主要开放的接口是 
     -export([enqueue/1,dequeue/0,get_queue_len/0]).
    意思分别是入队,出队,查询队列长度。
    game_db_writer是用gen_fsm状态机实现的,主要负责具体的写事务,这个类目前写的效率还没有具体调优。

    game_db_cache.erl

    %%%-------------------------------------------------------------------
    %%% @author 李世铭
    %%% @copyright (C) Mar,30th 2016, <COMPANY>
    %%% @doc
    %%% 进行服务器启动时的缓存处理服务
    %%% @end
    %%% Created : 30. 三月 2016 14:10
    %%%-------------------------------------------------------------------
    -module(game_db_cache).
    -author("Administrator").
    -behaviour(gen_server).
    %% API
    -export([start_link/0]).
    %% gen_server callbacks
    -export([init/1,
      handle_call/3,
      handle_cast/2,
      handle_info/2,
      terminate/2,
      code_change/3]).
    %%自定义API
    -export([reload/0, reload/1]).
    -define(SERVER, ?MODULE).
    -record(state, {}).
    %%%===================================================================
    %%% API
    %%%===================================================================
    %%重新计算全部的缓存,mysql=>redis
    reload()->
      reload(all).
    %%重新计算缓存,根据对应的atom读取计算对应的cache,mysql=>redis
    reload(TableName) when is_atom(TableName)->
      gen_server:call(?MODULE, {reload,TableName});
    reload(TableName) when is_list(TableName)->
      TableAtom = list_to_existing_atom(TableName),
      gen_server:call(?MODULE, {reload,TableName});
    reload(TableName)  when is_binary(TableName)->
      TableAtom = list_to_existing_atom(binary_to_list(TableName)),
      gen_server:call(?MODULE, {reload,TableAtom}).
    %%根据传入的原子来读取对应的cache
    load_cache()->
      load_cache(all).
    load_cache(CacheAtom) when is_atom(CacheAtom)->
      case CacheAtom of
        all->
          %%读取计算所有的缓存
          cache_model:init_sciense_cache(),
          cache_model:init_user_cache();
        science->
          cache_model:init_sciense_cache();
        user->
          cache_model:init_user_cache();
        _->
          ok
      end.
    %%--------------------------------------------------------------------
    %% @doc
    %% Starts the server
    %%
    %% @end
    %%--------------------------------------------------------------------
    -spec(start_link() ->
      {ok, Pid :: pid()} | ignore | {error, Reason :: term()}).
    start_link() ->
      gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
    %%%===================================================================
    %%% gen_server callbacks
    %%%===================================================================
    %%--------------------------------------------------------------------
    %% @private
    %% @doc
    %% Initializes the server
    %%
    %% @spec init(Args) -> {ok, State} |
    %%                     {ok, State, Timeout} |
    %%                     ignore |
    %%                     {stop, Reason}
    %% @end
    %%--------------------------------------------------------------------
    -spec(init(Args :: term()) ->
      {ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} |
      {stop, Reason :: term()} | ignore).
    init([]) ->
      load_cache(),
      {ok, #state{}}.
    %%--------------------------------------------------------------------
    %% @private
    %% @doc
    %% Handling call messages
    %%
    %% @end
    %%--------------------------------------------------------------------
    -spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()},
        State :: #state{}) ->
      {reply, Reply :: term(), NewState :: #state{}} |
      {reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} |
      {noreply, NewState :: #state{}} |
      {noreply, NewState :: #state{}, timeout() | hibernate} |
      {stop, Reason :: term(), Reply :: term(), NewState :: #state{}} |
      {stop, Reason :: term(), NewState :: #state{}}).
    handle_call({reload,TableName},_From,State)->
      load_cache(TableName),
      {reply, ok, State};
    handle_call(_Request, _From, State) ->
      {reply, ok, State}.
    %%--------------------------------------------------------------------
    %% @private
    %% @doc
    %% Handling cast messages
    %%
    %% @end
    %%--------------------------------------------------------------------
    -spec(handle_cast(Request :: term(), State :: #state{}) ->
      {noreply, NewState :: #state{}} |
      {noreply, NewState :: #state{}, timeout() | hibernate} |
      {stop, Reason :: term(), NewState :: #state{}}).
    handle_cast(_Request, State) ->
      {noreply, State}.
    %%--------------------------------------------------------------------
    %% @private
    %% @doc
    %% Handling all non call/cast messages
    %%
    %% @spec handle_info(Info, State) -> {noreply, State} |
    %%                                   {noreply, State, Timeout} |
    %%                                   {stop, Reason, State}
    %% @end
    %%--------------------------------------------------------------------
    -spec(handle_info(Info :: timeout() | term(), State :: #state{}) ->
      {noreply, NewState :: #state{}} |
      {noreply, NewState :: #state{}, timeout() | hibernate} |
      {stop, Reason :: term(), NewState :: #state{}}).
    handle_info(_Info, State) ->
      {noreply, State}.
    %%--------------------------------------------------------------------
    %% @private
    %% @doc
    %% This function is called by a gen_server when it is about to
    %% terminate. It should be the opposite of Module:init/1 and do any
    %% necessary cleaning up. When it returns, the gen_server terminates
    %% with Reason. The return value is ignored.
    %%
    %% @spec terminate(Reason, State) -> void()
    %% @end
    %%--------------------------------------------------------------------
    -spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()),
        State :: #state{}) -> term()).
    terminate(_Reason, _State) ->
      ok.
    %%--------------------------------------------------------------------
    %% @private
    %% @doc
    %% Convert process state when code is changed
    %%
    %% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
    %% @end
    %%--------------------------------------------------------------------
    -spec(code_change(OldVsn :: term() | {down, term()}, State :: #state{},
        Extra :: term()) ->
      {ok, NewState :: #state{}} | {error, Reason :: term()}).
    code_change(_OldVsn, State, _Extra) ->
      {ok, State}.
    %%%===================================================================
    %%% Internal functions
    %%%===================================================================

    game_db_queue.erl

    %%%-------------------------------------------------------------------
    %%% @author 李世铭
    %%% @copyright (C) Mar,31th 2016, <COMPANY>
    %%% @doc
    %%% 维护一个队列,redis=>mysql同步数据用的队列
    %%% 包含以下功能:
    %%% 1、入队
    %%% 2、出队
    %%% 3、获取队列余量
    %%% 使用genserver来保证队列单线程,
    %%% 使用redis的队列来保证数据不会丢失太多。
    %%% @end
    %%% Created : 31. 三月 2016 17:18
    %%%-------------------------------------------------------------------
    -module(game_db_queue).
    -author("Administrator").
    -behaviour(gen_server).
    -include("db_config.hrl").
    %% API
    -export([start_link/0]).
    %% gen_server callbacks
    -export([init/1,
      handle_call/3,
      handle_cast/2,
      handle_info/2,
      terminate/2,
      code_change/3]).
    -export([enqueue/1,dequeue/0,get_queue_len/0]).
    -define(SERVER, ?MODULE).
    -record(state, {}).
    %%%===================================================================
    %%% API
    %%%===================================================================
    %%入队操作
    enqueue(DbMsg) ->
      gen_server:call(?MODULE, {enqueue,DbMsg}).
    %%出队操作
    dequeue()->
      gen_server:call(?MODULE,{dequeue}).
    %%获取队列长度
    get_queue_len()->
      gen_server:call(?MODULE,{get_queue_len}).
    %%--------------------------------------------------------------------
    %% @doc
    %% Starts the server
    %%
    %% @end
    %%--------------------------------------------------------------------
    -spec(start_link() ->
      {ok, Pid :: pid()} | ignore | {error, Reason :: term()}).
    start_link() ->
      gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
    %%%===================================================================
    %%% gen_server callbacks
    %%%===================================================================
    %%--------------------------------------------------------------------
    %% @private
    %% @doc
    %% Initializes the server
    %%
    %% @spec init(Args) -> {ok, State} |
    %%                     {ok, State, Timeout} |
    %%                     ignore |
    %%                     {stop, Reason}
    %% @end
    %%--------------------------------------------------------------------
    -spec(init(Args :: term()) ->
      {ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} |
      {stop, Reason :: term()} | ignore).
    init([]) ->
      {ok, #state{}}.
    %%--------------------------------------------------------------------
    %% @private
    %% @doc
    %% Handling call messages
    %%
    %% @end
    %%--------------------------------------------------------------------
    -spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()},
        State :: #state{}) ->
      {reply, Reply :: term(), NewState :: #state{}} |
      {reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} |
      {noreply, NewState :: #state{}} |
      {noreply, NewState :: #state{}, timeout() | hibernate} |
      {stop, Reason :: term(), Reply :: term(), NewState :: #state{}} |
      {stop, Reason :: term(), NewState :: #state{}}).
    handle_call({enqueue,DbMsg},_From,State)->
      SzDbMsg = db_utility:pack_data(DbMsg),
      Result = redis:lpush(?MYSQL_WRITE_LIST,SzDbMsg),
      {reply,Result,State};
    handle_call({dequeue},_From,State)->
      SzDbMsg = redis:rpop(?MYSQL_WRITE_LIST),
      Result = db_utility:unpack_data(SzDbMsg),
      {reply,Result,State};
    handle_call({get_queue_len},_From,State)->
      Result = redis:llen(?MYSQL_WRITE_LIST),
      {reply,Result,State};
    handle_call(_Request, _From, State) ->
      {reply, ok, State}.
    %%--------------------------------------------------------------------
    %% @private
    %% @doc
    %% Handling cast messages
    %%
    %% @end
    %%--------------------------------------------------------------------
    -spec(handle_cast(Request :: term(), State :: #state{}) ->
      {noreply, NewState :: #state{}} |
      {noreply, NewState :: #state{}, timeout() | hibernate} |
      {stop, Reason :: term(), NewState :: #state{}}).
    handle_cast(_Request, State) ->
      {noreply, State}.
    %%--------------------------------------------------------------------
    %% @private
    %% @doc
    %% Handling all non call/cast messages
    %%
    %% @spec handle_info(Info, State) -> {noreply, State} |
    %%                                   {noreply, State, Timeout} |
    %%                                   {stop, Reason, State}
    %% @end
    %%--------------------------------------------------------------------
    -spec(handle_info(Info :: timeout() | term(), State :: #state{}) ->
      {noreply, NewState :: #state{}} |
      {noreply, NewState :: #state{}, timeout() | hibernate} |
      {stop, Reason :: term(), NewState :: #state{}}).
    handle_info(_Info, State) ->
      {noreply, State}.
    %%--------------------------------------------------------------------
    %% @private
    %% @doc
    %% This function is called by a gen_server when it is about to
    %% terminate. It should be the opposite of Module:init/1 and do any
    %% necessary cleaning up. When it returns, the gen_server terminates
    %% with Reason. The return value is ignored.
    %%
    %% @spec terminate(Reason, State) -> void()
    %% @end
    %%--------------------------------------------------------------------
    -spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()),
        State :: #state{}) -> term()).
    terminate(_Reason, _State) ->
      ok.
    %%--------------------------------------------------------------------
    %% @private
    %% @doc
    %% Convert process state when code is changed
    %%
    %% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
    %% @end
    %%--------------------------------------------------------------------
    -spec(code_change(OldVsn :: term() | {down, term()}, State :: #state{},
        Extra :: term()) ->
      {ok, NewState :: #state{}} | {error, Reason :: term()}).
    code_change(_OldVsn, State, _Extra) ->
      {ok, State}.
    %%%===================================================================
    %%% Internal functions
    %%%===================================================================

    game_db_writer的代码想了想还是先不放了,下周修改下再说。 
    最后顺手拍下我们颇有个性的墙绘。

  • 相关阅读:
    解决VMwave下卡死的办法
    深度探索C++对象模型第四章:函数语义学
    cc
    tbb库的使用
    10内核同步方法
    哈希
    django 和restful framework 初始配置轻松搞定
    linux有趣动画--代码雨
    linux有趣开机图标--佛祖保佑
    Socket是什么,通俗易懂点说
  • 原文地址:https://www.cnblogs.com/lsm19870508/p/5348052.html
Copyright © 2020-2023  润新知