feat(sessds): use trees to hold streams in session state
This commit is contained in:
parent
532f04da9d
commit
dc73b957b3
|
@ -113,7 +113,7 @@
|
||||||
-type pmap(K, V) ::
|
-type pmap(K, V) ::
|
||||||
#pmap{
|
#pmap{
|
||||||
table :: atom(),
|
table :: atom(),
|
||||||
cache :: #{K => V},
|
cache :: #{K => V} | gb_trees:tree(K, V),
|
||||||
dirty :: #{K => dirty | del}
|
dirty :: #{K => dirty | del}
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
@ -619,7 +619,7 @@ update_pmaps(Fun, Map) ->
|
||||||
%% This functtion should be ran in a transaction.
|
%% This functtion should be ran in a transaction.
|
||||||
-spec pmap_open(atom(), emqx_persistent_session_ds:id()) -> pmap(_K, _V).
|
-spec pmap_open(atom(), emqx_persistent_session_ds:id()) -> pmap(_K, _V).
|
||||||
pmap_open(Table, SessionId) ->
|
pmap_open(Table, SessionId) ->
|
||||||
Clean = maps:from_list(kv_pmap_restore(Table, SessionId)),
|
Clean = cache_from_list(Table, kv_pmap_restore(Table, SessionId)),
|
||||||
#pmap{
|
#pmap{
|
||||||
table = Table,
|
table = Table,
|
||||||
cache = Clean,
|
cache = Clean,
|
||||||
|
@ -627,29 +627,29 @@ pmap_open(Table, SessionId) ->
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-spec pmap_get(K, pmap(K, V)) -> V | undefined.
|
-spec pmap_get(K, pmap(K, V)) -> V | undefined.
|
||||||
pmap_get(K, #pmap{cache = Cache}) ->
|
pmap_get(K, #pmap{table = Table, cache = Cache}) ->
|
||||||
maps:get(K, Cache, undefined).
|
cache_get(Table, K, Cache).
|
||||||
|
|
||||||
-spec pmap_put(K, V, pmap(K, V)) -> pmap(K, V).
|
-spec pmap_put(K, V, pmap(K, V)) -> pmap(K, V).
|
||||||
pmap_put(K, V, Pmap = #pmap{dirty = Dirty, cache = Cache}) ->
|
pmap_put(K, V, Pmap = #pmap{table = Table, dirty = Dirty, cache = Cache}) ->
|
||||||
Pmap#pmap{
|
Pmap#pmap{
|
||||||
cache = maps:put(K, V, Cache),
|
cache = cache_put(Table, K, V, Cache),
|
||||||
dirty = Dirty#{K => dirty}
|
dirty = Dirty#{K => dirty}
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-spec pmap_del(K, pmap(K, V)) -> pmap(K, V).
|
-spec pmap_del(K, pmap(K, V)) -> pmap(K, V).
|
||||||
pmap_del(
|
pmap_del(
|
||||||
Key,
|
Key,
|
||||||
Pmap = #pmap{dirty = Dirty, cache = Cache}
|
Pmap = #pmap{table = Table, dirty = Dirty, cache = Cache}
|
||||||
) ->
|
) ->
|
||||||
Pmap#pmap{
|
Pmap#pmap{
|
||||||
cache = maps:remove(Key, Cache),
|
cache = cache_remove(Table, Key, Cache),
|
||||||
dirty = Dirty#{Key => del}
|
dirty = Dirty#{Key => del}
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-spec pmap_fold(fun((K, V, A) -> A), A, pmap(K, V)) -> A.
|
-spec pmap_fold(fun((K, V, A) -> A), A, pmap(K, V)) -> A.
|
||||||
pmap_fold(Fun, Acc, #pmap{cache = Cache}) ->
|
pmap_fold(Fun, Acc, #pmap{table = Table, cache = Cache}) ->
|
||||||
maps:fold(Fun, Acc, Cache).
|
cache_fold(Table, Fun, Acc, Cache).
|
||||||
|
|
||||||
-spec pmap_commit(emqx_persistent_session_ds:id(), pmap(K, V)) -> pmap(K, V).
|
-spec pmap_commit(emqx_persistent_session_ds:id(), pmap(K, V)) -> pmap(K, V).
|
||||||
pmap_commit(
|
pmap_commit(
|
||||||
|
@ -660,7 +660,7 @@ pmap_commit(
|
||||||
(K, del) ->
|
(K, del) ->
|
||||||
kv_pmap_delete(Tab, SessionId, K);
|
kv_pmap_delete(Tab, SessionId, K);
|
||||||
(K, dirty) ->
|
(K, dirty) ->
|
||||||
V = maps:get(K, Cache),
|
V = cache_get(Tab, K, Cache),
|
||||||
kv_pmap_persist(Tab, SessionId, K, V)
|
kv_pmap_persist(Tab, SessionId, K, V)
|
||||||
end,
|
end,
|
||||||
Dirty
|
Dirty
|
||||||
|
@ -670,13 +670,110 @@ pmap_commit(
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-spec pmap_format(pmap(_K, _V)) -> map().
|
-spec pmap_format(pmap(_K, _V)) -> map().
|
||||||
pmap_format(#pmap{cache = Cache}) ->
|
pmap_format(#pmap{table = Table, cache = Cache}) ->
|
||||||
Cache.
|
cache_format(Table, Cache).
|
||||||
|
|
||||||
-spec pmap_size(pmap(_K, _V)) -> non_neg_integer().
|
-spec pmap_size(pmap(_K, _V)) -> non_neg_integer().
|
||||||
pmap_size(#pmap{cache = Cache}) ->
|
pmap_size(#pmap{table = Table, cache = Cache}) ->
|
||||||
|
cache_size(Table, Cache).
|
||||||
|
|
||||||
|
pmap_iter_after(After, #pmap{table = Table, cache = Cache}) ->
|
||||||
|
%% NOTE: Only valid for gbt-backed PMAPs.
|
||||||
|
gbt = cache_data_type(Table),
|
||||||
|
gbt_iter_after(After, Cache).
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
cache_data_type(?stream_tab) -> gbt;
|
||||||
|
cache_data_type(_Table) -> map.
|
||||||
|
|
||||||
|
cache_from_list(?stream_tab, L) ->
|
||||||
|
gbt_from_list(L);
|
||||||
|
cache_from_list(_Table, L) ->
|
||||||
|
maps:from_list(L).
|
||||||
|
|
||||||
|
cache_get(?stream_tab, K, Cache) ->
|
||||||
|
gbt_get(K, Cache, undefined);
|
||||||
|
cache_get(_Table, K, Cache) ->
|
||||||
|
maps:get(K, Cache, undefined).
|
||||||
|
|
||||||
|
cache_put(?stream_tab, K, V, Cache) ->
|
||||||
|
gbt_put(K, V, Cache);
|
||||||
|
cache_put(_Table, K, V, Cache) ->
|
||||||
|
maps:put(K, V, Cache).
|
||||||
|
|
||||||
|
cache_remove(?stream_tab, K, Cache) ->
|
||||||
|
gbt_remove(K, Cache);
|
||||||
|
cache_remove(_Table, K, Cache) ->
|
||||||
|
maps:remove(K, Cache).
|
||||||
|
|
||||||
|
cache_fold(?stream_tab, Fun, Acc, Cache) ->
|
||||||
|
gbt_fold(Fun, Acc, Cache);
|
||||||
|
cache_fold(_Table, Fun, Acc, Cache) ->
|
||||||
|
maps:fold(Fun, Acc, Cache).
|
||||||
|
|
||||||
|
cache_format(?stream_tab, Cache) ->
|
||||||
|
gbt_format(Cache);
|
||||||
|
cache_format(_Table, Cache) ->
|
||||||
|
Cache.
|
||||||
|
|
||||||
|
cache_size(?stream_tab, Cache) ->
|
||||||
|
gbt_size(Cache);
|
||||||
|
cache_size(_Table, Cache) ->
|
||||||
maps:size(Cache).
|
maps:size(Cache).
|
||||||
|
|
||||||
|
%% PMAP Cache implementation backed by `gb_trees'.
|
||||||
|
%% Supports iteration starting from specific key.
|
||||||
|
|
||||||
|
gbt_from_list(L) ->
|
||||||
|
lists:foldl(
|
||||||
|
fun({K, V}, Acc) -> gb_trees:insert(K, V, Acc) end,
|
||||||
|
gb_trees:empty(),
|
||||||
|
L
|
||||||
|
).
|
||||||
|
|
||||||
|
gbt_get(K, Cache, undefined) ->
|
||||||
|
case gb_trees:lookup(K, Cache) of
|
||||||
|
none -> undefined;
|
||||||
|
{_, V} -> V
|
||||||
|
end.
|
||||||
|
|
||||||
|
gbt_put(K, V, Cache) ->
|
||||||
|
gb_trees:enter(K, V, Cache).
|
||||||
|
|
||||||
|
gbt_remove(K, Cache) ->
|
||||||
|
gb_trees:delete(K, Cache).
|
||||||
|
|
||||||
|
gbt_format(Cache) ->
|
||||||
|
gb_trees:to_list(Cache).
|
||||||
|
|
||||||
|
gbt_fold(Fun, Acc, Cache) ->
|
||||||
|
It = gb_trees:iterator(Cache),
|
||||||
|
gbt_fold_iter(Fun, Acc, It).
|
||||||
|
|
||||||
|
gbt_fold_iter(Fun, Acc, It0) ->
|
||||||
|
case gb_trees:next(It0) of
|
||||||
|
{K, V, It} ->
|
||||||
|
gbt_fold_iter(Fun, Fun(K, V, Acc), It);
|
||||||
|
_ ->
|
||||||
|
Acc
|
||||||
|
end.
|
||||||
|
|
||||||
|
gbt_size(Cache) ->
|
||||||
|
gb_trees:size(Cache).
|
||||||
|
|
||||||
|
gbt_iter_after(After, Cache) ->
|
||||||
|
It0 = gb_trees:iterator_from(After, Cache),
|
||||||
|
case gb_trees:next(It0) of
|
||||||
|
{After, _, It} ->
|
||||||
|
It;
|
||||||
|
_ ->
|
||||||
|
It0
|
||||||
|
end.
|
||||||
|
|
||||||
|
gbt_iter_next(It) ->
|
||||||
|
gb_trees:next(It).
|
||||||
|
|
||||||
%% Functions dealing with set tables:
|
%% Functions dealing with set tables:
|
||||||
|
|
||||||
kv_persist(Tab, SessionId, Val0) ->
|
kv_persist(Tab, SessionId, Val0) ->
|
||||||
|
|
Loading…
Reference in New Issue