Skip to content

Commit 8b88549

Browse files
committed
Initial creation of ets_ring_buffer_ro and ets owning FSM
1 parent baf364f commit 8b88549

3 files changed

Lines changed: 504 additions & 0 deletions

File tree

src/epocxy_ets_fsm.erl

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
%%%------------------------------------------------------------------------------
2+
%%% @copyright (c) 2014-2014, DuoMark International, Inc.
3+
%%% @author Jay Nelson <jay@duomark.com>
4+
%%% @reference 2014-2015 Development sponsored by TigerText, Inc. [http://tigertext.com/]
5+
%%% @reference The license is based on the template for Modified BSD from
6+
%%% <a href="http://opensource.org/licenses/BSD-3-Clause">OSI</a>
7+
%%% @doc
8+
%%% The epocxy ETS FSM is the owner of all ETS tables needed when
9+
%%% constructing ets_buffers and other patterns. It allows the
10+
%%% generation of an unnamed ETS table so that atomic operations
11+
%%% which swap one table for another to replace a set of data can
12+
%%% be efficiently implemented without worrying about the ETS
13+
%%% owning process dying and losing the table.
14+
%%%
15+
%%% Tables are created as sets with public access and a key that
16+
%%% is the first field of a record. The caller may request read
17+
%%% and/or write concurrency to be set. The purpose of generated
18+
%%% tables is for maximum concurrency, so they must be accessible
19+
%%% by all processes.
20+
%%%
21+
%%% @since v0.9.8d
22+
%%% @end
23+
%%%------------------------------------------------------------------------------
24+
-module(epocxy_ets_fsm).
25+
-author('Jay Nelson <jay@duomark.com>').
26+
27+
-behaviour(gen_fsm).
28+
29+
%% API
30+
-export([
31+
start_link/0,
32+
create_ets_table/1, create_ets_table/2,
33+
delete_ets_table/1
34+
]).
35+
36+
%% gen_fsm state functions
37+
-export(['READY'/2, 'READY'/3]).
38+
39+
%% gen_fsm callbacks
40+
-export([init/1, terminate/3, code_change/4,
41+
handle_event/3, handle_sync_event/4, handle_info/3]).
42+
43+
-define(SERVER, ?MODULE).
44+
45+
-record(eef_state, {}).
46+
47+
48+
%%%===================================================================
49+
%%% External API
50+
%%%===================================================================
51+
52+
-type ets_concurrency() :: none | read_only | write_only | read_and_write.
53+
-export_type([ets_concurrency/0]).
54+
55+
-spec start_link() -> {ok, pid()}.
56+
-spec create_ets_table(ets_concurrency()) -> ets:tid().
57+
-spec create_ets_table(atom(), ets_concurrency()) -> ets:tid().
58+
-spec delete_ets_table(atom() | ets:tid()) -> ok.
59+
60+
start_link() ->
61+
gen_fsm:start_link({local, ?SERVER}, ?MODULE, {}, []).
62+
63+
create_ets_table(Concurrency_Type) ->
64+
Options = make_options(Concurrency_Type),
65+
gen_fsm:sync_send_event(?SERVER, {create_ets_table, Options}).
66+
67+
create_ets_table(Name, Concurrency_Type)
68+
when is_atom(Name) ->
69+
Options = [named_table | make_options(Concurrency_Type)],
70+
gen_fsm:sync_send_event(?SERVER, {create_ets_table, Name, Options}).
71+
72+
delete_ets_table(Table_Id_Or_Name) ->
73+
gen_fsm:sync_send_event(?SERVER, {delete_ets_table, Table_Id_Or_Name}).
74+
75+
make_options(none) -> make_base_options([]);
76+
make_options(read_only) -> make_base_options([{read_concurrency, true}]);
77+
make_options(write_only) -> make_base_options([{write_concurrency, true}]);
78+
make_options(read_and_write) -> make_base_options([{read_concurrency, true},
79+
{write_concurrency, true}]).
80+
81+
make_base_options(Concurrency_Options) ->
82+
[set, public, {keypos, 2}] ++ Concurrency_Options.
83+
84+
85+
%%%===================================================================
86+
%%% gen_fsm callbacks
87+
%%%===================================================================
88+
89+
-type internal_state() :: #eef_state{}.
90+
-type state_name() :: 'READY'.
91+
-type create_ets_cmd() :: {create_ets_table, proplists:proplist()}
92+
| {create_ets_table, Name::atom(), proplists:proplist()}.
93+
-type delete_ets_cmd() :: {delete_ets_table, ets:tid() | atom()}.
94+
-type stop_cmd() :: stop.
95+
%% -type ready_cmds() :: create_ets_cmd() | delete_ets_cmd() | stop_cmd().
96+
97+
-spec init({}) -> {ok, 'READY', internal_state()}.
98+
-spec terminate (any(), state_name(), internal_state()) -> ok.
99+
-spec code_change (any(), state_name(), internal_state(), any()) -> {ok, state_name(), #eef_state{}}.
100+
101+
init({}) ->
102+
{ok, 'READY', #eef_state{}}.
103+
104+
terminate (_Reason, _State_Name, #eef_state{}) -> ok.
105+
code_change (_OldVsn, State_Name, #eef_state{} = State, _Extra) -> {ok, State_Name, State}.
106+
107+
%% The FSM has only the 'READY' state.
108+
-type from() :: {pid(), reference()}.
109+
-spec 'READY'(create_ets_cmd(), from(), internal_state()) -> ets:tid();
110+
(delete_ets_cmd(), from(), internal_state()) -> ok;
111+
(stop_cmd(), from(), internal_state()) -> {stop, normal}.
112+
113+
'READY'({create_ets_table, Name, Options}, _From, #eef_state{} = State) when is_atom(Name), is_list(Options) -> {reply, ets:new(Name, Options), 'READY', State};
114+
'READY'({create_ets_table, Options}, _From, #eef_state{} = State) when is_list(Options) -> {reply, ets:new(noname, Options), 'READY', State};
115+
'READY'({delete_ets_table, Table}, _From, #eef_state{} = State) when is_atom(Table); is_integer(Table) -> {reply, ets:delete(Table), 'READY', State};
116+
117+
%% Stop the ets owner FSM process.
118+
'READY'(stop, _From, #eef_state{}) -> {stop, normal}.
119+
120+
%% No asynch events are expected.
121+
'READY'(_Any, #eef_state{} = State) -> {next_state, 'READY', State}.
122+
123+
-spec handle_info (any(), state_name(), internal_state())
124+
-> {next_state, state_name(), internal_state()}.
125+
126+
handle_info (_Info, State_Name, #eef_state{} = State) ->
127+
{next_state, State_Name, State}.
128+
129+
%% Handle event and sync_event aren't used
130+
-spec handle_event(any(), state_name(), internal_state())
131+
-> {next_state, state_name(), internal_state()}.
132+
-spec handle_sync_event(any(), {pid(), reference()}, state_name(), internal_state())
133+
-> {reply, any(), state_name(), internal_state()}.
134+
135+
handle_event (_Event, State_Name, #eef_state{} = State) -> {next_state, State_Name, State}.
136+
handle_sync_event (_Event, _From, State_Name, #eef_state{} = State) -> {reply, ok, State_Name, State}.

src/epocxy_sup.erl

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
%%%------------------------------------------------------------------------------
2+
%%% @copyright (c) 2014-2015, DuoMark International, Inc.
3+
%%% @author Jay Nelson <jay@duomark.com>
4+
%%% @reference 2014-2015 Development sponsored by TigerText, Inc. [http://tigertext.com/]
5+
%%% @reference The license is based on the template for Modified BSD from
6+
%%% <a href="http://opensource.org/licenses/BSD-3-Clause">OSI</a>
7+
%%% @doc
8+
%%% The epocxy supervisor provides a supervised FSM to manage any ets
9+
%%% tables that are needed by the concurrency library. This FSM is
10+
%%% intended to outlive any patterns which are built on ets tables.
11+
%%%
12+
%%% @since v0.9.8d
13+
%%% @end
14+
%%%------------------------------------------------------------------------------
15+
-module(epocxy_sup).
16+
-author('Jay Nelson <jay@duomark.com>').
17+
18+
-behaviour(supervisor).
19+
20+
%% API
21+
-export([start_link/0]).
22+
23+
%% Supervisor callbacks
24+
-export([init/1]).
25+
26+
-define(SERVER, ?MODULE).
27+
28+
29+
%% ===================================================================
30+
%% API functions
31+
%% ===================================================================
32+
33+
-spec start_link() -> {ok, pid()}.
34+
35+
start_link() ->
36+
supervisor:start_link({local, ?SERVER}, ?MODULE, {}).
37+
38+
39+
%% ===================================================================
40+
%% Supervisor callbacks
41+
%% ===================================================================
42+
43+
-type restart() :: {supervisor:strategy(), non_neg_integer(), non_neg_integer()}.
44+
-type sup_init_return() :: {ok, {restart(), [supervisor:child_spec()]}}.
45+
46+
-spec init({}) -> sup_init_return().
47+
48+
-define(CHILD(__Mod, __Args), {__Mod, {__Mod, start_link, __Args}, temporary, 2000, worker, [__Mod]}).
49+
50+
init({}) ->
51+
Epocxy_Ets_Fsm = ?CHILD(epocxy_ets_fsm, []),
52+
{ok, { {one_for_one, 5, 60}, [Epocxy_Ets_Fsm]} }.

0 commit comments

Comments
 (0)