Просмотр исходного кода

ft: 确保执行锁的进程被意外干掉时 锁能够被正确释放

master
SisMaker 1 год назад
Родитель
Сommit
cfa46cadba
4 измененных файлов: 89 добавлений и 28 удалений
  1. +3
    -1
      include/eGLock.hrl
  2. +31
    -24
      src/eGLock.erl
  3. +43
    -0
      src/eGLockMgr.erl
  4. +12
    -3
      src/eGLock_sup.erl

+ 3
- 1
include/eGLock.hrl Просмотреть файл

@ -4,4 +4,6 @@
-define(LockTimeOut, 5000).
%% :Ms
-define(ReTryTime, 10).
-define(ReTryTime, 10).
-define(eGLockMgr, eGLockMgr).

+ 31
- 24
src/eGLock.erl Просмотреть файл

@ -7,88 +7,95 @@
, lockApply/3
]).
-spec lockApply(KeyOrKeys :: tuple() | [tuple()], MFAOrFun :: {M :: atom(), F :: atom(), Args :: list()} | {Fun :: function(), Args :: list()}) -> term().
-spec lockApply(KeyOrKeys :: term() | [term()], MFAOrFun :: {M :: atom(), F :: atom(), Args :: list()} | {Fun :: function(), Args :: list()}) -> term().
lockApply(KeyOrKeys, MFAOrFun) ->
lockApply(KeyOrKeys, MFAOrFun, ?LockTimeOut).
-spec lockApply(KeyOrKeys :: tuple() | [tuple()], MFAOrFun :: {M :: atom(), F :: atom(), Args :: list()} | {Fun :: function(), Args :: list()}, TimeOut :: integer() | infinity) -> term().
-spec lockApply(KeyOrKeys :: term() | [term()], MFAOrFun :: {M :: atom(), F :: atom(), Args :: list()} | {Fun :: function(), Args :: list()}, TimeOut :: integer() | infinity) -> term().
lockApply(KeyOrKeys, MFAOrFun, TimeOut) ->
case KeyOrKeys of
{_, _} ->
lockApply(KeyOrKeys, MFAOrFun, TimeOut, erlang:system_time(millisecond));
link(whereis(?eGLockMgr)),
Pid = self(),
case is_list(KeyOrKeys) of
true ->
KeyPids = [{OneKey, Pid} || OneKey <- KeyOrKeys],
lockApplys(KeyPids, KeyOrKeys, MFAOrFun, TimeOut, erlang:system_time(millisecond));
_ ->
lockApplys(KeyOrKeys, MFAOrFun, TimeOut, erlang:system_time(millisecond))
lockApply({KeyOrKeys, Pid}, KeyOrKeys, MFAOrFun, TimeOut, erlang:system_time(millisecond))
end.
-define(CASE(Cond, Then, That), case Cond of true -> Then; _ -> That end).
lockApply(Key, MFAOrFun, TimeOut, FirstTime) ->
case ets:insert_new(?EtsGLockKey, Key) of
lockApply(KeyPid, Key, MFAOrFun, TimeOut, FirstTime) ->
case ets:insert_new(?EtsGLockKey, KeyPid) of
true ->
try doApply(MFAOrFun)
catch C:R:S ->
{error, {lock_apply_error, {C, R, S}}}
after
ets:delete(?EtsGLockKey, element(1, Key)),
ets:delete(?EtsGLockKey, Key),
unlink(whereis(?eGLockMgr)),
ok
end;
_ ->
loopTry(Key, MFAOrFun, TimeOut, FirstTime)
loopTry(KeyPid, Key, MFAOrFun, TimeOut, FirstTime)
end.
loopTry(Key, MFAOrFun, TimeOut, FirstTime) ->
loopTry(KeyPid, Key, MFAOrFun, TimeOut, FirstTime) ->
receive
after ?ReTryTime ->
case ets:lookup(?EtsGLockKey, element(1, Key)) of
case ets:lookup(?EtsGLockKey, Key) of
[] ->
lockApply(Key, MFAOrFun, TimeOut, FirstTime);
lockApply(KeyPid, Key, MFAOrFun, TimeOut, FirstTime);
_ ->
case TimeOut of
infinity ->
loopTry(Key, MFAOrFun, TimeOut, FirstTime);
loopTry(KeyPid, Key, MFAOrFun, TimeOut, FirstTime);
_ ->
LTimeOut = TimeOut - abs(erlang:system_time(millisecond) - FirstTime),
case LTimeOut =< 0 of
true ->
unlink(whereis(?eGLockMgr)),
{error, {lock_timeout, Key}};
_ ->
loopTry(Key, MFAOrFun, TimeOut, FirstTime)
loopTry(KeyPid, Key, MFAOrFun, TimeOut, FirstTime)
end
end
end
end.
lockApplys(Keys, MFAOrFun, TimeOut, FirstTime) ->
case ets:insert_new(?EtsGLockKey, Keys) of
lockApplys(KeyPids, Keys, MFAOrFun, TimeOut, FirstTime) ->
case ets:insert_new(?EtsGLockKey, KeyPids) of
true ->
try doApply(MFAOrFun)
catch C:R:S ->
{error, {lock_apply_error, {C, R, S}}}
after
[ets:delete(?EtsGLockKey, element(1, OneKey)) || OneKey <- Keys],
[ets:delete(?EtsGLockKey, OneKey) || OneKey <- Keys],
unlink(whereis(?eGLockMgr)),
ok
end;
_ ->
loopTrys(Keys, MFAOrFun, TimeOut, FirstTime)
loopTrys(KeyPids, Keys, MFAOrFun, TimeOut, FirstTime)
end.
loopTrys(Keys, MFAOrFun, TimeOut, FirstTime) ->
loopTrys(KeyPids, Keys, MFAOrFun, TimeOut, FirstTime) ->
receive
after ?ReTryTime ->
[Key | _] = Keys,
case ets:lookup(?EtsGLockKey, element(1, Key)) of
case ets:lookup(?EtsGLockKey, Key) of
[] ->
lockApplys(Keys, MFAOrFun, TimeOut, FirstTime);
lockApplys(KeyPids, Keys, MFAOrFun, TimeOut, FirstTime);
_ ->
case TimeOut of
infinity ->
loopTrys(Keys, MFAOrFun, TimeOut, FirstTime);
loopTrys(KeyPids, Keys, MFAOrFun, TimeOut, FirstTime);
_ ->
LTimeOut = TimeOut - abs(erlang:system_time(millisecond) - FirstTime),
case LTimeOut =< 0 of
true ->
unlink(whereis(?eGLockMgr)),
{error, {lock_timeout, Keys}};
_ ->
loopTrys(Keys, MFAOrFun, TimeOut, FirstTime)
loopTrys(KeyPids, Keys, MFAOrFun, TimeOut, FirstTime)
end
end
end

+ 43
- 0
src/eGLockMgr.erl Просмотреть файл

@ -0,0 +1,43 @@
-module(eGLockMgr).
-behaviour(gen_server).
-include("eGLock.hrl").
-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
code_change/3]).
-define(SERVER, ?MODULE).
-record(state, {}).
%%%===================================================================
%%% Spawning and gen_server implementation
%%%===================================================================
start_link() ->
gen_server:start_link({local, eGLockMgr}, ?MODULE, [], []).
init([]) ->
process_flag(trap_exit, true),
ets:new(?EtsGLockKey, [named_table, set, public, {write_concurrency, true}, {read_concurrency, true}]),
{ok, #state{}}.
handle_call(_Request, _From, State) ->
{reply, ok, State}.
handle_cast(_Request, State) ->
{noreply, State}.
handle_info({'EXIT', Pid, _Reason}, State) ->
ets:match_delete(?EtsGLockKey, {'_', Pid}),
{noreply, State};
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.

+ 12
- 3
src/eGLock_sup.erl Просмотреть файл

@ -12,6 +12,15 @@ start_link() ->
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
init([]) ->
SupFlags = #{strategy => one_for_all, intensity => 0, period => 1},
ets:new(?EtsGLockKey, [named_table, set, public, {write_concurrency, auto}, {read_concurrency, true}]),
{ok, {SupFlags, []}}.
SupFlags = #{strategy => one_for_all, intensity => 100, period => 3600},
ChildSpecs = [
#{
id => ?eGLockMgr,
start => {eGLockMgr, start_link, []},
restart => permanent,
shutdown => 3000,
type => worker,
modules => [eGLockMgr]
}
],
{ok, {SupFlags, ChildSpecs}}.

Загрузка…
Отмена
Сохранить