浏览代码

ft: 添加transaction 事务执行

master
SisMaker 6 个月前
父节点
当前提交
027af58f1d
共有 1 个文件被更改,包括 128 次插入10 次删除
  1. +128
    -10
      src/eGLock.erl

+ 128
- 10
src/eGLock.erl 查看文件

@ -1,6 +1,7 @@
-module(eGLock).
-define(CASE(Cond, Then, That), case Cond of true -> Then; _ -> That end).
-define(CASE(Expr, Expect, Then, ExprRet, That), case Expr of Expect -> Then; ExprRet -> That end).
%% :Ms
-define(LockTimeOut, 5000).
@ -18,7 +19,16 @@
, lockApply/3
]).
-spec tryLock(KeyOrKeys :: term() | [term()]) -> true | ltimeout.
-export([
lockGet/1
, lockGet/2
, transaction/2
, transaction/3
]).
-spec tryLock(KeyOrKeys :: term() | [term()]) -> true | lockTimeout.
tryLock(KeyOrKeys) ->
tryLock(KeyOrKeys, ?LockTimeOut).
@ -52,7 +62,7 @@ loopLock(KeyIx, TimeOut) ->
loopLock(KeyIx, LTimeOut)
end;
_ ->
ltimeout
lockTimeout
end
end.
@ -77,7 +87,7 @@ loopLocks(KeyIxs, TimeOut) ->
loopLocks(KeyIxs, LTimeOut)
end;
_ ->
ltimeout
lockTimeout
end
end.
@ -100,7 +110,7 @@ getLockPid(KeyOrKeys) ->
{KeyOrKeys, eNifLock:getLockPid(erlang:phash2(KeyOrKeys, ?eGLockSize))}
end.
-spec lockApply(KeyOrKeys :: term() | [term()], MFAOrFun :: {M :: atom(), F :: atom(), Args :: list()} | {Fun :: function(), Args :: list()}) -> term() | {error, ltimeout} | {error, {lock_apply_error, term()}}.
-spec lockApply(KeyOrKeys :: term() | [term()], MFAOrFun :: {M :: atom(), F :: atom(), Args :: list()} | {Fun :: function(), Args :: list()}) -> term() | {error, lockTimeout} | {error, {lockApplyError, term()}}.
lockApply(KeyOrKeys, MFAOrFun) ->
lockApply(KeyOrKeys, MFAOrFun, ?LockTimeOut).
@ -113,13 +123,13 @@ lockApply(KeyOrKeys, MFAOrFun, TimeOut) ->
true ->
try doApply(MFAOrFun)
catch C:R:S ->
{error, {lock_apply_error, {C, R, S}}}
{error, {lockApplyError, {C, R, S}}}
after
eNifLock:releaseLocks(KeyIxs),
ok
end;
ltimeout ->
{error, ltimeout}
lockTimeout ->
{error, lockTimeout}
end;
_ ->
KeyIx = erlang:phash2(KeyOrKeys, ?eGLockSize),
@ -127,13 +137,13 @@ lockApply(KeyOrKeys, MFAOrFun, TimeOut) ->
true ->
try doApply(MFAOrFun)
catch C:R:S ->
{error, {lock_apply_error, {C, R, S}}}
{error, {lockApplyError, {KeyOrKeys, MFAOrFun}, {C, R, S}}}
after
eNifLock:releaseLock(KeyIx),
ok
end;
ltimeout ->
{error, ltimeout}
lockTimeout ->
{error, lockTimeout}
end
end.
@ -147,5 +157,113 @@ doApply({M, F, Args}) ->
doApply({Fun, Args}) ->
apply(Fun, Args).
-spec lockGet(KeyOrKeys :: term() | [term()]) -> ok.
lockGet(KeyOrKeys) ->
lockGet(KeyOrKeys, ?LockTimeOut).
-spec lockGet(KeyOrKeys :: term() | [term()], TimeOut :: integer() | infinity) -> ok.
lockGet({EtsTab, Key} = GetKey, TimeOut) ->
KeyIx = erlang:phash2(GetKey, ?eGLockSize),
case doTryLock(KeyIx, TimeOut) of
true ->
try
#{GetKey => getEtsTabValue(EtsTab, Key, undefined)}
catch C:R:S ->
{error, {lockGetError, GetKey, {C, R, S}}}
after
eNifLock:releaseLock(KeyIx),
ok
end;
lockTimeout ->
{error, lockTimeout}
end;
lockGet({EtsTab, Key, DefValue}, TimeOut) ->
GetKey = {EtsTab, Key},
KeyIx = erlang:phash2(GetKey, ?eGLockSize),
case doTryLock(KeyIx, TimeOut) of
true ->
try
#{GetKey => getEtsTabValue(EtsTab, Key, DefValue)}
catch C:R:S ->
{error, {lockGetError, {EtsTab, Key, DefValue}, {C, R, S}}}
after
eNifLock:releaseLock(KeyIx),
ok
end;
lockTimeout ->
{error, lockTimeout}
end;
lockGet(EtsTabKeys, TimeOut) ->
KeysMap = #{{EtsTab, Key} => DefValue || OneEtsTabKey <- EtsTabKeys, case OneEtsTabKey of {EtsTab, Key} -> DefValue = undefined, true; {EtsTab, Key, DefValue} -> true end},
KeyOrKeys = maps:keys(KeysMap),
KeyIxs = getKexIxs(KeyOrKeys, []),
case doTryLocks(KeyIxs, TimeOut) of
true ->
try
#{OneGetKey => getEtsTabValue(OneEtsTab, OneKey, OneDefValue) || {OneEtsTab, OneKey} = OneGetKey := OneDefValue <- KeysMap}
catch C:R:S ->
{error, {lockGetError, EtsTabKeys, {C, R, S}}}
after
eNifLock:releaseLocks(KeyIxs),
ok
end;
lockTimeout ->
{error, lockTimeout}
end.
transactionApply({M, F, Args}, EtsTabValue) ->
apply(M, F, [EtsTabValue | Args]);
transactionApply({Fun, Args}, EtsTabValue) ->
apply(Fun, [EtsTabValue | Args]).
-spec transaction(KeyOrKeys :: term() | [term()], MFAOrFun :: {M :: atom(), F :: atom(), Args :: list()} | {Fun :: function(), Args :: list()}) -> term().
transaction(EtsTabKeys, MFAOrFun) ->
transaction(EtsTabKeys, MFAOrFun, ?LockTimeOut).
-spec transaction(KeyOrKeys :: term() | [term()], MFAOrFun :: {M :: atom(), F :: atom(), Args :: list()} | {Fun :: function(), Args :: list()}, TimeOut :: integer() | infinity) -> term().
transaction(EtsTabKeys, MFAOrFun, TimeOut) ->
KeysMap = #{{EtsTab, Key} => DefValue || OneEtsTabKey <- EtsTabKeys, case OneEtsTabKey of {EtsTab, Key} -> DefValue = undefined, true; {EtsTab, Key, DefValue} -> true end},
KeyOrKeys = maps:keys(KeysMap),
KeyIxs = getKexIxs(KeyOrKeys, []),
case doTryLocks(KeyIxs, TimeOut) of
true ->
try
EtsTabValue = #{OneGetKey => getEtsTabValue(OneEtsTab, OneKey, OneDefValue) || {OneEtsTab, OneKey} = OneGetKey := OneDefValue <- KeysMap},
case transactionApply(MFAOrFun, EtsTabValue) of
{Ret, ChangeEtsTab} ->
[changeEtsTabValue(OneEtsTab, OneKey, ChangeValue) || {OneEtsTab, OneKey} := ChangeValue <- ChangeEtsTab],
Ret;
Ret ->
Ret
end
catch
throw:Ret -> Ret;
C:R:S ->
{error, {lockTransactionError, {MFAOrFun, EtsTabKeys}, {C, R, S}}}
after
eNifLock:releaseLocks(KeyIxs),
ok
end;
lockTimeout ->
{error, lockTimeout}
end.
getEtsTabValue(undefined, _Key, DefValue) ->
DefValue;
getEtsTabValue(Ets, Key, DefValue) ->
case ets:lookup(Ets, Key) of
[] ->
DefValue;
[OneValue] ->
OneValue
end.
changeEtsTabValue(undefined, _Key, _Value) ->
ok;
changeEtsTabValue(Ets, Key, delete) ->
ets:delete(Ets, Key);
changeEtsTabValue(Ets, _Key, Value) ->
ets:insert(Ets, Value).

正在加载...
取消
保存