arangodb erlang数据库驱动
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

206 строки
9.6 KiB

3 лет назад
4 лет назад
4 лет назад
4 лет назад
3 лет назад
4 лет назад
3 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
3 лет назад
3 лет назад
3 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
3 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
3 лет назад
4 лет назад
3 лет назад
4 лет назад
4 лет назад
3 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
3 лет назад
4 лет назад
3 лет назад
4 лет назад
3 лет назад
4 лет назад
3 лет назад
4 лет назад
4 лет назад
3 лет назад
4 лет назад
4 лет назад
  1. -module(agTcpAgency).
  2. -include("agVstCli.hrl").
  3. -include("eArango.hrl").
  4. -compile(inline).
  5. -compile({inline_size, 128}).
  6. -export([
  7. start_link/3
  8. , init_it/3
  9. , loop/3
  10. , system_code_change/4
  11. , system_continue/3
  12. , system_get_state/1
  13. , system_terminate/4
  14. ]).
  15. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% genActor start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  16. -spec start_link(module(), term(), [proc_lib:spawn_option()]) -> {ok, pid()}.
  17. start_link(ServerName, Args, SpawnOpts) ->
  18. proc_lib:start_link(?MODULE, init_it, [ServerName, self(), Args], infinity, SpawnOpts).
  19. init_it(ServerName, Parent, Args) ->
  20. case safeRegister(ServerName) of
  21. true ->
  22. process_flag(trap_exit, true),
  23. moduleInit(Parent, Args);
  24. {false, Pid} ->
  25. proc_lib:init_ack(Parent, {error, {alreadyStarted, Pid}})
  26. end.
  27. -spec system_code_change(term(), module(), undefined | term(), term()) -> {ok, term()}.
  28. system_code_change(MiscState, _Module, _OldVsn, _Extra) ->
  29. {ok, MiscState}.
  30. -spec system_continue(pid(), [], {module(), term(), term()}) -> ok.
  31. system_continue(_Parent, _Debug, {Parent, SrvState, CliState}) ->
  32. ?MODULE:loop(Parent, SrvState, CliState).
  33. -spec system_get_state(term()) -> {ok, term()}.
  34. system_get_state({_Parent, SrvState, _CliState}) ->
  35. {ok, SrvState}.
  36. -spec system_terminate(term(), pid(), [], term()) -> none().
  37. system_terminate(Reason, _ParentS, _Debug, {_Parent, SrvState, CliState}) ->
  38. terminate(Reason, SrvState, CliState).
  39. safeRegister(ServerName) ->
  40. try register(ServerName, self()) of
  41. true -> true
  42. catch
  43. _:_ -> {false, whereis(ServerName)}
  44. end.
  45. moduleInit(Parent, Args) ->
  46. case init(Args) of
  47. {ok, SrvState, CliState} ->
  48. proc_lib:init_ack(Parent, {ok, self()}),
  49. ?MODULE:loop(Parent, SrvState, CliState);
  50. {stop, Reason} ->
  51. proc_lib:init_ack(Parent, {error, Reason}),
  52. exit(Reason)
  53. end.
  54. loop(Parent, SrvState, CliState) ->
  55. receive
  56. {system, From, Request} ->
  57. sys:handle_system_msg(Request, From, Parent, ?MODULE, [], {Parent, SrvState, CliState});
  58. {'EXIT', Parent, Reason} ->
  59. terminate(Reason, SrvState, CliState);
  60. Msg ->
  61. {ok, NewSrvState, NewCliState} = handleMsg(Msg, SrvState, CliState),
  62. ?MODULE:loop(Parent, NewSrvState, NewCliState)
  63. end.
  64. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% genActor end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  65. -spec init(term()) -> no_return().
  66. init({PoolName, AgencyName, #agencyOpts{reconnect = Reconnect, backlogSize = BacklogSize, reConnTimeMin = Min, reConnTimeMax = Max}}) ->
  67. self() ! ?AgMDoDBConn,
  68. ReConnState = agAgencyUtils:initReConnState(Reconnect, Min, Max),
  69. {ok, #srvState{poolName = PoolName, serverName = AgencyName, reConnState = ReConnState}, #cliState{backlogSize = BacklogSize}}.
  70. -spec handleMsg(term(), srvState(), cliState()) -> {ok, term(), term()}.
  71. handleMsg(#agReq{method = Method, path = Path, queryPars = QueryPars, headers = Headers, body = Body, messageId = MessageId, fromPid = FromPid, overTime = OverTime, isSystem = IsSystem},
  72. #srvState{serverName = ServerName, dbName = DbName, socket = Socket, vstSize = VstSize} = SrvState,
  73. #cliState{backlogNum = BacklogNum, backlogSize = BacklogSize} = CliState) ->
  74. case Socket of
  75. undefined ->
  76. agAgencyUtils:agencyReply(FromPid, undefined, MessageId, {error, noSocket}),
  77. {ok, SrvState, CliState};
  78. _ ->
  79. case BacklogNum >= BacklogSize of
  80. true ->
  81. ?AgWarn(ServerName, ":backlog full curNum:~p Total: ~p ~n", [BacklogNum, BacklogSize]),
  82. agAgencyUtils:agencyReply(FromPid, undefined, MessageId, {error, backlogFull}),
  83. {ok, SrvState, CliState};
  84. _ ->
  85. Request = agVstProto:request(IsSystem, MessageId, Method, DbName, Path, QueryPars, Headers, Body, VstSize),
  86. %file:write_file("./request", BBBB),
  87. %erlang:put(MessageId, {FromPid, undefined, 0, <<>>}),
  88. %Ret = agVstProto:response(?AgUndef, 0, 0, 0, 0, <<>>, BBBB),
  89. %?AgErr(ServerName, "the request is response ret:~p~n", [Ret]),
  90. case gen_tcp:send(Socket, Request) of
  91. ok ->
  92. TimerRef = case OverTime of
  93. infinity ->
  94. undefined;
  95. _ ->
  96. erlang:start_timer(OverTime, self(), {mWaitingOver, MessageId, FromPid}, [{abs, true}])
  97. end,
  98. erlang:put(MessageId, {FromPid, TimerRef, 0, <<>>}),
  99. {ok, SrvState, CliState#cliState{backlogNum = BacklogNum + 1}};
  100. {error, Reason} ->
  101. ?AgErr(ServerName, ":send error: ~p ~p ~p ~n", [Reason, FromPid, MessageId]),
  102. gen_tcp:close(Socket),
  103. agAgencyUtils:agencyReply(FromPid, undefined, MessageId, {error, {socketSendError, Reason}}),
  104. agAgencyUtils:dealClose(SrvState, CliState, {error, {socketSendError, Reason}})
  105. end
  106. end
  107. end;
  108. handleMsg({tcp, _Socket, DataBuffer}, SrvState,
  109. #cliState{revStatus = RevStatus, backlogNum = BacklogNum, messageId = OldMessageId, chunkIdx = OldChunkIdx, chunkSize = OldChunkSize, chunkBuffer = OldChunkBuffer} = CliState) ->
  110. case agVstProto:response(RevStatus, 0, OldMessageId, OldChunkIdx, OldChunkSize, OldChunkBuffer, DataBuffer) of
  111. {?AgUndef, DoneCnt} ->
  112. {ok, SrvState, CliState#cliState{revStatus = ?AgUndef, backlogNum = BacklogNum - DoneCnt, chunkBuffer = <<>>}};
  113. {?AgCBodyStart, DoneCnt, MessageId, ChunkIdx, ChunkSize, ChunkBuffer} ->
  114. {ok, SrvState, CliState#cliState{revStatus = ?AgCBody, backlogNum = BacklogNum - DoneCnt, messageId = MessageId, chunkIdx = ChunkIdx, chunkSize = ChunkSize, chunkBuffer = ChunkBuffer}};
  115. {?AgCBodyGoOn, DoneCnt, ChunkBuffer} ->
  116. {ok, SrvState, CliState#cliState{revStatus = ?AgCBody, backlogNum = BacklogNum - DoneCnt, chunkBuffer = ChunkBuffer}};
  117. {?AgCHeader, DoneCnt, ChunkBuffer} ->
  118. {ok, SrvState, CliState#cliState{revStatus = ?AgCHeader, backlogNum = BacklogNum - DoneCnt, chunkBuffer = ChunkBuffer}}
  119. end;
  120. handleMsg({timeout, _TimerRef, {mWaitingOver, MessageId, FromPid}}, SrvState,
  121. #cliState{backlogNum = BacklogNum} = CliState) ->
  122. MsgCache = erlang:get(MessageId),
  123. MsgPF = erlang:setelement(?AgPFIdx, MsgCache, timeOut),
  124. erlang:put(MessageId, MsgPF),
  125. agAgencyUtils:agencyReTimeout(FromPid, MessageId, {error, timeout}),
  126. {ok, SrvState, CliState#cliState{backlogNum = BacklogNum - 1}};
  127. handleMsg({tcp_closed, Socket},
  128. #srvState{socket = Socket, serverName = ServerName} = SrvState,
  129. CliState) ->
  130. ?AgInfo(ServerName, "connection closed~n", []),
  131. gen_tcp:close(Socket),
  132. agAgencyUtils:dealClose(SrvState, CliState, {error, tcp_closed});
  133. handleMsg({tcp_error, Socket, Reason},
  134. #srvState{socket = Socket, serverName = ServerName} = SrvState,
  135. CliState) ->
  136. ?AgInfo(ServerName, "connection error: ~p~n", [Reason]),
  137. gen_tcp:close(Socket),
  138. agAgencyUtils:dealClose(SrvState, CliState, {error, {tcp_error, Reason}});
  139. handleMsg(?AgMDoDBConn,
  140. #srvState{poolName = PoolName, serverName = ServerName, reConnState = ReConnState} = SrvState,
  141. CliState) ->
  142. case ?agBeamPool:getv(PoolName) of
  143. #dbOpts{port = Port, hostname = HostName, dbName = DbName, user = User, password = Password, vstSize = VstSize} ->
  144. case gen_tcp:connect(HostName, Port, ?AgDefSocketOpts, ?AgDefConnTimeout) of
  145. {ok, Socket} ->
  146. gen_tcp:send(Socket, ?AgUpgradeInfo),
  147. AuthInfo = agVstProto:authInfo(User, Password),
  148. gen_tcp:send(Socket, AuthInfo),
  149. case agVstCli:receiveTcpData(#recvState{}, Socket) of
  150. {200, _BodyMap, _HeaderMap} ->
  151. ?AgDebug(ServerName, "IMY************ connect success: old server state:~n ~p~n client state~n ~p", [SrvState, CliState]),
  152. {ok, SrvState#srvState{dbName = DbName, reConnState = agAgencyUtils:resetReConnState(ReConnState), socket = Socket, vstSize = VstSize}, CliState};
  153. _Err ->
  154. ?AgErr(ServerName, "auth error: ~p~n", [_Err]),
  155. agAgencyUtils:reConnTimer(SrvState, CliState)
  156. end;
  157. _Err ->
  158. ?AgErr(ServerName, "connect error: ~p~n", [_Err]),
  159. agAgencyUtils:reConnTimer(SrvState, CliState)
  160. end;
  161. _Ret ->
  162. ?AgErr(ServerName, "deal connect not found agBeamPool:getv(~p) ret ~p is error ~n", [PoolName, _Ret])
  163. end;
  164. handleMsg({'$gen_call', FromTag, '$SrvInfo'}, SrvState, CliState) ->
  165. {To, Tag} = FromTag,
  166. catch To ! {Tag, {erlang:get(), SrvState, CliState}},
  167. {ok, SrvState, CliState};
  168. handleMsg(Msg, #srvState{serverName = ServerName} = SrvState, CliState) ->
  169. ?AgErr(ServerName, "unknown msg: ~p~n", [Msg]),
  170. {ok, SrvState, CliState}.
  171. -spec terminate(term(), srvState(), cliState()) -> ok.
  172. terminate(Reason, #srvState{socket = Socket} = SrvState, CliState) ->
  173. {ok, NewSrvState, NewCliState} = waitAllReqOver(SrvState, CliState),
  174. gen_tcp:close(Socket),
  175. agAgencyUtils:dealClose(NewSrvState, NewCliState, {error, shutdown}),
  176. exit(Reason).
  177. -spec waitAllReqOver(srvState(), cliState()) -> {ok, srvState(), cliState()}.
  178. waitAllReqOver(SrvState, #cliState{backlogNum = BacklogNum} = CliState) ->
  179. case BacklogNum > 0 of
  180. true ->
  181. receive
  182. Msg ->
  183. {ok, NewSrvState, NewCliState} = handleMsg(Msg, SrvState, CliState),
  184. waitAllReqOver(NewSrvState, NewCliState)
  185. end;
  186. _ ->
  187. {ok, SrvState, CliState}
  188. end.