1 |
|
%%% ==================================================================== |
2 |
|
%%% ``The contents of this file are subject to the Erlang Public License, |
3 |
|
%%% Version 1.1, (the "License"); you may not use this file except in |
4 |
|
%%% compliance with the License. You should have received a copy of the |
5 |
|
%%% Erlang Public License along with this software. If not, it can be |
6 |
|
%%% retrieved via the world wide web at http://www.erlang.org/. |
7 |
|
%%% |
8 |
|
%%% |
9 |
|
%%% Software distributed under the License is distributed on an "AS IS" |
10 |
|
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See |
11 |
|
%%% the License for the specific language governing rights and limitations |
12 |
|
%%% under the License. |
13 |
|
%%% |
14 |
|
%%% |
15 |
|
%%% The Initial Developer of the Original Code is ProcessOne. |
16 |
|
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne |
17 |
|
%%% All Rights Reserved.'' |
18 |
|
%%% This software is copyright 2006-2015, ProcessOne. |
19 |
|
%%% |
20 |
|
%%% |
21 |
|
%%% @copyright 2006-2015 ProcessOne |
22 |
|
%%% @author Christophe Romain <christophe.romain@process-one.net> |
23 |
|
%%% [http://www.process-one.net/] |
24 |
|
%%% @end |
25 |
|
%%% ==================================================================== |
26 |
|
|
27 |
|
%% important note: |
28 |
|
%% new/1 and free/2 MUST be called inside a transaction bloc |
29 |
|
|
30 |
|
-module(pubsub_index). |
31 |
|
-author('christophe.romain@process-one.net'). |
32 |
|
|
33 |
|
-include("pubsub.hrl"). |
34 |
|
|
35 |
|
-export([init/0, new/1]). |
36 |
|
|
37 |
|
init() -> |
38 |
:-( |
mongoose_mnesia:create_table(pubsub_index, |
39 |
|
[{disc_copies, [node()]}, |
40 |
|
{attributes, record_info(fields, pubsub_index)}]). |
41 |
|
|
42 |
|
new(Index) -> |
43 |
|
%% Create a new short lived transaction to reduce lock contention |
44 |
:-( |
spawn_and_call(fun() -> mnesia:transaction(fun() -> new_transaction(Index) end) end). |
45 |
|
|
46 |
|
new_transaction(Index) -> |
47 |
:-( |
case mnesia:wread({pubsub_index, Index}) of |
48 |
|
[I] -> |
49 |
:-( |
Id = I#pubsub_index.last + 1, |
50 |
:-( |
mnesia:write(I#pubsub_index{last = Id}), |
51 |
:-( |
Id; |
52 |
|
_ -> |
53 |
:-( |
mnesia:write(#pubsub_index{index = Index, last = 1, free = []}), |
54 |
:-( |
1 |
55 |
|
end. |
56 |
|
|
57 |
|
spawn_and_call(F) -> |
58 |
:-( |
Ref = make_ref(), |
59 |
:-( |
Parent = self(), |
60 |
:-( |
FF = fun() -> Result = F(), Parent ! {call_result, Ref, Result} end, |
61 |
:-( |
Pid = spawn_monitor(FF), |
62 |
:-( |
receive |
63 |
|
{call_result, Ref, Result} -> |
64 |
:-( |
{atomic, NewId} = Result, |
65 |
:-( |
erlang:demonitor(Ref, [flush]), |
66 |
:-( |
NewId; |
67 |
|
{'DOWN', Ref, process, Pid, Reason} -> |
68 |
:-( |
erlang:error({spawn_and_call_failed, Reason}) |
69 |
|
after 5000 -> |
70 |
:-( |
erlang:demonitor(Ref, [flush]), |
71 |
:-( |
erlang:error(spawn_and_call_timeout) |
72 |
|
end. |