|
|
@ -14,67 +14,56 @@ lockApply(KeyOrKeys, MFAOrFun) -> |
|
|
|
|
|
|
|
-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(?eALockMgr), |
|
|
|
ALockRef = persistent_term:get(?eALockRef), |
|
|
|
CurPid = self(), |
|
|
|
PidInt = eGPidInt:termInt(CurPid), |
|
|
|
PidInt = eGPidInt:pidToInt(CurPid), |
|
|
|
case is_list(KeyOrKeys) of |
|
|
|
true -> |
|
|
|
KeyIxs = getKexIxs(KeyOrKeys, []), |
|
|
|
lockApplys(KeyIxs, KeyOrKeys, ALockRef, CurPid, PidInt, GLockMgrPid, MFAOrFun, TimeOut); |
|
|
|
lockApplys(KeyIxs, KeyOrKeys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut); |
|
|
|
_ -> |
|
|
|
lockApply(erlang:phash2(KeyOrKeys, ?eALockSize) + 1, KeyOrKeys, ALockRef, CurPid, PidInt, GLockMgrPid, MFAOrFun, TimeOut) |
|
|
|
lockApply(erlang:phash2(KeyOrKeys, ?eALockSize) + 1, KeyOrKeys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) |
|
|
|
end. |
|
|
|
|
|
|
|
lockApply(KeyIx, Key, ALockRef, CurPid, PidInt, GLockMgrPid, MFAOrFun, TimeOut) -> |
|
|
|
link(GLockMgrPid), |
|
|
|
ets:insert(?EtsGLockPid, {CurPid, KeyIx}), |
|
|
|
case atomics:compare_exchange(ALockRef, KeyIx, 0, PidInt) of |
|
|
|
lockApply(KeyIx, Key, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> |
|
|
|
case tryLockOne(KeyIx, ALockRef, PidInt) of |
|
|
|
ok -> |
|
|
|
try doApply(MFAOrFun) |
|
|
|
catch C:R:S -> |
|
|
|
{error, {lock_apply_error, {C, R, S}}} |
|
|
|
after |
|
|
|
atomics:exchange(ALockRef, KeyIx, 0), |
|
|
|
ets:delete(?EtsGLockPid, CurPid), |
|
|
|
unlink(GLockMgrPid), |
|
|
|
ok |
|
|
|
end; |
|
|
|
_ -> |
|
|
|
loopTry(KeyIx, Key, ALockRef, CurPid, PidInt, GLockMgrPid, MFAOrFun, TimeOut) |
|
|
|
loopTry(KeyIx, Key, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) |
|
|
|
end. |
|
|
|
|
|
|
|
loopTry(KeyIx, Key, ALockRef, CurPid, PidInt, GLockMgrPid, MFAOrFun, TimeOut) -> |
|
|
|
loopTry(KeyIx, Key, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> |
|
|
|
receive |
|
|
|
after ?ReTryTime -> |
|
|
|
LTimeOut = ?CASE(TimeOut == infinity, TimeOut, TimeOut - ?ReTryTime), |
|
|
|
case LTimeOut >= 0 of |
|
|
|
true -> |
|
|
|
case atomics:compare_exchange(ALockRef, KeyIx, 0, PidInt) of |
|
|
|
case tryLockOne(KeyIx, ALockRef, PidInt) of |
|
|
|
ok -> |
|
|
|
try doApply(MFAOrFun) |
|
|
|
catch C:R:S -> |
|
|
|
{error, {lock_apply_error, {C, R, S}}} |
|
|
|
after |
|
|
|
atomics:exchange(ALockRef, KeyIx, 0), |
|
|
|
ets:delete(?EtsGLockPid, CurPid), |
|
|
|
unlink(GLockMgrPid), |
|
|
|
ok |
|
|
|
end; |
|
|
|
_ -> |
|
|
|
loopTry(KeyIx, Key, ALockRef, CurPid, PidInt, GLockMgrPid, MFAOrFun, LTimeOut) |
|
|
|
loopTry(KeyIx, Key, ALockRef, CurPid, PidInt, MFAOrFun, LTimeOut) |
|
|
|
end; |
|
|
|
_ -> |
|
|
|
ets:delete(?EtsGLockPid, CurPid), |
|
|
|
unlink(GLockMgrPid), |
|
|
|
{error, {lock_timeout, Key}} |
|
|
|
end |
|
|
|
end. |
|
|
|
|
|
|
|
lockApplys(KeyIxs, Keys, ALockRef, CurPid, PidInt, GLockMgrPid, MFAOrFun, TimeOut) -> |
|
|
|
lockApplys(KeyIxs, Keys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> |
|
|
|
CurPid = self(), |
|
|
|
link(GLockMgrPid), |
|
|
|
ets:insert(?EtsGLockPid, {CurPid, KeyIxs}), |
|
|
|
case tryLockAll(KeyIxs, ALockRef, PidInt, []) of |
|
|
|
ok -> |
|
|
|
try doApply(MFAOrFun) |
|
|
@ -82,15 +71,13 @@ lockApplys(KeyIxs, Keys, ALockRef, CurPid, PidInt, GLockMgrPid, MFAOrFun, TimeOu |
|
|
|
{error, {lock_apply_error, {C, R, S}}} |
|
|
|
after |
|
|
|
[atomics:exchange(ALockRef, KeyIx, 0) || KeyIx <- KeyIxs], |
|
|
|
ets:delete(?EtsGLockPid, CurPid), |
|
|
|
unlink(GLockMgrPid), |
|
|
|
ok |
|
|
|
end; |
|
|
|
_ -> |
|
|
|
loopTrys(KeyIxs, Keys, ALockRef, CurPid, PidInt, GLockMgrPid, MFAOrFun, TimeOut) |
|
|
|
loopTrys(KeyIxs, Keys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) |
|
|
|
end. |
|
|
|
|
|
|
|
loopTrys(KeyIxs, Keys, ALockRef, CurPid, PidInt, GLockMgrPid, MFAOrFun, TimeOut) -> |
|
|
|
loopTrys(KeyIxs, Keys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) -> |
|
|
|
receive |
|
|
|
after ?ReTryTime -> |
|
|
|
LTimeOut = ?CASE(TimeOut == infinity, TimeOut, TimeOut - ?ReTryTime), |
|
|
@ -103,16 +90,12 @@ loopTrys(KeyIxs, Keys, ALockRef, CurPid, PidInt, GLockMgrPid, MFAOrFun, TimeOut) |
|
|
|
{error, {lock_apply_error, {C, R, S}}} |
|
|
|
after |
|
|
|
[atomics:exchange(ALockRef, KeyIx, 0) || KeyIx <- KeyIxs], |
|
|
|
ets:delete(?EtsGLockPid, CurPid), |
|
|
|
unlink(GLockMgrPid), |
|
|
|
ok |
|
|
|
end; |
|
|
|
_ -> |
|
|
|
loopTrys(KeyIxs, Keys, ALockRef, CurPid, PidInt, GLockMgrPid, MFAOrFun, TimeOut) |
|
|
|
loopTrys(KeyIxs, Keys, ALockRef, CurPid, PidInt, MFAOrFun, TimeOut) |
|
|
|
end; |
|
|
|
_ -> |
|
|
|
ets:delete(?EtsGLockPid, CurPid), |
|
|
|
unlink(GLockMgrPid), |
|
|
|
{error, {lock_timeout, Keys}} |
|
|
|
end |
|
|
|
end. |
|
|
@ -122,14 +105,32 @@ getKexIxs([Key | Keys], IxAcc) -> |
|
|
|
KeyIx = erlang:phash2(Key, ?eALockSize) + 1, |
|
|
|
getKexIxs(Keys, ?CASE(lists:member(KeyIx, IxAcc), IxAcc, [KeyIx | IxAcc])). |
|
|
|
|
|
|
|
tryLockOne(KeyIx, ALockRef, PidInt) -> |
|
|
|
case atomics:compare_exchange(ALockRef, KeyIx, 0, PidInt) of |
|
|
|
ok -> |
|
|
|
ok; |
|
|
|
OldPidInt -> |
|
|
|
case is_process_alive(eGPidInt:intToPid(OldPidInt)) of |
|
|
|
true -> |
|
|
|
false; |
|
|
|
_ -> |
|
|
|
case atomics:compare_exchange(ALockRef, KeyIx, OldPidInt, PidInt) of |
|
|
|
ok -> |
|
|
|
ok; |
|
|
|
_ -> |
|
|
|
false |
|
|
|
end |
|
|
|
end |
|
|
|
end. |
|
|
|
|
|
|
|
tryLockAll([], _ALockRef, _PidInt, _LockAcc) -> |
|
|
|
ok; |
|
|
|
tryLockAll([KeyIx | KeyIxs], ALockRef, PidInt, LockAcc) -> |
|
|
|
case atomics:compare_exchange(ALockRef, KeyIx, 0, PidInt) of |
|
|
|
case tryLockOne(KeyIx, ALockRef, PidInt) of |
|
|
|
ok -> |
|
|
|
tryLockAll(KeyIxs, ALockRef, PidInt, [KeyIx | LockAcc]); |
|
|
|
_ -> |
|
|
|
[atomics:exchange(ALockRef, OneLock, 0) || OneLock <- LockAcc], |
|
|
|
[atomics:compare_exchange(ALockRef, OneLock, PidInt, 0) || OneLock <- LockAcc], |
|
|
|
false |
|
|
|
end. |
|
|
|
|
|
|
|