|
@ -1,31 +1,112 @@ |
|
|
-module(eALock). |
|
|
|
|
|
|
|
|
-module(eGLock). |
|
|
|
|
|
|
|
|
-include("eGLock.hrl"). |
|
|
-include("eGLock.hrl"). |
|
|
-define(CASE(Cond, Then, That), case Cond of true -> Then; _ -> That end). |
|
|
-define(CASE(Cond, Then, That), case Cond of true -> Then; _ -> That end). |
|
|
|
|
|
|
|
|
-export([ |
|
|
-export([ |
|
|
lockApply/2 |
|
|
|
|
|
|
|
|
tryLock/1 |
|
|
|
|
|
, tryLock/2 |
|
|
|
|
|
, releaseLock/1 |
|
|
|
|
|
, lockApply/2 |
|
|
, lockApply/3 |
|
|
, 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(). |
|
|
-spec lockApply(KeyOrKeys :: term() | [term()], MFAOrFun :: {M :: atom(), F :: atom(), Args :: list()} | {Fun :: function(), Args :: list()}) -> term(). |
|
|
lockApply(KeyOrKeys, MFAOrFun) -> |
|
|
lockApply(KeyOrKeys, MFAOrFun) -> |
|
|
lockApply(KeyOrKeys, MFAOrFun, ?LockTimeOut). |
|
|
lockApply(KeyOrKeys, MFAOrFun, ?LockTimeOut). |
|
|
|
|
|
|
|
|
-spec lockApply(KeyOrKeys :: term() | [term()], 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) -> |
|
|
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 |
|
|
case is_list(KeyOrKeys) of |
|
|
true -> |
|
|
true -> |
|
|
KeyIxs = getKexIxs(KeyOrKeys, []), |
|
|
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. |
|
|
end. |
|
|
|
|
|
|
|
|
lockApply(KeyIx, Key, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> |
|
|
|
|
|
|
|
|
lockApply(KeyIx, Key, ALockRef, PidInt, MFAOrFun, TimeOut) -> |
|
|
case tryLockOne(KeyIx, ALockRef, PidInt) of |
|
|
case tryLockOne(KeyIx, ALockRef, PidInt) of |
|
|
ok -> |
|
|
ok -> |
|
|
try doApply(MFAOrFun) |
|
|
try doApply(MFAOrFun) |
|
@ -36,10 +117,10 @@ lockApply(KeyIx, Key, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> |
|
|
ok |
|
|
ok |
|
|
end; |
|
|
end; |
|
|
_ -> |
|
|
_ -> |
|
|
loopTry(KeyIx, Key, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) |
|
|
|
|
|
|
|
|
loopApply(KeyIx, Key, ALockRef, PidInt, MFAOrFun, TimeOut) |
|
|
end. |
|
|
end. |
|
|
|
|
|
|
|
|
loopTry(KeyIx, Key, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> |
|
|
|
|
|
|
|
|
loopApply(KeyIx, Key, ALockRef, PidInt, MFAOrFun, TimeOut) -> |
|
|
receive |
|
|
receive |
|
|
after ?ReTryTime -> |
|
|
after ?ReTryTime -> |
|
|
LTimeOut = ?CASE(TimeOut == infinity, TimeOut, TimeOut - ?ReTryTime), |
|
|
LTimeOut = ?CASE(TimeOut == infinity, TimeOut, TimeOut - ?ReTryTime), |
|
@ -55,15 +136,14 @@ loopTry(KeyIx, Key, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> |
|
|
ok |
|
|
ok |
|
|
end; |
|
|
end; |
|
|
_ -> |
|
|
_ -> |
|
|
loopTry(KeyIx, Key, ALockRef, CurPid, PidInt, MFAOrFun, LTimeOut) |
|
|
|
|
|
|
|
|
loopApply(KeyIx, Key, ALockRef, PidInt, MFAOrFun, LTimeOut) |
|
|
end; |
|
|
end; |
|
|
_ -> |
|
|
_ -> |
|
|
{error, {lock_timeout, Key}} |
|
|
{error, {lock_timeout, Key}} |
|
|
end |
|
|
end |
|
|
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 |
|
|
case tryLockAll(KeyIxs, ALockRef, PidInt, []) of |
|
|
ok -> |
|
|
ok -> |
|
|
try doApply(MFAOrFun) |
|
|
try doApply(MFAOrFun) |
|
@ -74,10 +154,10 @@ lockApplys(KeyIxs, Keys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> |
|
|
ok |
|
|
ok |
|
|
end; |
|
|
end; |
|
|
_ -> |
|
|
_ -> |
|
|
loopTrys(KeyIxs, Keys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) |
|
|
|
|
|
|
|
|
loopApplys(KeyIxs, Keys, ALockRef, PidInt, MFAOrFun, TimeOut) |
|
|
end. |
|
|
end. |
|
|
|
|
|
|
|
|
loopTrys(KeyIxs, Keys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> |
|
|
|
|
|
|
|
|
loopApplys(KeyIxs, Keys, ALockRef, PidInt, MFAOrFun, TimeOut) -> |
|
|
receive |
|
|
receive |
|
|
after ?ReTryTime -> |
|
|
after ?ReTryTime -> |
|
|
LTimeOut = ?CASE(TimeOut == infinity, TimeOut, TimeOut - ?ReTryTime), |
|
|
LTimeOut = ?CASE(TimeOut == infinity, TimeOut, TimeOut - ?ReTryTime), |
|
@ -93,7 +173,7 @@ loopTrys(KeyIxs, Keys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> |
|
|
ok |
|
|
ok |
|
|
end; |
|
|
end; |
|
|
_ -> |
|
|
_ -> |
|
|
loopTrys(KeyIxs, Keys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) |
|
|
|
|
|
|
|
|
loopApplys(KeyIxs, Keys, ALockRef, PidInt, MFAOrFun, LTimeOut) |
|
|
end; |
|
|
end; |
|
|
_ -> |
|
|
_ -> |
|
|
{error, {lock_timeout, Keys}} |
|
|
{error, {lock_timeout, Keys}} |
|
@ -102,7 +182,7 @@ loopTrys(KeyIxs, Keys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> |
|
|
|
|
|
|
|
|
getKexIxs([], IxAcc) -> IxAcc; |
|
|
getKexIxs([], IxAcc) -> IxAcc; |
|
|
getKexIxs([Key | Keys], 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])). |
|
|
getKexIxs(Keys, ?CASE(lists:member(KeyIx, IxAcc), IxAcc, [KeyIx | IxAcc])). |
|
|
|
|
|
|
|
|
tryLockOne(KeyIx, ALockRef, PidInt) -> |
|
|
tryLockOne(KeyIx, ALockRef, PidInt) -> |