From 2596354225f71b3c23452e85b168c75e096244aa Mon Sep 17 00:00:00 2001 From: SisMaker <1713699517@qq.com> Date: Mon, 15 Apr 2024 22:13:05 +0800 Subject: [PATCH] =?UTF-8?q?ft:=20=E6=B7=BB=E5=8A=A0=E6=96=B0=E7=9A=84?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=20=E5=88=A0=E9=99=A4=E5=9F=BA=E4=BA=8Eets?= =?UTF-8?q?=E8=A1=A8=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 - include/eGLock.hrl | 10 +-- src/eELock.erl | 98 ----------------------- src/eELockMgr.erl | 44 ----------- src/{eALock.erl => eGLock.erl} | 114 +++++++++++++++++++++++---- src/{eALockMgr.erl => eGLockMgr.erl} | 6 +- src/eGLock_sup.erl | 14 +--- 7 files changed, 105 insertions(+), 183 deletions(-) delete mode 100644 src/eELock.erl delete mode 100644 src/eELockMgr.erl rename src/{eALock.erl => eGLock.erl} (51%) rename src/{eALockMgr.erl => eGLockMgr.erl} (86%) diff --git a/README.md b/README.md index a84efd9..0450c48 100644 --- a/README.md +++ b/README.md @@ -12,5 +12,3 @@ Build ---- eALock 基于atmoics - eELock 基于Ets表 - eALock 更优 \ No newline at end of file diff --git a/include/eGLock.hrl b/include/eGLock.hrl index 233addd..a6ac64b 100644 --- a/include/eGLock.hrl +++ b/include/eGLock.hrl @@ -1,15 +1,9 @@ -%% 锁key --define(EtsGLockKey, '$EtsGLockKey'). - %% 默认超时时间单位:Ms -define(LockTimeOut, 5000). - %% 超时重试时间单位:Ms -define(ReTryTime, 10). --define(eELockMgr, eELockMgr). - %% 数组数量 --define(eALockSize, 1048576). +-define(eGLockSize, 1048576). %% atomics索引 --define(eALockRef, eALockRef). +-define(eGLockRef, eGLockRef). diff --git a/src/eELock.erl b/src/eELock.erl deleted file mode 100644 index e93d081..0000000 --- a/src/eELock.erl +++ /dev/null @@ -1,98 +0,0 @@ --module(eELock). - --include("eGLock.hrl"). --define(CASE(Cond, Then, That), case Cond of true -> Then; _ -> That end). - --export([ - lockApply/2 - , lockApply/3 -]). - --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 :: term() | [term()], MFAOrFun :: {M :: atom(), F :: atom(), Args :: list()} | {Fun :: function(), Args :: list()}, TimeOut :: integer() | infinity) -> term(). -lockApply(KeyOrKeys, MFAOrFun, TimeOut) -> - GLockMgrPid = persistent_term:get(?eELockMgr), - link(GLockMgrPid), - Pid = self(), - case is_list(KeyOrKeys) of - true -> - KeyPids = [{OneKey, Pid} || OneKey <- KeyOrKeys], - [FirstKey | _] = KeyOrKeys, - lockApplys(KeyPids, KeyOrKeys, FirstKey, GLockMgrPid, MFAOrFun, TimeOut); - _ -> - lockApply({KeyOrKeys, Pid}, KeyOrKeys, GLockMgrPid, MFAOrFun, TimeOut) - end. - -lockApply(KeyPid, Key, GLockMgrPid, MFAOrFun, TimeOut) -> - 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, Key), - unlink(GLockMgrPid), - ok - end; - _ -> - loopTry(KeyPid, Key, GLockMgrPid, MFAOrFun, TimeOut) - end. - -loopTry(KeyPid, Key, GLockMgrPid, MFAOrFun, TimeOut) -> - receive - after ?ReTryTime -> - LTimeOut = ?CASE(TimeOut == infinity, TimeOut, TimeOut - ?ReTryTime), - case LTimeOut >= 0 of - true -> - case ets:lookup(?EtsGLockKey, Key) of - [] -> - lockApply(KeyPid, Key, GLockMgrPid, MFAOrFun, LTimeOut); - _ -> - loopTry(KeyPid, Key, GLockMgrPid, MFAOrFun, LTimeOut) - end; - _ -> - unlink(GLockMgrPid), - {error, {lock_timeout, Key}} - end - end. - -lockApplys(KeyPids, Keys, FirstKey, GLockMgrPid, MFAOrFun, TimeOut) -> - 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, OneKey) || OneKey <- Keys], - unlink(GLockMgrPid), - ok - end; - _ -> - loopTrys(KeyPids, Keys, FirstKey, GLockMgrPid, MFAOrFun, TimeOut) - end. - -loopTrys(KeyPids, Keys, FirstKey, GLockMgrPid, MFAOrFun, TimeOut) -> - receive - after ?ReTryTime -> - LTimeOut = ?CASE(TimeOut == infinity, TimeOut, TimeOut - ?ReTryTime), - case LTimeOut >= 0 of - true -> - case ets:lookup(?EtsGLockKey, FirstKey) of - [] -> - lockApplys(KeyPids, Keys, FirstKey, GLockMgrPid, MFAOrFun, LTimeOut); - _ -> - loopTrys(KeyPids, Keys, FirstKey, GLockMgrPid, MFAOrFun, LTimeOut) - end; - _ -> - unlink(GLockMgrPid), - {error, {lock_timeout, Keys}} - end - end. - -doApply({M, F, A}) -> - apply(M, F, A); -doApply({Fun, Args}) -> - apply(Fun, Args). diff --git a/src/eELockMgr.erl b/src/eELockMgr.erl deleted file mode 100644 index 0b86244..0000000 --- a/src/eELockMgr.erl +++ /dev/null @@ -1,44 +0,0 @@ --module(eELockMgr). - --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, ?SERVER}, ?MODULE, [], []). - -init([]) -> - process_flag(trap_exit, true), - persistent_term:put(?eELockMgr, self()), - ets:new(?EtsGLockKey, [named_table, set, public, {write_concurrency, auto}, {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}. diff --git a/src/eALock.erl b/src/eGLock.erl similarity index 51% rename from src/eALock.erl rename to src/eGLock.erl index 1e19a29..8c98f8f 100644 --- a/src/eALock.erl +++ b/src/eGLock.erl @@ -1,31 +1,112 @@ --module(eALock). +-module(eGLock). -include("eGLock.hrl"). -define(CASE(Cond, Then, That), case Cond of true -> Then; _ -> That end). -export([ - lockApply/2 + tryLock/1 + , tryLock/2 + , releaseLock/1 + , lockApply/2 , lockApply/3 ]). +-spec tryLock(KeyOrKeys :: term() | [term()]) -> ok | timeout. +tryLock(KeyOrKeys) -> + tryLock(KeyOrKeys, ?LockTimeOut). + +tryLock(KeyOrKeys, TimeOut) -> + ALockRef = persistent_term:get(?eGLockRef), + PidInt = eGPidInt:pidToInt(self()), + case is_list(KeyOrKeys) of + true -> + KeyIxs = getKexIxs(KeyOrKeys, []), + tryLocks(KeyIxs, ALockRef, PidInt, TimeOut); + _ -> + tryLock(erlang:phash2(KeyOrKeys, ?eGLockSize) + 1, ALockRef, PidInt, TimeOut) + end. + +tryLock(KeyIx, ALockRef, PidInt, TimeOut) -> + case tryLockOne(KeyIx, ALockRef, PidInt) of + ok -> + ok; + _ -> + loopLock(KeyIx, ALockRef, PidInt, TimeOut) + end. + +loopLock(KeyIx, ALockRef, PidInt, TimeOut) -> + receive + after ?ReTryTime -> + LTimeOut = ?CASE(TimeOut == infinity, TimeOut, TimeOut - ?ReTryTime), + case LTimeOut >= 0 of + true -> + case tryLockOne(KeyIx, ALockRef, PidInt) of + ok -> + ok; + _ -> + loopLock(KeyIx, ALockRef, PidInt, LTimeOut) + end; + _ -> + timeout + end + end. + +tryLocks(KeyIxs, ALockRef, PidInt, TimeOut) -> + case tryLockAll(KeyIxs, ALockRef, PidInt, []) of + ok -> + ok; + _ -> + loopLocks(KeyIxs, ALockRef, PidInt, TimeOut) + end. + +loopLocks(KeyIxs, ALockRef, PidInt, TimeOut) -> + receive + after ?ReTryTime -> + LTimeOut = ?CASE(TimeOut == infinity, TimeOut, TimeOut - ?ReTryTime), + case LTimeOut >= 0 of + true -> + case tryLockAll(KeyIxs, ALockRef, PidInt, []) of + ok -> + ok; + _ -> + loopLocks(KeyIxs, ALockRef, PidInt, LTimeOut) + end; + _ -> + timeout + end + end. + +-spec releaseLock(KeyOrKeys :: term() | [term()]) -> ok. +releaseLock(KeyOrKeys) -> + ALockRef = persistent_term:get(?eGLockRef), + PidInt = eGPidInt:pidToInt(self()), + case is_list(KeyOrKeys) of + true -> + KeyIxs = getKexIxs(KeyOrKeys, []), + [atomics:compare_exchange(ALockRef, OneKeyIx, PidInt, 0) || OneKeyIx <- KeyIxs], + ok; + _ -> + atomics:compare_exchange(ALockRef, rlang:phash2(KeyOrKeys, ?eGLockSize) + 1, PidInt, 0), + ok + end. + -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 :: term() | [term()], MFAOrFun :: {M :: atom(), F :: atom(), Args :: list()} | {Fun :: function(), Args :: list()}, TimeOut :: integer() | infinity) -> term(). lockApply(KeyOrKeys, MFAOrFun, TimeOut) -> - ALockRef = persistent_term:get(?eALockRef), - CurPid = self(), - PidInt = eGPidInt:pidToInt(CurPid), + ALockRef = persistent_term:get(?eGLockRef), + PidInt = eGPidInt:pidToInt(self()), case is_list(KeyOrKeys) of true -> KeyIxs = getKexIxs(KeyOrKeys, []), - lockApplys(KeyIxs, KeyOrKeys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut); + lockApplys(KeyIxs, KeyOrKeys, ALockRef, PidInt, MFAOrFun, TimeOut); _ -> - lockApply(erlang:phash2(KeyOrKeys, ?eALockSize) + 1, KeyOrKeys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) + lockApply(erlang:phash2(KeyOrKeys, ?eGLockSize) + 1, KeyOrKeys, ALockRef, PidInt, MFAOrFun, TimeOut) end. -lockApply(KeyIx, Key, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> +lockApply(KeyIx, Key, ALockRef, PidInt, MFAOrFun, TimeOut) -> case tryLockOne(KeyIx, ALockRef, PidInt) of ok -> try doApply(MFAOrFun) @@ -36,10 +117,10 @@ lockApply(KeyIx, Key, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> ok end; _ -> - loopTry(KeyIx, Key, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) + loopApply(KeyIx, Key, ALockRef, PidInt, MFAOrFun, TimeOut) end. -loopTry(KeyIx, Key, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> +loopApply(KeyIx, Key, ALockRef, PidInt, MFAOrFun, TimeOut) -> receive after ?ReTryTime -> LTimeOut = ?CASE(TimeOut == infinity, TimeOut, TimeOut - ?ReTryTime), @@ -55,15 +136,14 @@ loopTry(KeyIx, Key, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> ok end; _ -> - loopTry(KeyIx, Key, ALockRef, CurPid, PidInt, MFAOrFun, LTimeOut) + loopApply(KeyIx, Key, ALockRef, PidInt, MFAOrFun, LTimeOut) end; _ -> {error, {lock_timeout, Key}} end end. -lockApplys(KeyIxs, Keys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> - CurPid = self(), +lockApplys(KeyIxs, Keys, ALockRef, PidInt, MFAOrFun, TimeOut) -> case tryLockAll(KeyIxs, ALockRef, PidInt, []) of ok -> try doApply(MFAOrFun) @@ -74,10 +154,10 @@ lockApplys(KeyIxs, Keys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> ok end; _ -> - loopTrys(KeyIxs, Keys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) + loopApplys(KeyIxs, Keys, ALockRef, PidInt, MFAOrFun, TimeOut) end. -loopTrys(KeyIxs, Keys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> +loopApplys(KeyIxs, Keys, ALockRef, PidInt, MFAOrFun, TimeOut) -> receive after ?ReTryTime -> LTimeOut = ?CASE(TimeOut == infinity, TimeOut, TimeOut - ?ReTryTime), @@ -93,7 +173,7 @@ loopTrys(KeyIxs, Keys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> ok end; _ -> - loopTrys(KeyIxs, Keys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) + loopApplys(KeyIxs, Keys, ALockRef, PidInt, MFAOrFun, LTimeOut) end; _ -> {error, {lock_timeout, Keys}} @@ -102,7 +182,7 @@ loopTrys(KeyIxs, Keys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> getKexIxs([], IxAcc) -> IxAcc; getKexIxs([Key | Keys], IxAcc) -> - KeyIx = erlang:phash2(Key, ?eALockSize) + 1, + KeyIx = erlang:phash2(Key, ?eGLockSize) + 1, getKexIxs(Keys, ?CASE(lists:member(KeyIx, IxAcc), IxAcc, [KeyIx | IxAcc])). tryLockOne(KeyIx, ALockRef, PidInt) -> diff --git a/src/eALockMgr.erl b/src/eGLockMgr.erl similarity index 86% rename from src/eALockMgr.erl rename to src/eGLockMgr.erl index 046ebfb..77d5e99 100644 --- a/src/eALockMgr.erl +++ b/src/eGLockMgr.erl @@ -1,4 +1,4 @@ --module(eALockMgr). +-module(eGLockMgr). -behaviour(gen_server). @@ -21,8 +21,8 @@ start_link() -> init([]) -> process_flag(trap_exit, true), - ATLockRef = atomics:new(?eALockSize, [{signed, false}]), - persistent_term:put(?eALockRef, ATLockRef), + ATLockRef = atomics:new(?eGLockSize, [{signed, false}]), + persistent_term:put(?eGLockRef, ATLockRef), {ok, #state{}}. handle_call(_Request, _From, State) -> diff --git a/src/eGLock_sup.erl b/src/eGLock_sup.erl index 9f5ae63..9e4fdaf 100644 --- a/src/eGLock_sup.erl +++ b/src/eGLock_sup.erl @@ -15,20 +15,12 @@ init([]) -> SupFlags = #{strategy => one_for_all, intensity => 100, period => 3600}, ChildSpecs = [ #{ - id => ?eELockMgr, - start => {eELockMgr, start_link, []}, + id => eGLockMgr, + start => {eGLockMgr, start_link, []}, restart => permanent, shutdown => 3000, type => worker, - modules => [eELockMgr] - }, - #{ - id => eALockMgr, - start => {eALockMgr, start_link, []}, - restart => permanent, - shutdown => 3000, - type => worker, - modules => [eALockMgr] + modules => [eGLockMgr] } ], {ok, {SupFlags, ChildSpecs}}.