aboutsummaryrefslogtreecommitdiffstats
path: root/lib/cosNotification/src/cosNotification_eventDB.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/cosNotification/src/cosNotification_eventDB.erl')
-rw-r--r--lib/cosNotification/src/cosNotification_eventDB.erl1351
1 files changed, 0 insertions, 1351 deletions
diff --git a/lib/cosNotification/src/cosNotification_eventDB.erl b/lib/cosNotification/src/cosNotification_eventDB.erl
deleted file mode 100644
index cd3c74d617..0000000000
--- a/lib/cosNotification/src/cosNotification_eventDB.erl
+++ /dev/null
@@ -1,1351 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2015. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : cosNotification_eventDB.erl
-%% Purpose :
-%% Purpose : This module is supposed to centralize Event storage.
-%% Comments:
-%% * Setting Order Policy to AnyOrder eq. Priority order
-%%
-%% * Setting Discard Policy to AnyOrder eq. RejectNewEvents.
-%%
-%% * DB ordering: Since the deliver- and discard-order may differ we need
-%% two ets-tables, both of type 'ordered_set'. They contain:
-%% - table 1 (T1): deliver order key and the associated event.
-%% - table 2 (T2): discard order key.
-%%
-%% When adding a new event we add, if necessary, related keys in T2.
-%% For example, if we should discard events in FIFO order, the delivery
-%% order may be set to Priority order. If the Max Event limit is reached
-%% we first look in T2 to find out which event to discard by using and
-%% reorder the key elements. T2 gives {TimeStamp, Priority}, which is used
-%% to lookup in T1 as {Priority, TimeStamp}.
-%% A TimeStamp is always included in the DB keys, even if FIFO or LIFO
-%% is used, since lots of events probably will have the same prioity and
-%% with a little bit of bad luck some events will never be delivered.
-%%
-%% Note: deliver order AnyOrder and PriorityOrder is equal since the later
-%% is defined as default.
-%% discard order AnyOrder and RejectNewEvents is equal since the later
-%% is defined as default.
-%% The keys used is ('-' indicates T2 is not needed and, thus, not instantiated):
-%%
-%% T1 policy T1 Key T2 Policy T2 Key
-%% ------------------------------------------------------------------
-%% DeadlineOrder {DL, Key, Prio} PriorityOrder {Prio, Key, DL}
-%% DeadlineOrder {DL, Key} FifoOrder {Key, DL}
-%% DeadlineOrder {DL, Key} LifoOrder {Key, DL}
-%% DeadlineOrder {DL, Key} RejectNewEvents -
-%% DeadlineOrder {DL, Key} DeadlineOrder -
-%% FifoOrder {Key, DL} DeadlineOrder {DL, Key}
-%% FifoOrder {Key, Prio} PriorityOrder {Prio, Key}
-%% FifoOrder Key RejectNewEvents -
-%% FifoOrder Key Fifo -
-%% FifoOrder Key Lifo -
-%% PriorityOrder {Prio, Key, DL} DeadlineOrder {DL, Key, Prio}
-%% PriorityOrder {Prio, Key} Fifo {Key, Prio}
-%% PriorityOrder {Prio, Key} Lifo {Key, Prio}
-%% PriorityOrder {Prio, Key} RejectNewEvents -
-%% ------------------------------------------------------------------
-%% DL == Deadline, Key == TimeStamp, Prio == Priority
-%%
-%% NOTE: If defined, the Discard DB Keys are the same as in Event DB, except
-%% that the first and last Key change place. {K1,K2}<->{K2,K1} and
-%% {K1,K2,K3}<->{K3,K2,K1}.
-%%----------------------------------------------------------------------
--module(cosNotification_eventDB).
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
--include_lib("cosTime/include/TimeBase.hrl").
-
-%% Application files
--include("CosNotification.hrl").
--include("CosNotifyChannelAdmin.hrl").
--include("CosNotifyComm.hrl").
--include("CosNotifyFilter.hrl").
-
--include("CosNotification_Definitions.hrl").
-
-%%--------------- EXPORTS ------------------------------------
-%% Internal Filter Functions
--export([validate_event/5,
- create_db/4,
- destroy_db/1,
- get_event/1,
- get_event/2,
- get_events/2,
- get_events/3,
- delete_events/1,
- update/2,
- update/4,
- add_event/2,
- add_event/4,
- add_and_get_event/2,
- add_and_get_event/3,
- add_and_get_event/4,
- add_and_get_event/5,
- gc_events/2,
- gc_events_local/4,
- gc_start/2,
- filter_events/2,
- filter_events/3,
- status/2]).
-
-%%--------------- DATA STRUCTURES ----------------------------
--record(dbRef, {orderRef, discardRef, orderPolicy, discardPolicy,
- defPriority, maxEvents, defStopT, startTsupport,
- stopTsupport, gcTime, gcLimit, timeRef}).
-
-
-
-%%--------------- DEFINES ------------------------------------
-
--define(CreateRef(OR, DR, O, D, DP, ME, DS, StaT, StoT, GT, GL, TR),
- #dbRef{orderRef=OR, discardRef=DR, orderPolicy=O, discardPolicy=D,
- defPriority=DP, maxEvents=ME, defStopT=DS, startTsupport=StaT,
- stopTsupport=StoT, gcTime=GT, gcLimit=round(ME*GL/100),
- timeRef=TR}).
-
-
--define(get_OrderP(DR), DR#dbRef.orderPolicy).
--define(get_DiscardP(DR), DR#dbRef.discardPolicy).
--define(get_OrderRef(DR), DR#dbRef.orderRef).
--define(get_DiscardRef(DR), DR#dbRef.orderRef).
--define(get_DefPriority(DR), DR#dbRef.defPriority).
--define(get_MaxEvents(DR), DR#dbRef.maxEvents).
--define(get_DefStopT(DR), DR#dbRef.defStopT).
--define(get_StartTsupport(DR), DR#dbRef.startTsupport).
--define(get_StopTsupport(DR), DR#dbRef.stopTsupport).
--define(get_GCTime(DR), DR#dbRef.gcTime).
--define(get_GCLimit(DR), DR#dbRef.gcLimit).
--define(get_TimeRef(DR), DR#dbRef.timeRef).
-
--define(set_OrderP(DR, O), DR#dbRef{orderPolicy = O}).
--define(set_DiscardP(DR, D), DR#dbRef{discardPolicy = D}).
--define(set_OrderRef(DR, E), DR#dbRef{orderRef = E}).
--define(set_DiscardRef(DR, E), DR#dbRef{orderRef = E}).
--define(set_DefPriority(DR, DP), DR#dbRef{defPriority = DP}).
--define(set_MaxEvents(DR, ME), DR#dbRef{maxEvents = ME}).
--define(set_DefStopT(DR, DS), DR#dbRef{defStopT = DS}).
--define(set_StartTsupport(DR, B), DR#dbRef{startTsupport = B}).
--define(set_StopTsupport(DR, B), DR#dbRef{stopTsupport = B}).
-
--define(is_StartTNotSupported(DR), DR#dbRef.startTsupport == false).
--define(is_StopTNotSupported(DR), DR#dbRef.stopTsupport == false).
--define(is_TimeoutNotUsed(DR), DR#dbRef.defStopT == 0).
-
-
-%%------------------------------------------------------------
-%% function : status
-%% Arguments: DBRef
-%% Key - which information we want.
-%% Returns : Data related to the Key.
-%%------------------------------------------------------------
-status(DBRef, eventCounter) ->
- ets:info(?get_OrderRef(DBRef), size);
-status(DBRef, {batchLimit, Limit}) ->
- case ets:info(?get_OrderRef(DBRef), size) of
- Current when is_integer(Current) andalso Current >= Limit ->
- ?debug_print("BATCH LIMIT (~p) REACHED, CONTAINS: ~p~n", [Limit, Current]),
- true;
- _Other ->
- ?debug_print("BATCH LIMIT (~p) NOT REACHED, CONTAINS: ~p~n",
- [Limit, _Other]),
- false
- end;
-status(DBRef, {batchLimit, Limit, TemporaryMax}) ->
- case ets:info(?get_OrderRef(DBRef), size) of
- Current when is_integer(Current) andalso Current >= TemporaryMax ->
- ?debug_print("MAX LIMIT (~p) REACHED, CONTAINS: ~p~n",
- [TemporaryMax, Current]),
- true;
- Current when is_integer(Current) andalso Current >= Limit ->
- ?debug_print("BATCH LIMIT (~p) REACHED, CONTAINS: ~p~n", [Limit, Current]),
- true;
- _Other ->
- ?debug_print("BATCH LIMIT (~p) NOT REACHED, CONTAINS: ~p~n",
- [Limit, _Other]),
- false
- end;
-status(_, _) ->
- error.
-
-
-%%------------------------------------------------------------
-%% function : gc_events_local
-%% Arguments: DBRef
-%% Returns :
-%% Comment : This function is intended for "emergency" GC, i.e.,
-%% when the DB must discard events we should first try
-%% to remove events with expired deadlines.
-%%------------------------------------------------------------
-gc_events_local(_, _, false, _) ->
- ok;
-gc_events_local(_, _, _, 0) ->
- ok;
-gc_events_local(ORef, DRef, _, _) ->
- gc_loop(ets:first(ORef), ORef, DRef).
-
-%%------------------------------------------------------------
-%% function : gc_events
-%% Arguments: DBRef
-%% Priority - 'low', 'medium' or 'high'; will determine
-%% how important a fast gc is.
-%% Returns :
-%% Comment : This function is intended for background GC.
-%%------------------------------------------------------------
-gc_events(DBRef, _Priority) when ?is_TimeoutNotUsed(DBRef) ->
- ok;
-gc_events(DBRef, _Priority) when ?is_StopTNotSupported(DBRef) ->
- ok;
-gc_events(DBRef, Priority) ->
- TS = erlang:monotonic_time(),
- {resolution, TR} = lists:keyfind(resolution, 1, erlang:system_info(os_monotonic_time_source)),
- case get(oe_GC_timestamp) of
- Num when TS > Num ->
- put(oe_GC_timestamp, TS + ?get_GCTime(DBRef) * TR),
- spawn_link(?MODULE, gc_start, [DBRef, Priority]);
- _->
- ok
- end.
-
-%%------------------------------------------------------------
-%% function : gc_start
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-gc_start(#dbRef{orderRef = ORef, discardRef = DRef}, Priority) ->
- process_flag(priority, Priority),
- gc_loop(ets:first(ORef), ORef, DRef).
-
-gc_loop('$end_of_table', _, _) ->
- ok;
-gc_loop(Key, ORef, DRef) ->
- [{Keys,DL,_,_,_}]=ets:lookup(ORef, Key),
- case check_deadline(DL) of
- true when DRef == undefined ->
- ets:delete(ORef, Key);
- true ->
- ets:delete(ORef, Key),
- gc_discard_DB(Keys, DRef);
- _ ->
- ok
- end,
- gc_loop(ets:next(ORef, Key), ORef, DRef).
-
-gc_discard_DB({Key1, Key2}, DRef) ->
- ets:delete(DRef, {Key2, Key1});
-gc_discard_DB({Key1, Key2, Key3}, DRef) ->
- ets:delete(DRef, {Key3, Key2, Key1}).
-
-%%------------------------------------------------------------
-%% function : create_FIFO_Key
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-create_FIFO_Key() ->
- {M, S, U} = erlang:timestamp(),
- -M*1000000000000 - S*1000000 - U.
-
-%%------------------------------------------------------------
-%% function : convert_FIFO_Key
-%% Arguments:
-%% Returns : A timestamp tuple
-%% Comment : Used when we must reuse a timestamp, i.e., only
-%% when we must reorder the DB.
-%%------------------------------------------------------------
-convert_FIFO_Key(Key) ->
- K = abs(Key),
- Secs = trunc(K/1000000),
- M = trunc(K/1000000000000),
- S = Secs-M*1000000,
- U = K - S*1000000-M*1000000000000,
- {M, S, U}.
-
-%%------------------------------------------------------------
-%% function : extract_priority
-%% Arguments: Event
-%% Defalt Value
-%% Mapping Filter Value
-%% - false value not needed (depends on QoS type)
-%% - undefined value needed but no filter associated.
-%% Returns :
-%%------------------------------------------------------------
-extract_priority(_, _, false) ->
- false;
-extract_priority(#'CosNotification_StructuredEvent'
- {header = #'CosNotification_EventHeader'
- {variable_header = VH}}, DefPriority, undefined) ->
- extract_value(VH, ?not_Priority, DefPriority);
-%% Maybe a unstructured event.
-extract_priority(_, DefPriority, undefined) ->
- DefPriority;
-extract_priority(_, _, PriorityOverride) ->
- %% Must have an associated MappingFilter for Priority.
- PriorityOverride.
-
-%%------------------------------------------------------------
-%% function : extract_start_time
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-extract_start_time(_, false, _) ->
- false;
-extract_start_time(#'CosNotification_StructuredEvent'
- {header = #'CosNotification_EventHeader'
- {variable_header = VH}}, _, TRef) ->
- ST = case extract_value(VH, ?not_StartTime, undefined) of
- UTC when is_record(UTC, 'TimeBase_UtcT') ->
- UTC;
- _ ->
- false
- end,
- convert_time(ST, TRef, erlang:timestamp());
-extract_start_time(_, _, _) ->
- false.
-
-%%------------------------------------------------------------
-%% function : extract_deadline
-%% Arguments: Structured Event
-%% Default Timeout Value - TimeT or UtcT (see cosTime).
-%% StopTSupported - boolean().
-%% TRef - reference to TimeService
-%% Mapping Filter Value
-%% - false eq. value not needed (depends on QoS type)
-%% - undefined eq. value needed but no filter associated.
-%% Now - used when we want to reuse old TimeStamp which
-%% must be done when changing QoS.
-%% Returns : A modified return from erlang:timestamp().
-%%------------------------------------------------------------
-extract_deadline(_, _, _, _, false) ->
- false;
-extract_deadline(Event, DefaultT, StopTSupported, TRef, MappingVal) ->
- extract_deadline(Event, DefaultT, StopTSupported, TRef, MappingVal, erlang:timestamp()).
-
-extract_deadline(_, _, _, _, false, _) ->
- false;
-extract_deadline(#'CosNotification_StructuredEvent'
- {header = #'CosNotification_EventHeader'
- {variable_header = VH}}, DefaultT, StopTSupported,
- TRef, undefined, Now) ->
- DL = case extract_value(VH, ?not_Timeout, undefined) of
- undefined when StopTSupported == true, TRef =/= undefined ->
- case extract_value(VH, ?not_StopTime, undefined) of
- undefined ->
- DefaultT;
- DefinedTime ->
- DefinedTime
- end;
- undefined ->
- DefaultT;
- DefinedTime ->
- DefinedTime
- end,
- convert_time(DL, TRef, Now);
-%% Maybe a unstructured event.
-extract_deadline(_, Time, _, TRef, undefined, Now) ->
- convert_time(Time, TRef, Now);
-extract_deadline(_, _, _, TRef, DOverride, Now) ->
- %% Must have an associated MappingFilter defining a Deadline.
- convert_time(DOverride, TRef, Now).
-
-convert_time(0, _, _) ->
- false;
-convert_time(UTC, TRef, {M,S,U}) when is_record(UTC, 'TimeBase_UtcT') ->
- case catch get_time_diff(UTC, TRef) of
- {'EXCEPTION', _} ->
- false;
- {'EXIT', _} ->
- false;
- DL ->
- MicroSecs = round(DL/10),
- Secs = round(MicroSecs/1000000),
- MegaSecs = round(Secs/1000000),
- {-M-MegaSecs, -S-Secs+MegaSecs, -U-MicroSecs+Secs}
- end;
-convert_time(DL, _, {M,S,U}) when is_integer(DL) ->
- MicroSecs = round(DL/10),
- Secs = round(MicroSecs/1000000),
- MegaSecs = round(Secs/1000000),
- {-M-MegaSecs, -S-Secs+MegaSecs, -U-MicroSecs+Secs};
-convert_time(_, _, _) ->
- false.
-
-
-get_time_diff(UTC, TRef) ->
- UTO = 'CosTime_TimeService':universal_time(TRef),
- UTO2 = 'CosTime_TimeService':uto_from_utc(TRef, UTC),
- TIO = 'CosTime_UTO':time_to_interval(UTO, UTO2),
- #'TimeBase_IntervalT'{lower_bound=LB, upper_bound = UB} =
- 'CosTime_TIO':'_get_time_interval'(TIO),
- UB-LB.
-
-check_deadline(DL) when is_tuple(DL) ->
- {M,S,U} = erlang:timestamp(),
- DL >= {-M,-S,-U};
-check_deadline(_DL) ->
- %% This case will cover if no timeout is set.
- false.
-
-check_start_time(ST) when is_tuple(ST) ->
- {M,S,U} = erlang:timestamp(),
- ST >= {-M,-S,-U};
-check_start_time(_ST) ->
- %% This case will cover if no earliest delivery time is set.
- true.
-
-%%------------------------------------------------------------
-%% function : extract_value
-%% Arguments: A Property Sequence
-%% ID - wanted property string()
-%% Other - default-value.
-%% Returns : Value associated with given ID or default value.
-%%------------------------------------------------------------
-extract_value([], _, Other) ->
- Other;
-extract_value([#'CosNotification_Property'{name=ID, value=V}|_], ID, _) ->
- any:get_value(V);
-extract_value([_H|T], ID, Other) ->
- extract_value(T, ID, Other).
-
-%%------------------------------------------------------------
-%% function : get_event
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-get_event(DBRef) ->
- get_event(DBRef, true).
-get_event(DBRef, Delete) ->
- case get_events(DBRef, 1, Delete) of
- {[], false} ->
- {[], false};
- {[], false, Keys} ->
- {[], false, Keys};
- {[Event], Bool} ->
- {Event, Bool};
- {[Event], Bool, Keys} ->
- {Event, Bool, Keys}
- end.
-
-%%------------------------------------------------------------
-%% function : get_events
-%% Arguments:
-%% Returns : A list of events (possibly empty) and a boolean
-%% indicating if event found.
-%% Comments : Try to extract Max events from the database.
-%%------------------------------------------------------------
-get_events(#dbRef{orderRef = ORef, discardRef = DRef}, Max) ->
- event_loop(ets:last(ORef), ORef, DRef, Max, [], [], true).
-
-get_events(#dbRef{orderRef = ORef, discardRef = DRef}, Max, Delete) ->
- event_loop(ets:last(ORef), ORef, DRef, Max, [], [], Delete).
-
-event_loop('$end_of_table', _, _, _, [], _, true) ->
- {[], false};
-event_loop('$end_of_table', _, _, _, [], [], _) ->
- {[], false, []};
-event_loop('$end_of_table', _ORef, _, _, Accum, _Keys, true) ->
- {lists:reverse(Accum), true};
-event_loop('$end_of_table', _ORef, _, _, Accum, Keys, _) ->
- {lists:reverse(Accum), true, Keys};
-event_loop(_, _ORef, _, 0, [], _Keys, true) ->
- %% Only possible if some tries to pull a sequence of 0 events.
- %% Should we really test for this case?
- {[], false};
-event_loop(_, _ORef, _, 0, [], Keys, _) ->
- {[], false, Keys};
-event_loop(_, _ORef, _, 0, Accum, _Keys, true) ->
- {lists:reverse(Accum), true};
-event_loop(_, _ORef, _, 0, Accum, Keys, _) ->
- {lists:reverse(Accum), true, Keys};
-event_loop(Key, ORef, undefined, Left, Accum, Keys, Delete) ->
- [{_,DL,ST,_PO,Event}]=ets:lookup(ORef, Key),
- case check_deadline(DL) of
- true ->
- ets:delete(ORef, Key),
- event_loop(ets:prev(ORef, Key), ORef, undefined,
- Left, Accum, Keys, Delete);
- false ->
- case check_start_time(ST) of
- true when Delete == true ->
- ets:delete(ORef, Key),
- event_loop(ets:prev(ORef, Key), ORef, undefined,
- Left-1, [Event|Accum], Keys, Delete);
- true ->
- event_loop(ets:prev(ORef, Key), ORef, undefined,
- Left-1, [Event|Accum], [{ORef, Key}|Keys], Delete);
- false ->
- event_loop(ets:prev(ORef, Key), ORef, undefined,
- Left, Accum, Keys, Delete)
- end
- end;
-event_loop({Key1, Key2}, ORef, DRef, Left, Accum, Keys, Delete) ->
- [{_,DL,ST,_PO,Event}]=ets:lookup(ORef, {Key1, Key2}),
- case check_deadline(DL) of
- true ->
- ets:delete(ORef, {Key1, Key2}),
- ets:delete(DRef, {Key2, Key1}),
- event_loop(ets:prev(ORef, {Key1, Key2}), ORef, DRef,
- Left, Accum, Keys, Delete);
- false ->
- case check_start_time(ST) of
- true when Delete == true ->
- ets:delete(ORef, {Key1, Key2}),
- ets:delete(DRef, {Key2, Key1}),
- event_loop(ets:prev(ORef, {Key1, Key2}), ORef, DRef,
- Left-1, [Event|Accum], Keys, Delete);
- true ->
- event_loop(ets:prev(ORef, {Key1, Key2}), ORef, DRef,
- Left-1, [Event|Accum],
- [{ORef, {Key1, Key2}}, {DRef, {Key2, Key1}}|Keys],
- Delete);
- false ->
- event_loop(ets:prev(ORef, {Key1, Key2}), ORef, DRef,
- Left, Accum, Keys, Delete)
- end
- end;
-event_loop({Key1, Key2, Key3}, ORef, DRef, Left, Accum, Keys, Delete) ->
- [{_,DL,ST,_PO,Event}]=ets:lookup(ORef, {Key1, Key2, Key3}),
- case check_deadline(DL) of
- true ->
- ets:delete(ORef, {Key1, Key2, Key3}),
- ets:delete(DRef, {Key3, Key2, Key1}),
- event_loop(ets:prev(ORef, {Key1, Key2, Key3}), ORef, DRef,
- Left, Accum, Keys, Delete);
- false ->
- case check_start_time(ST) of
- true when Delete == true ->
- ets:delete(ORef, {Key1, Key2, Key3}),
- ets:delete(DRef, {Key3, Key2, Key1}),
- event_loop(ets:prev(ORef, {Key1, Key2, Key3}), ORef, DRef,
- Left-1, [Event|Accum], Keys, Delete);
- true ->
- event_loop(ets:prev(ORef, {Key1, Key2, Key3}), ORef, DRef,
- Left-1, [Event|Accum],
- [{ORef, {Key1, Key2, Key3}},
- {DRef, {Key3, Key2, Key1}}|Keys], Delete);
- false ->
- event_loop(ets:prev(ORef, {Key1, Key2, Key3}), ORef, DRef,
- Left, Accum, Keys, Delete)
- end
- end.
-
-%%------------------------------------------------------------
-%% function : delete_events
-%% Arguments: EventList - what's returned by get_event, get_events
-%% and add_and_get_event.
-%% Returns :
-%% Comment : Shall be invoked when it's safe to premanently remove
-%% the events found in the EventList.
-%%
-%%------------------------------------------------------------
-delete_events([]) ->
- ok;
-delete_events([{DB, Key}|T]) ->
- ets:delete(DB, Key),
- delete_events(T).
-
-%%------------------------------------------------------------
-%% function : update
-%% Arguments:
-%% Returns :
-%% Comment : As default we shall deliver Events in Priority order.
-%% Hence, if AnyOrder set we will still deliver in
-%% Priority order.
-%%------------------------------------------------------------
-update(undefined, _QoS) ->
- ok;
-update(DBRef, QoS) ->
- update(DBRef, QoS, undefined, undefined).
-
-update(DBRef, QoS, LifeFilter, PrioFilter) ->
- case updated_order(DBRef, ?not_GetOrderPolicy(QoS)) of
- false ->
- case updated_discard(DBRef, ?not_GetDiscardPolicy(QoS)) of
- false ->
- DBR2 = ?set_DefPriority(DBRef, ?not_GetPriority(QoS)),
- DBR3 = ?set_MaxEvents(DBR2, ?not_GetMaxEventsPerConsumer(QoS)),
- DBR4 = ?set_DefStopT(DBR3, ?not_GetTimeout(QoS)),
- DBR5 = ?set_StartTsupport(DBR4, ?not_GetStartTimeSupported(QoS)),
- DBR6 = ?set_StopTsupport(DBR5, ?not_GetStopTimeSupported(QoS)),
- case ets:info(?get_OrderRef(DBR6), size) of
- N when N =< ?get_MaxEvents(DBR6) ->
- %% Even if the QoS MaxEvents have been changed
- %% we don't reach the limit.
- DBR6;
- N ->
- %% The QoS MaxEvents must have been decreased.
- discard_events(DBR6, N-?get_MaxEvents(DBR6)),
- DBR6
- end;
- true ->
- destroy_discard_db(DBRef),
- NewDBRef = create_db(QoS, ?get_GCTime(DBRef), ?get_GCLimit(DBRef),
- ?get_TimeRef(DBRef)),
- move_events(DBRef, NewDBRef, ets:first(?get_OrderRef(DBRef)),
- LifeFilter, PrioFilter)
- end;
- true ->
- destroy_discard_db(DBRef),
- NewDBRef = create_db(QoS, ?get_GCTime(DBRef), ?get_GCLimit(DBRef),
- ?get_TimeRef(DBRef)),
- move_events(DBRef, NewDBRef, ets:first(?get_OrderRef(DBRef)),
- LifeFilter, PrioFilter)
- end.
-
-updated_order(#dbRef{orderPolicy = Equal}, Equal) -> false;
-updated_order(#dbRef{orderPolicy = ?not_PriorityOrder}, ?not_AnyOrder) -> false;
-updated_order(#dbRef{orderPolicy = ?not_AnyOrder}, ?not_PriorityOrder) -> false;
-updated_order(_, _) -> true.
-
-updated_discard(#dbRef{discardPolicy = Equal}, Equal) -> false;
-updated_discard(#dbRef{discardPolicy = ?not_RejectNewEvents}, ?not_AnyOrder) -> false;
-updated_discard(#dbRef{discardPolicy = ?not_AnyOrder}, ?not_RejectNewEvents) -> false;
-updated_discard(_, _) -> true.
-
-move_events(DBRef, NewDBRef, '$end_of_table', _, _) ->
- destroy_order_db(DBRef),
- case ets:info(?get_OrderRef(NewDBRef), size) of
- N when N =< ?get_MaxEvents(NewDBRef) ->
- %% Even if the QoS MaxEvents have been changed
- %% we don't reach the limit.
- NewDBRef;
- N ->
- %% The QoS MaxEvents must have been decreased.
- discard_events(DBRef, N-?get_MaxEvents(NewDBRef)),
- NewDBRef
- end;
-move_events(DBRef, NewDBRef, Key, LifeFilter, PrioFilter) ->
- [{Keys, DeadLine, StartTime, PriorityOverride, Event}] =
- ets:lookup(?get_OrderRef(DBRef), Key),
- case check_deadline(DeadLine) of
- true ->
- ok;
- _->
- write_event(?get_OrderP(DBRef),
- {Keys, DeadLine, StartTime, PriorityOverride, Event},
- DBRef, NewDBRef, Key, LifeFilter, PrioFilter)
- end,
- ets:delete(?get_OrderRef(DBRef), Key),
- move_events(DBRef, NewDBRef, ets:next(?get_OrderRef(DBRef), Key),
- LifeFilter, PrioFilter).
-
-%% We cannot use do_add_event directly since we MUST lookup the timestamp (TS).
-write_event(?not_DeadlineOrder, {{_, TS, _Prio}, DL, ST, PO, Event}, _DBRef, NewDBRef,
- _Key, _LifeFilter, _PrioFilter) ->
- StartT = update_starttime(NewDBRef, Event, ST),
- %% Deadline and Priority previously extracted.
- do_add_event(NewDBRef, Event, TS, DL, StartT, PO);
-write_event(?not_DeadlineOrder, {{_, TS}, DL, _ST, PO, Event}, _DBRef, NewDBRef,
- _Key, _LifeFilter, PrioFilter) ->
- %% Priority not previously extracted.
- POverride = update_priority(NewDBRef, PrioFilter, Event, PO),
- StartT = extract_start_time(Event, ?get_StartTsupport(NewDBRef),
- ?get_TimeRef(NewDBRef)),
- do_add_event(NewDBRef, Event, TS, DL, StartT, POverride);
-write_event(?not_FifoOrder, {{TS, _PorD}, DL, ST, PO, Event}, _DBRef, NewDBRef,
- _Key, LifeFilter, PrioFilter) ->
- %% Priority or Deadline have been extracted before but we cannot tell which.
- POverride = update_priority(NewDBRef, PrioFilter, Event, PO),
- DeadL = update_deadline(NewDBRef, LifeFilter, Event, TS, DL),
- StartT = update_starttime(NewDBRef, Event, ST),
- do_add_event(NewDBRef, Event, TS, DeadL, StartT, POverride);
-write_event(?not_FifoOrder, {TS, DL, ST, PO, Event}, _DBRef, NewDBRef,
- _Key, LifeFilter, PrioFilter) ->
- %% Priority and Deadline not extracetd before. Do it now.
- POverride = update_priority(NewDBRef, PrioFilter, Event, PO),
- DeadL = update_deadline(NewDBRef, LifeFilter, Event, TS, DL),
- StartT = update_starttime(NewDBRef, Event, ST),
- do_add_event(NewDBRef, Event, TS, DeadL, StartT, POverride);
-%% Order Policy must be AnyOrder or PriorityOrder.
-write_event(_, {{_Prio, TS}, DL, ST, PO, Event}, _DBRef, NewDBRef,
- _Key, LifeFilter, _PrioFilter) ->
- DeadL = update_deadline(NewDBRef, LifeFilter, Event, TS, DL),
- StartT = update_starttime(NewDBRef, Event, ST),
- do_add_event(NewDBRef, Event, TS, DeadL, StartT, PO);
-write_event(_, {{_Prio, TS, DL}, DL, ST, PO, Event}, _DBRef, NewDBRef, _Key, _, _) ->
- %% Both Deadline and Priority have been extracetd before.
- StartT = update_starttime(NewDBRef, Event, ST),
- do_add_event(NewDBRef, Event, TS, DL, StartT, PO).
-
-
-%%------------------------------------------------------------
-%% function : update_priority
-%% Arguments:
-%% Returns :
-%% Comment : The purpose with this function is to avoid
-%% calling MappingFilter priority again, especially
-%% deadline again (we especially want to avoid calling
-%% since it may require intra-ORB communication.
-%% Use only when doing an update.
-%%------------------------------------------------------------
-update_priority(DBRef, PrioFilter, Event, OldPrio) when is_atom(OldPrio) ->
- get_prio_mapping_value(DBRef, PrioFilter, Event);
-update_priority(_DBRef, _PrioFilter, _Event, OldPrio) ->
- OldPrio.
-
-%%------------------------------------------------------------
-%% function : update_deadline
-%% Arguments:
-%% Returns :
-%% Comment : The purpose with this function is to avoid
-%% calling MappingFilter or parsing the events for
-%% deadline again (we especially want to avoid calling
-%% the MappingFilter since it may require intra-ORB
-%% communication. Use only when doing an update.
-%%------------------------------------------------------------
-update_deadline(DBRef, _LifeFilter, _Event, _TS, _OldDeadL) when
- ?get_DiscardP(DBRef) =/= ?not_DeadlineOrder,
- ?get_OrderP(DBRef) =/= ?not_DeadlineOrder,
- ?is_StopTNotSupported(DBRef) ->
- %% We do not need to extract the Deadline since it will not be used.
- false;
-update_deadline(DBRef, LifeFilter, Event, TS, OldDeadL) when is_atom(OldDeadL) ->
- %% We need the Deadline and it have not been extracetd before.
- DOverride = get_life_mapping_value(DBRef, LifeFilter, Event),
- %% We must find out when the event was delivered; setting a deadline using
- %% a new timestamp would not be accurate since we cannot tell for how long
- %% the event have been waiting.
- OldNow = convert_FIFO_Key(TS),
- extract_deadline(Event, ?get_DefStopT(DBRef), ?get_StopTsupport(DBRef),
- ?get_TimeRef(DBRef), DOverride, OldNow);
-update_deadline(_DBRef, _LifeFilter, _Event, _TS, OldDeadL) ->
- %% We need the Deadline and it have been extracetd before.
- OldDeadL.
-
-%%------------------------------------------------------------
-%% function : update_starttime
-%% Arguments:
-%% Returns :
-%% Comment : The purpose with this function is to avoid
-%% parsing the events for starttime again.
-%% Use only when doing an update.
-%%------------------------------------------------------------
-update_starttime(DBRef, Event, OldStartT) when is_atom(OldStartT) ->
- %% Probably not previously extracted; try to get it.
- extract_start_time(Event, ?get_StartTsupport(DBRef), ?get_TimeRef(DBRef));
-update_starttime(_DBRef, _Event, OldStartT) ->
- %% Previously extracted.
- OldStartT.
-
-%%------------------------------------------------------------
-%% function : discard_events
-%% Arguments: DBRef
-%% N - number of events we must discard.
-%% Returns :
-%% Comment : As default we shall Reject New Events when the limit
-%% is reached. Any discard order will do the same.
-%%
-%% This function can only be used for the discard policies
-%% Fifo, Priority and Deadline. Any or RejectNewEvents
-%% will not allow events to be stored at all, i.e., no events
-%% to discard. Lifo will not be stored either since when
-%% trying to add an event it is definitely the last event in.
-%%------------------------------------------------------------
-%% Since no Discard DB must the same Order policy.
-discard_events(#dbRef{orderRef = ORef, discardRef = undefined,
- discardPolicy = ?not_DeadlineOrder}, N) ->
- ?debug_print("Discarding ~p events Deadline Order.",[N]),
- index_loop_backward(ets:last(ORef), undefined, ORef, N);
-discard_events(#dbRef{orderRef = ORef, discardRef = DRef,
- discardPolicy = ?not_DeadlineOrder}, N) ->
- ?debug_print("Discarding ~p events Deadline Order.",[N]),
- index_loop_backward(ets:last(DRef), DRef, ORef, N);
-%% Fifo.
-discard_events(#dbRef{orderRef = ORef, discardRef = undefined,
- discardPolicy = ?not_FifoOrder}, N) ->
- ?debug_print("Discarding ~p events Fifo Order.",[N]),
- index_loop_backward(ets:last(ORef), undefined, ORef, N);
-discard_events(#dbRef{orderRef = ORef, discardRef = DRef,
- discardPolicy = ?not_FifoOrder}, N) ->
- ?debug_print("Discarding ~p events Fifo Order.",[N]),
- index_loop_backward(ets:last(DRef), DRef, ORef, N);
-%% Lifo- or Priority-Order
-discard_events(#dbRef{orderRef = ORef, discardRef = undefined}, N) ->
- ?debug_print("Discarding ~p events Lifo- or Priority-Order.",[N]),
- index_loop_forward(ets:first(ORef), undefined, ORef, N);
-discard_events(#dbRef{orderRef = ORef, discardRef = DRef}, N) ->
- ?debug_print("Discarding ~p events Lifo- or Priority-Order.",[N]),
- index_loop_forward(ets:first(DRef), DRef, ORef, N).
-
-
-index_loop_forward('$end_of_table', _, _, _Left) ->
- ok;
-index_loop_forward(_, _, _, 0) ->
- ok;
-index_loop_forward(Key, undefined, ORef, Left) ->
- ets:delete(ORef, Key),
- NewKey=ets:next(ORef, Key),
- index_loop_forward(NewKey, undefined, ORef, Left-1);
-
-index_loop_forward({Key1, Key2, Key3}, DRef, ORef, Left) ->
- ets:delete(DRef, {Key1, Key2, Key3}),
- ets:delete(ORef, {Key3, Key2, Key1}),
- NewKey=ets:next(DRef, {Key1, Key2, Key3}),
- index_loop_forward(NewKey, DRef, ORef, Left-1);
-
-index_loop_forward({Key1, Key2}, DRef, ORef, Left) ->
- ets:delete(DRef, {Key1, Key2}),
- ets:delete(ORef, {Key2, Key1}),
- NewKey=ets:next(DRef, {Key1, Key2}),
- index_loop_forward(NewKey, DRef, ORef, Left-1).
-
-index_loop_backward('$end_of_table', _, _, _) ->
- ok;
-index_loop_backward(_, _, _, 0) ->
- ok;
-index_loop_backward(Key, undefined, ORef, Left) ->
- ets:delete(ORef, Key),
- NewKey=ets:prev(ORef, Key),
- index_loop_backward(NewKey, undefined, ORef, Left-1);
-index_loop_backward({Key1, Key2}, DRef, ORef, Left) ->
- ets:delete(DRef, {Key1, Key2}),
- ets:delete(ORef, {Key2, Key1}),
- NewKey=ets:prev(DRef, {Key1, Key2}),
- index_loop_backward(NewKey, DRef, ORef, Left-1);
-index_loop_backward({Key1, Key2, Key3}, DRef, ORef, Left) ->
- ets:delete(DRef, {Key1, Key2, Key3}),
- ets:delete(ORef, {Key3, Key2, Key1}),
- NewKey=ets:prev(DRef, {Key1, Key2, Key3}),
- index_loop_backward(NewKey, DRef, ORef, Left-1).
-
-%%------------------------------------------------------------
-%% function : add_and_get_event
-%% Arguments: DBRef and Event
-%% Returns : {[], bool()} | {Event, bool()}
-%% Comment : This function is a mixture of ad anf get events.
-%% The intended use to avoid storing an event when
-%% not necessary.
-%%------------------------------------------------------------
-add_and_get_event(DBRef, Event) ->
- add_and_get_event(DBRef, Event, undefined, undefined, true).
-
-add_and_get_event(DBRef, Event, Delete) ->
- add_and_get_event(DBRef, Event, undefined, undefined, Delete).
-
-add_and_get_event(DBRef, Event, LifeFilter, PrioFilter) ->
- add_and_get_event(DBRef, Event, LifeFilter, PrioFilter, true).
-
-add_and_get_event(DBRef, Event, LifeFilter, PrioFilter, Delete) ->
- case ets:info(?get_OrderRef(DBRef), size) of
- 0 when ?is_StartTNotSupported(DBRef), ?is_StopTNotSupported(DBRef),
- Delete == true ->
- %% No stored events and no timeouts used; just return the event.
- {Event, false};
- 0 when ?is_StartTNotSupported(DBRef), ?is_StopTNotSupported(DBRef) ->
- %% No stored events and no timeouts used; just return the event.
- {Event, false, []};
- 0 when ?is_StartTNotSupported(DBRef) ->
- %% Only deadline supported, lookup values and cehck if ok.
- DOverride = get_life_mapping_value(DBRef, LifeFilter, Event),
- DL = extract_deadline(Event, ?get_DefStopT(DBRef),
- ?get_StopTsupport(DBRef), ?get_TimeRef(DBRef),
- DOverride),
- case check_deadline(DL) of
- true when Delete == true ->
- %% Expired, just discard the event.
- {[], false};
- true ->
- {[], false, []};
- _ when Delete == true ->
- %% Not expired, we can safely return the event.
- {Event, false};
- _ ->
- %% Not expired, we can safely return the event.
- {Event, false, []}
- end;
- 0 when ?is_StopTNotSupported(DBRef) ->
- %% Only starttime allowed, test if we can deliver the event now.
- ST = extract_start_time(Event, ?get_StartTsupport(DBRef),
- ?get_TimeRef(DBRef)),
- case check_start_time(ST) of
- false when Delete == true ->
- DOverride = get_life_mapping_value(DBRef, LifeFilter, Event),
- POverride = get_prio_mapping_value(DBRef, PrioFilter, Event),
- DL = extract_deadline(Event, ?get_DefStopT(DBRef),
- ?get_StopTsupport(DBRef),
- ?get_TimeRef(DBRef), DOverride),
- do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride),
- {[], true};
- false ->
- DOverride = get_life_mapping_value(DBRef, LifeFilter, Event),
- POverride = get_prio_mapping_value(DBRef, PrioFilter, Event),
- DL = extract_deadline(Event, ?get_DefStopT(DBRef),
- ?get_StopTsupport(DBRef),
- ?get_TimeRef(DBRef), DOverride),
- do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride),
- {[], true, []};
- _ when Delete == true ->
- %% Starttime ok, just return the event.
- {Event, false};
- _ ->
- %% Starttime ok, just return the event.
- {Event, false, []}
- end;
- _->
- %% Event already stored, just have to accept the overhead.
- ST = extract_start_time(Event, ?get_StartTsupport(DBRef),
- ?get_TimeRef(DBRef)),
- DOverride = get_life_mapping_value(DBRef, LifeFilter, Event),
- POverride = get_prio_mapping_value(DBRef, PrioFilter, Event),
- DL = extract_deadline(Event, ?get_DefStopT(DBRef),
- ?get_StopTsupport(DBRef),
- ?get_TimeRef(DBRef), DOverride),
- do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride),
- get_event(DBRef, Delete)
- end.
-
-%%------------------------------------------------------------
-%% function : add_event
-%% Arguments: DBRef and Event
-%% Returns : true (or whatever 'ets:insert' returns) |
-%% {'EXCEPTION', #'IMP_LIMIT'{}}
-%% Comment : As default we shall deliver Events in Priority order.
-%% Hence, if AnyOrder set we will still deliver in
-%% Priority order. But we cannot use only the Priority
-%% value since if "all" events have the same priority
-%% there is a risk that some never will be delivered if
-%% the EventDB always contain events.
-%%
-%% When discard and order policy is equal we only use one
-%% DB since all we have to do is to "read from the other
-%% end" to discard the correct event(s).
-%%
-%% In the discard DB we must also store keys necessary to
-%% lookup the event in the order DB.
-%%
-%% If event limit reached 'IMPL_LIMIT' is raised if
-%% the discard policy is RejectNewEvents or AnyOrder.
-%% Theses two policies we currently define to be equal.
-%%------------------------------------------------------------
-
-add_event(DBRef, Event) ->
- %% Save overhead by first checking if we really need to extract
- %% Deadline and/or Priority.
- Deadline = get_life_mapping_value(DBRef, undefined, Event),
- Priority = get_prio_mapping_value(DBRef, undefined, Event),
- add_event_helper(DBRef, Event, Deadline, Priority).
-
-add_event(DBRef, Event, LifeFilter, PrioFilter) ->
- %% Save overhead by first checking if we really need to extract
- %% Deadline and/or Priority.
- Deadline = get_life_mapping_value(DBRef, LifeFilter, Event),
- Priority = get_prio_mapping_value(DBRef, PrioFilter, Event),
- add_event_helper(DBRef, Event, Deadline, Priority).
-
-add_event_helper(DBRef, Event, DOverride, POverride) ->
- case ets:info(?get_OrderRef(DBRef), size) of
- N when N < ?get_MaxEvents(DBRef), N > ?get_GCLimit(DBRef) ->
- gc_events(DBRef, low),
- DL = extract_deadline(Event, ?get_DefStopT(DBRef),
- ?get_StopTsupport(DBRef), ?get_TimeRef(DBRef),
- DOverride),
- case check_deadline(DL) of
- true ->
- true;
- _ ->
- ST = extract_start_time(Event, ?get_StartTsupport(DBRef),
- ?get_TimeRef(DBRef)),
- do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride)
- end;
- N when N < ?get_MaxEvents(DBRef) ->
- DL = extract_deadline(Event, ?get_DefStopT(DBRef),
- ?get_StopTsupport(DBRef), ?get_TimeRef(DBRef),
- DOverride),
- case check_deadline(DL) of
- true ->
- true;
- _ ->
- ST = extract_start_time(Event, ?get_StartTsupport(DBRef),
- ?get_TimeRef(DBRef)),
- do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride)
- end;
- _N when ?get_DiscardP(DBRef) == ?not_RejectNewEvents ->
- gc_events(DBRef, low),
- corba:raise(#'IMP_LIMIT'{completion_status=?COMPLETED_NO});
- _N when ?get_DiscardP(DBRef) == ?not_AnyOrder ->
- gc_events(DBRef, low),
- corba:raise(#'IMP_LIMIT'{completion_status=?COMPLETED_NO});
- _N when ?get_DiscardP(DBRef) == ?not_LifoOrder ->
- gc_events(DBRef, low),
- corba:raise(#'IMP_LIMIT'{completion_status=?COMPLETED_NO});
- _N ->
- gc_events(DBRef, low),
- %% Other discard policy; we must first store the event
- %% and the look up in the Discard DB which event we
- %% should remove.
- DL = extract_deadline(Event, ?get_DefStopT(DBRef),
- ?get_StopTsupport(DBRef), ?get_TimeRef(DBRef),
- DOverride),
- case check_deadline(DL) of
- true ->
- true;
- _ ->
- ST = extract_start_time(Event, ?get_StartTsupport(DBRef),
- ?get_TimeRef(DBRef)),
- do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride),
- discard_events(DBRef, 1)
- end
- end.
-
-
-do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_DeadlineOrder,
- discardRef = DRef, discardPolicy = ?not_PriorityOrder,
- defPriority = DefPrio, defStopT = _DefStopT}, Event, Key, DL, ST, PO) ->
- Prio = extract_priority(Event, DefPrio, PO),
- ets:insert(ORef, {{DL, Key, Prio}, DL, ST, PO, Event}),
- ets:insert(DRef, {{Prio, Key, DL}});
-do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_DeadlineOrder,
- discardRef = DRef, discardPolicy = ?not_FifoOrder,
- defStopT = _DefStopT}, Event, Key, DL, ST, PO) ->
- ets:insert(ORef, {{DL, Key}, DL, ST, PO, Event}),
- ets:insert(DRef, {{Key, DL}});
-do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_DeadlineOrder,
- discardRef = DRef, discardPolicy = ?not_LifoOrder,
- defStopT = _DefStopT}, Event, Key, DL, ST, PO) ->
- ets:insert(ORef, {{DL, Key}, DL, ST, PO, Event}),
- ets:insert(DRef, {{Key, DL}});
-%% Either the same (DeadlineOrder), RejectNewEvents or AnyOrder. No need
-%% to store anything in the discard policy, i.e., if the same we'll just
-%% read "from the other end" and AnyOrder and RejectNewEvents is equal.
-do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_DeadlineOrder,
- defStopT = _DefStopT}, Event, Key, DL, ST, PO) ->
- ets:insert(ORef, {{DL, Key}, DL, ST, PO, Event});
-
-
-do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_FifoOrder,
- discardRef = DRef, discardPolicy = ?not_DeadlineOrder,
- defStopT = _DefStopT}, Event, Key, DL, ST, PO) ->
- ets:insert(ORef, {{Key, DL}, DL, ST, PO, Event}),
- ets:insert(DRef, {{DL, Key}});
-do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_FifoOrder,
- discardRef = DRef, discardPolicy = ?not_PriorityOrder,
- defPriority = DefPrio}, Event, Key, DL, ST, PO) ->
- Prio = extract_priority(Event, DefPrio, PO),
- ets:insert(ORef, {{Key, Prio}, DL, ST, PO, Event}),
- ets:insert(DRef, {{Prio, Key}});
-%% The discard policy must RejectNewEvents, AnyOrder, Fifo or Lifo order.
-do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_FifoOrder,
- discardRef = _DRef}, Event, Key, DL, ST, PO) ->
- ets:insert(ORef, {Key, DL, ST, PO, Event});
-
-%% Order Policy must be AnyOrder or PriorityOrder.
-do_add_event(#dbRef{orderRef = ORef,
- discardRef = DRef, discardPolicy = ?not_DeadlineOrder,
- defPriority = DefPrio, defStopT = _DefStopT}, Event, Key, DL, ST, PO) ->
- Prio = extract_priority(Event, DefPrio, PO),
- ets:insert(ORef, {{Prio, Key, DL}, DL, ST, PO, Event}),
- ets:insert(DRef, {{DL, Key, Prio}});
-do_add_event(#dbRef{orderRef = ORef,
- discardRef = DRef, discardPolicy = ?not_FifoOrder,
- defPriority = DefPrio}, Event, Key, DL, ST, PO) ->
- Prio = extract_priority(Event, DefPrio, PO),
- ets:insert(ORef, {{Prio, Key}, DL, ST, PO, Event}),
- ets:insert(DRef, {{Key, Prio}});
-
-do_add_event(#dbRef{orderRef = ORef,
- discardRef = DRef, discardPolicy = ?not_LifoOrder,
- defPriority = DefPrio}, Event, Key, DL, ST, PO) ->
- Prio = extract_priority(Event, DefPrio, PO),
- ets:insert(ORef, {{Prio, Key}, DL, ST, PO, Event}),
- ets:insert(DRef, {{Key, Prio}});
-
-%% Order Policy must be AnyOrder or PriorityOrder and Discard Policy must be
-%% AnyOrder or RejectNewEvents
-do_add_event(#dbRef{orderRef = ORef, defPriority = DefPrio}, Event, Key, DL, ST, PO) ->
- Prio = extract_priority(Event, DefPrio, PO),
- ets:insert(ORef, {{Prio, Key}, DL, ST, PO, Event}).
-
-%%------------------------------------------------------------
-%% function : destroy_db
-%% Arguments: A DB reference
-%% Returns :
-%%------------------------------------------------------------
-destroy_db(#dbRef{orderRef = ORef, discardRef = undefined}) ->
- ets:delete(ORef);
-destroy_db(#dbRef{orderRef = ORef, discardRef = DRef}) ->
- ets:delete(ORef),
- ets:delete(DRef).
-
-%%------------------------------------------------------------
-%% function : destroy_discard_db
-%% Arguments: A DB reference
-%% Returns :
-%%------------------------------------------------------------
-destroy_discard_db(#dbRef{discardRef = undefined}) ->
- ok;
-destroy_discard_db(#dbRef{discardRef = DRef}) ->
- ets:delete(DRef).
-
-%%------------------------------------------------------------
-%% function : destroy_order_db
-%% Arguments: A DB reference
-%% Returns :
-%%------------------------------------------------------------
-destroy_order_db(#dbRef{orderRef = ORef}) ->
- ets:delete(ORef).
-
-%%------------------------------------------------------------
-%% function : create_db
-%% Arguments: QoS (local representation).
-%% Returns : A DB reference
-%%------------------------------------------------------------
-create_db(QoS, GCTime, GCLimit, TimeRef) ->
- DiscardRef =
- case {?not_GetDiscardPolicy(QoS), ?not_GetOrderPolicy(QoS)} of
- {Equal, Equal} ->
- undefined;
- {?not_PriorityOrder, ?not_AnyOrder} ->
- %% NOTE: Any- and Priority-Order delivery policy is equal.
- undefined;
- {?not_RejectNewEvents, _} ->
- undefined;
- {?not_AnyOrder, _} ->
- undefined;
- {?not_LifoOrder, ?not_FifoOrder} ->
- undefined;
- _ ->
- ets:new(oe_ets, [set, public, ordered_set])
- end,
- DBRef = ?CreateRef(ets:new(oe_ets, [set, public, ordered_set]),
- DiscardRef,
- ?not_GetOrderPolicy(QoS), ?not_GetDiscardPolicy(QoS),
- ?not_GetPriority(QoS), ?not_GetMaxEventsPerConsumer(QoS),
- ?not_GetTimeout(QoS), ?not_GetStartTimeSupported(QoS),
- ?not_GetStopTimeSupported(QoS), GCTime, GCLimit, TimeRef),
- if
- ?is_TimeoutNotUsed(DBRef), ?is_StopTNotSupported(DBRef) ->
- ok;
- true ->
- TS = erlang:monotonic_time(),
- {resolution, TR} = lists:keyfind(resolution, 1,
- erlang:system_info(os_monotonic_time_source)),
- put(oe_GC_timestamp, TS+GCTime*TR)
- end,
- DBRef.
-
-%%------------------------------------------------------------
-%% function : get_prio_mapping_value
-%% Arguments: A MappingFilter reference | undefined
-%% Event (Any or Structured)
-%% Returns : undefined | Data
-%%------------------------------------------------------------
-get_prio_mapping_value(DBRef, _, _) when ?get_DiscardP(DBRef) =/= ?not_PriorityOrder,
- ?get_OrderP(DBRef) =/= ?not_AnyOrder,
- ?get_OrderP(DBRef) =/= ?not_PriorityOrder ->
- false;
-get_prio_mapping_value(_, undefined, _) ->
- undefined;
-get_prio_mapping_value(_, MFilter, Event) when is_record(Event, 'any') ->
- case catch 'CosNotifyFilter_MappingFilter':match(MFilter, Event) of
- {false, DefVal} when is_record(DefVal, 'any') ->
- any:get_value(DefVal);
- {true, Matched} when is_record(Matched, 'any') ->
- any:get_value(Matched);
- _ ->
- undefined
- end;
-get_prio_mapping_value(_, MFilter, Event) ->
- case catch 'CosNotifyFilter_MappingFilter':match_structured(MFilter, Event) of
- {false, DefVal} when is_record(DefVal, 'any') ->
- any:get_value(DefVal);
- {true, Matched} when is_record(Matched, 'any') ->
- any:get_value(Matched);
- _ ->
- undefined
- end.
-
-%%------------------------------------------------------------
-%% function : get_life_mapping_value
-%% Arguments: A MappingFilter reference | undefined
-%% Event (Any or Structured)
-%% Returns : undefined | Data
-%%------------------------------------------------------------
-get_life_mapping_value(DBRef, _, _) when ?get_DiscardP(DBRef) =/= ?not_DeadlineOrder,
- ?get_OrderP(DBRef) =/= ?not_DeadlineOrder,
- ?is_StopTNotSupported(DBRef) ->
- false;
-get_life_mapping_value(_, undefined, _) ->
- undefined;
-get_life_mapping_value(_, MFilter, Event) when is_record(Event, 'any') ->
- case catch 'CosNotifyFilter_MappingFilter':match(MFilter, Event) of
- {false, DefVal} when is_record(DefVal, 'any') ->
- any:get_value(DefVal);
- {true, Matched} when is_record(Matched, 'any') ->
- any:get_value(Matched);
- _ ->
- undefined
- end;
-get_life_mapping_value(_, MFilter, Event) ->
- case catch 'CosNotifyFilter_MappingFilter':match_structured(MFilter, Event) of
- {false, DefVal} when is_record(DefVal, 'any') ->
- any:get_value(DefVal);
- {true, Matched} when is_record(Matched, 'any') ->
- any:get_value(Matched);
- _ ->
- undefined
- end.
-
-%%------------------------------------------------------------
-%% function : validate_event
-%% Arguments: Subscribe data
-%% A sequence of Events, 'structured' or an 'any' record
-%% A list of filter references
-%% Status, i.e., do we have to filter the events or just check subscr.
-%% Returns : A tuple of two lists; list1 the events that passed
-%% and list2 the events that didn't pass.
-%%------------------------------------------------------------
-validate_event(true, Events, Filters, _, 'MATCH') ->
- filter_events(Events, Filters, false);
-validate_event(true, Events, _Filters, _, _) ->
- {Events, []};
-validate_event({_Which, _WC}, Event, Filters, _, 'MATCH') when is_record(Event, any) ->
- filter_events(Event, Filters, false);
-validate_event({_Which, _WC}, Event, _Filters, _, _) when is_record(Event, any) ->
- {Event, []};
-validate_event({Which, WC}, Events, Filters, DBRef, 'MATCH') ->
- Passed=validate_event2(DBRef, Events, Which, WC, []),
- filter_events(Passed, Filters, true);
-validate_event({Which, WC}, Events, _Filters, DBRef, _) ->
- Passed=validate_event2(DBRef, Events, Which, WC, []),
- {lists:reverse(Passed), []}.
-
-validate_event2(_, [], _, _, []) ->
- [];
-validate_event2(_, [], _, _, Acc) ->
- Acc;
-validate_event2(DBRef, [Event|T], Which, WC, Acc) ->
- ET = ((Event#'CosNotification_StructuredEvent'.header)
- #'CosNotification_EventHeader'.fixed_header)
- #'CosNotification_FixedEventHeader'.event_type,
- CheckList =
- case Which of
- both ->
- [ET];
- domain ->
- [ET,
- ET#'CosNotification_EventType'{type_name=""},
- ET#'CosNotification_EventType'{type_name="*"}];
- type ->
- [ET,
- ET#'CosNotification_EventType'{domain_name=""},
- ET#'CosNotification_EventType'{domain_name="*"}];
- _ ->
- [ET,
- ET#'CosNotification_EventType'{type_name=""},
- ET#'CosNotification_EventType'{type_name="*"},
- ET#'CosNotification_EventType'{domain_name=""},
- ET#'CosNotification_EventType'{domain_name="*"}]
- end,
- case check_subscription(DBRef, CheckList) of
- true ->
- validate_event2(DBRef, T, Which, WC, [Event|Acc]);
- _->
- case catch cosNotification_Filter:match_types(
- ET#'CosNotification_EventType'.domain_name,
- ET#'CosNotification_EventType'.type_name,
- WC) of
- true ->
- validate_event2(DBRef, T, Which, WC, [Event|Acc]);
- _->
- validate_event2(DBRef, T, Which, WC, Acc)
- end
- end.
-
-check_subscription(_, []) ->
- false;
-check_subscription(DBRef, [H|T]) ->
- case ets:lookup(DBRef, H) of
- [] ->
- check_subscription(DBRef, T);
- _ ->
- true
- end.
-
-
-%%------------------------------------------------------------
-%% function : filter_events
-%% Arguments: A sequence of structured Events or #any
-%% Returns : A tuple of two lists; list1 the events that passed
-%% and list2 the events that didn't pass.
-%%------------------------------------------------------------
-
-filter_events(Events, []) ->
- {Events, []};
-filter_events(Events, Filters) ->
- filter_events(Events, Filters, [], [], false).
-
-filter_events(Events, [], false) ->
- {Events, []};
-filter_events(Events, [], _) ->
- {lists:reverse(Events), []};
-filter_events(Events, Filters, Reversed) ->
- filter_events(Events, Filters, [], [], Reversed).
-
-filter_events([], _, AccPassed, AccFailed, false) ->
- {lists:reverse(AccPassed), lists:reverse(AccFailed)};
-filter_events([], _, AccPassed, AccFailed, _) ->
- {AccPassed, AccFailed};
-filter_events([H|T], Filters, AccPassed, AccFailed, Reversed) ->
- case call_filters(Filters, H) of
- true ->
- filter_events(T, Filters, [H|AccPassed], AccFailed, Reversed);
- _ ->
- filter_events(T, Filters, AccPassed, [H|AccFailed], Reversed)
- end;
-filter_events(Any, Filters, _AccPassed, _AccFailed, _Reversed) ->
- case call_filters(Filters, Any) of
- true ->
- {Any, []};
- _ ->
- {[], Any}
- end.
-
-call_filters([], _) ->
- false;
-call_filters([{_,H}|T], Event) when is_record(Event, any) ->
- case catch 'CosNotifyFilter_Filter':match(H, Event) of
- true ->
- true;
- _->
- call_filters(T, Event)
- end;
-call_filters([{_,H}|T], Event) when ?not_isConvertedAny(Event) ->
- case catch 'CosNotifyFilter_Filter':match(H,
- Event#'CosNotification_StructuredEvent'.remainder_of_body) of
- true ->
- true;
- _->
- call_filters(T, Event)
- end;
-call_filters([{_,H}|T], Event) ->
- case catch 'CosNotifyFilter_Filter':match_structured(H, Event) of
- true ->
- true;
- _->
- call_filters(T, Event)
- end.
-
-
-%%--------------- END OF MODULE ------------------------------