Selaa lähdekoodia

ft: 添加transaction 事务执行

master
SisMaker 5 kuukautta sitten
vanhempi
commit
a11fb37fce
1 muutettua tiedostoa jossa 72 lisäystä ja 20 poistoa
  1. +72
    -20
      src/eGLock.erl

+ 72
- 20
src/eGLock.erl Näytä tiedosto

@ -10,6 +10,9 @@
%% %%
-define(eGLockSize, 2097152). -define(eGLockSize, 2097152).
%% ets key
-define(undefTab, undefTab).
-export([ -export([
tryLock/1 tryLock/1
, tryLock/2 , tryLock/2
@ -19,13 +22,11 @@
, lockApply/3 , lockApply/3
]). ]).
-export([ -export([
lockGet/1 lockGet/1
, lockGet/2 , lockGet/2
, transaction/2 , transaction/2
, transaction/3 , transaction/3
]). ]).
-spec tryLock(KeyOrKeys :: term() | [term()]) -> true | lockTimeout. -spec tryLock(KeyOrKeys :: term() | [term()]) -> true | lockTimeout.
@ -162,6 +163,21 @@ lockGet(KeyOrKeys) ->
lockGet(KeyOrKeys, ?LockTimeOut). lockGet(KeyOrKeys, ?LockTimeOut).
-spec lockGet(KeyOrKeys :: term() | [term()], TimeOut :: integer() | infinity) -> ok. -spec lockGet(KeyOrKeys :: term() | [term()], TimeOut :: integer() | infinity) -> ok.
lockGet({?undefTab, Key = GetKey}, TimeOut) ->
KeyIx = erlang:phash2(GetKey, ?eGLockSize),
case doTryLock(KeyIx, TimeOut) of
true ->
try
#{{?undefTab, GetKey} => undefined}
catch C:R:S ->
{error, {lockGetError, {?undefTab, Key}, {C, R, S}}}
after
eNifLock:releaseLock(KeyIx),
ok
end;
lockTimeout ->
{error, lockTimeout}
end;
lockGet({EtsTab, Key} = GetKey, TimeOut) -> lockGet({EtsTab, Key} = GetKey, TimeOut) ->
KeyIx = erlang:phash2(GetKey, ?eGLockSize), KeyIx = erlang:phash2(GetKey, ?eGLockSize),
case doTryLock(KeyIx, TimeOut) of case doTryLock(KeyIx, TimeOut) of
@ -177,6 +193,21 @@ lockGet({EtsTab, Key} = GetKey, TimeOut) ->
lockTimeout -> lockTimeout ->
{error, lockTimeout} {error, lockTimeout}
end; end;
lockGet({?undefTab, Key = GetKey, DefValue}, TimeOut) ->
KeyIx = erlang:phash2(GetKey, ?eGLockSize),
case doTryLock(KeyIx, TimeOut) of
true ->
try
#{{?undefTab, GetKey} => getDefValue(DefValue)}
catch C:R:S ->
{error, {lockGetError, {?undefTab, Key, DefValue}, {C, R, S}}}
after
eNifLock:releaseLock(KeyIx),
ok
end;
lockTimeout ->
{error, lockTimeout}
end;
lockGet({EtsTab, Key, DefValue}, TimeOut) -> lockGet({EtsTab, Key, DefValue}, TimeOut) ->
GetKey = {EtsTab, Key}, GetKey = {EtsTab, Key},
KeyIx = erlang:phash2(GetKey, ?eGLockSize), KeyIx = erlang:phash2(GetKey, ?eGLockSize),
@ -194,9 +225,7 @@ lockGet({EtsTab, Key, DefValue}, TimeOut) ->
{error, lockTimeout} {error, lockTimeout}
end; end;
lockGet(EtsTabKeys, TimeOut) -> 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, []),
{KeyIxs, KeysMap} = getKeyIxAndMaps(EtsTabKeys, [], #{}),
case doTryLocks(KeyIxs, TimeOut) of case doTryLocks(KeyIxs, TimeOut) of
true -> true ->
try try
@ -211,6 +240,28 @@ lockGet(EtsTabKeys, TimeOut) ->
{error, lockTimeout} {error, lockTimeout}
end. end.
getKeyIxAndMaps([], IxAcc, KeysMap) -> {IxAcc, KeysMap};
getKeyIxAndMaps([Key | Keys], IxAcc, KeysMap) ->
case Key of
{?undefTab, JustKey} ->
GetKey = Key,
LDefValue = undefined,
KeyIx = erlang:phash2(Key, ?eGLockSize);
{?undefTab, JustKey, DefValue} ->
GetKey = {?undefTab, JustKey},
LDefValue = DefValue,
KeyIx = erlang:phash2(Key, ?eGLockSize);
{EtsTab, TabKey} ->
GetKey = Key,
LDefValue = undefined,
KeyIx = erlang:phash2(Key, ?eGLockSize);
{EtsTab, TabKey, DefValue} ->
GetKey = {EtsTab, TabKey},
LDefValue = DefValue,
KeyIx = erlang:phash2(Key, ?eGLockSize)
end,
getKeyIxAndMaps(Keys, ?CASE(lists:member(KeyIx, IxAcc), IxAcc, [KeyIx | IxAcc]), KeysMap#{GetKey => LDefValue}).
transactionApply({M, F, Args}, EtsTabValue) -> transactionApply({M, F, Args}, EtsTabValue) ->
apply(M, F, [EtsTabValue | Args]); apply(M, F, [EtsTabValue | Args]);
transactionApply({Fun, Args}, EtsTabValue) -> transactionApply({Fun, Args}, EtsTabValue) ->
@ -222,22 +273,22 @@ transaction(EtsTabKeys, MFAOrFun) ->
-spec transaction(KeyOrKeys :: term() | [term()], MFAOrFun :: {M :: atom(), F :: atom(), Args :: list()} | {Fun :: function(), Args :: list()}, TimeOut :: integer() | infinity) -> term(). -spec transaction(KeyOrKeys :: term() | [term()], MFAOrFun :: {M :: atom(), F :: atom(), Args :: list()} | {Fun :: function(), Args :: list()}, TimeOut :: integer() | infinity) -> term().
transaction(EtsTabKeys, MFAOrFun, TimeOut) -> 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, []),
{KeyIxs, KeysMap} = getKeyIxAndMaps(EtsTabKeys, [], #{}),
case doTryLocks(KeyIxs, TimeOut) of case doTryLocks(KeyIxs, TimeOut) of
true -> true ->
try try
EtsTabValue = #{OneGetKey => getEtsTabValue(OneEtsTab, OneKey, OneDefValue) || {OneEtsTab, OneKey} = OneGetKey := OneDefValue <- KeysMap}, EtsTabValue = #{OneGetKey => getEtsTabValue(OneEtsTab, OneKey, OneDefValue) || {OneEtsTab, OneKey} = OneGetKey := OneDefValue <- KeysMap},
case transactionApply(MFAOrFun, EtsTabValue) of case transactionApply(MFAOrFun, EtsTabValue) of
{Ret, ChangeEtsTab} ->
{ok, Ret, ChangeEtsTab} ->
[changeEtsTabValue(OneEtsTab, OneKey, ChangeValue) || {OneEtsTab, OneKey} := ChangeValue <- ChangeEtsTab], [changeEtsTabValue(OneEtsTab, OneKey, ChangeValue) || {OneEtsTab, OneKey} := ChangeValue <- ChangeEtsTab],
Ret; Ret;
Ret ->
Ret
{ok, Ret} ->
Ret;
{error, Err} ->
Err
end end
catch catch
throw:Throw-> Throw;
throw:Throw -> Throw;
C:R:S -> C:R:S ->
{error, {lockTransactionError, {MFAOrFun, EtsTabKeys}, {C, R, S}}} {error, {lockTransactionError, {MFAOrFun, EtsTabKeys}, {C, R, S}}}
after after
@ -248,22 +299,23 @@ transaction(EtsTabKeys, MFAOrFun, TimeOut) ->
{error, lockTimeout} {error, lockTimeout}
end. end.
getEtsTabValue(undefined, _Key, DefValue) ->
DefValue;
getDefValue(undefined) -> undefined;
getDefValue({DefFun, Args}) when is_function(DefFun) -> erlang:apply(DefFun, Args);
getDefValue(DefValue) -> DefValue.
getEtsTabValue(?undefTab, _Key, DefValue) ->
getDefValue(DefValue);
getEtsTabValue(Ets, Key, DefValue) -> getEtsTabValue(Ets, Key, DefValue) ->
case ets:lookup(Ets, Key) of case ets:lookup(Ets, Key) of
[] -> [] ->
DefValue;
getDefValue(DefValue);
[OneValue] -> [OneValue] ->
OneValue OneValue
end. end.
changeEtsTabValue(undefined, _Key, _Value) ->
changeEtsTabValue(?undefTab, _Key, _Value) ->
ok; ok;
changeEtsTabValue(Ets, Key, delete) -> changeEtsTabValue(Ets, Key, delete) ->
ets:delete(Ets, Key); ets:delete(Ets, Key);
changeEtsTabValue(Ets, _Key, Value) -> changeEtsTabValue(Ets, _Key, Value) ->
ets:insert(Ets, Value).
ets:insert(Ets, Value).

Ladataan…
Peruuta
Tallenna