TimeQueue.GbTrees (time_queue v1.2.1)
View SourceImplements a timers queue based on gb_trees.
The queue keys are a two-tuple composed of the timestamp of an event and an unique integer.
No erlang timers or processes are used, as the queue is only a data structure. The advantage is that the queue can be persisted on storage and keep working after restarting the runtime. The queue maintain its own list of unique integers to avoir relying on BEAM unique integers as they are reset on restart.
The main drawback is that the queue entries must be manually checked for expired timers.
Summary
Functions
Deletes an event from the queue and returns the new queue.
Deletes all entries from the queue whose values are equal to unwanted
.
Adds a new event to the queue with a TTL and the current system time as now/0
.
Adds a new event to the queue with a TTL relative to the given timestamp in milliseconds.
Adds a new event to the queue with an absolute timestamp.
Returns a new queue with entries for whom the given callback returned a truthy value.
Returns a new queue with entries for whom the given callback returned a truthy value.
Creates an empty time queue.
Returns the next value of the queue or a delay in milliseconds before the next value.
Returns the next value of the queue, or a delay, according to the given current time in milliseconds.
Returns the next event of the queue or a delay in milliseconds before the next value.
Returns the next event of the queue according to the given current time in milliseconds.
Extracts the next event in the queue or returns a delay.
Extracts the next event in the queue according to the given current time in milliseconds.
Extracts the next event of the queue with the current system time as now/0
.
Extracts the next event of the queue according to the given current time in milliseconds.
Returns the number of entries in the queue.
Returns a stream of all the events in the queue.
Returns the time to next event.
Returns the time to next event.
Provides a GenServer
compatible timeout from the queue, giving the time to
the next event.
Returns the absolute timestamp a queue event is scheduled for.
Returns the time reference of a queue event. This reference is used as a key to identify a unique event.
Returns the value of a queue event.
Types
@opaque event()
@type event_value() :: any()
@opaque id()
@opaque t()
@type timespec() :: {pos_integer(), timespec_unit()}
@type timespec_unit() ::
:ms
| :second
| :seconds
| :minute
| :minutes
| :hour
| :hours
| :day
| :days
| :week
| :weeks
@type timestamp_ms() :: pos_integer()
@opaque tref()
Functions
Deletes an event from the queue and returns the new queue.
It accepts a time reference or a full event. When an event is given, its time reference will be used to find the event to delete, meaning the queue event will be deleted even if the value of the passed event was tampered.
The function does not fail if the event cannot be found and simply returns the queue as-is.
Deletes all entries from the queue whose values are equal to unwanted
.
This function is slow with gb_trees
, see filter/2
.
Adds a new event to the queue with a TTL and the current system time as now/0
.
See enqueue/4
.
Adds a new event to the queue with a TTL relative to the given timestamp in milliseconds.
Returns {:ok, tref, new_queue}
where tref
is a timer reference.
Adds a new event to the queue with an absolute timestamp.
Returns {:ok, tref, new_queue}
where tref
is a timer reference.
Returns a new queue with entries for whom the given callback returned a truthy value.
With the gbtrees implementation, this operation is _very expensive as we convert the tree to and ordered list, filter the list, and convert back to a tree.
Returns a new queue with entries for whom the given callback returned a truthy value.
Unlinke filter/2
, the callback is only passed the event value.
This function is slow with gb_trees
, see filter/2
.
@spec new() :: t()
Creates an empty time queue.
iex> tq = TimeQueue.GbTrees.new()
iex> TimeQueue.GbTrees.peek_event(tq)
:empty
@spec peek(t()) :: :empty | {:delay, tref(), non_neg_integer()} | {:ok, event_value()}
Returns the next value of the queue or a delay in milliseconds before the next value.
See peek/2
.
@spec peek(t(), now :: timestamp_ms()) :: :empty | {:delay, tref(), non_neg_integer()} | {:ok, event_value()}
Returns the next value of the queue, or a delay, according to the given current time in milliseconds.
Just like pop/2
vs. pop_event/2
, peek
wil only return {:ok, value}
when a timeout is reached whereas peek_event
will return {:ok, event}
.
@spec peek_event(t()) :: :empty | {:delay, tref(), non_neg_integer()} | {:ok, event()}
Returns the next event of the queue or a delay in milliseconds before the next value.
event values can be retrieved with TimeQueue.GbTrees.value/1
.
See peek_event/2
.
@spec peek_event(t(), now :: timestamp_ms()) :: :empty | {:delay, tref(), non_neg_integer()} | {:ok, event()}
Returns the next event of the queue according to the given current time in milliseconds.
Possible return values are:
:empty
{:ok, event}
if the timestamp of the first event is<=
to the given current time.{:delay, tref, ms}
if the timestamp of the first event is>
to the given current time. The remaining amount of milliseconds is returned.
Example
iex> {:ok, tref, tq} = TimeQueue.GbTrees.new() |> TimeQueue.GbTrees.enqueue(100, :hello, _now = 0)
iex> {:delay, ^tref, 80} = TimeQueue.GbTrees.peek_event(tq, _now = 20)
iex> {:ok, _} = TimeQueue.GbTrees.peek_event(tq, _now = 100)
@spec pop(t()) :: :empty | {:delay, tref(), non_neg_integer()} | {:ok, event_value(), t()}
Extracts the next event in the queue or returns a delay.
See pop/2
.
@spec pop(t(), now :: timestamp_ms()) :: :empty | {:delay, tref(), non_neg_integer()} | {:ok, event_value(), t()}
Extracts the next event in the queue according to the given current time in milliseconds.
Much like pop_event/2
but the tuple returned when an event time is reached
(returns with :ok
) success will only contain the value inserted in the
queue.
Possible return values are:
:empty
{:ok, value, new_queue}
if the timestamp of the first event is<=
to the given current time. The event is deleted fromnew_queue
.{:delay, tref, ms}
if the timestamp of the first event is>
to the given current time. The remaining amount of milliseconds is returned.
Example
iex> {:ok, tref, tq} = TimeQueue.GbTrees.new() |> TimeQueue.GbTrees.enqueue(100, :hello, _now = 0)
iex> {:delay, ^tref, 80} = TimeQueue.GbTrees.pop(tq, _now = 20)
iex> {:ok, value, _} = TimeQueue.GbTrees.pop(tq, _now = 100)
iex> value
:hello
@spec pop_event(t()) :: :empty | {:delay, tref(), non_neg_integer()} | {:ok, event(), t()}
Extracts the next event of the queue with the current system time as now/0
.
See pop_event/2
.
@spec pop_event(t(), now :: timestamp_ms()) :: :empty | {:delay, tref(), non_neg_integer()} | {:ok, event(), t()}
Extracts the next event of the queue according to the given current time in milliseconds.
Possible return values are:
:empty
{:ok, event, new_queue}
if the timestamp of the first event is<=
to the given current time. The event is deleted fromnew_queue
.{:delay, tref, ms}
if the timestamp of the first event is>
to the given current time. The remaining amount of milliseconds is returned.
Example
iex> {:ok, tref, tq} = TimeQueue.GbTrees.new() |> TimeQueue.GbTrees.enqueue(100, :hello, _now = 0)
iex> {:delay, ^tref, 80} = TimeQueue.GbTrees.pop_event(tq, _now = 20)
iex> {:ok, _, _} = TimeQueue.GbTrees.pop_event(tq, _now = 100)
Returns the number of entries in the queue.
@spec stream(t()) :: Enumerable.t()
Returns a stream of all the events in the queue.
Note that this stream is immediate and does not wait for events.
Returns the time to next event.
Same as timeout(tq, :infinity, now())
. See timeout/3
.
Returns the time to next event.
Accepts either the current time or an atom to return when the queue is empty.
- If an integer is given, it will has the same result as
timeout(tq, :infinity, integer)
. - If an atom is given, it will has the same result as
timeout(tq, atom, now())
.
See timeout/3
.
@spec timeout(t(), :infinity | :hibernate | atom(), now :: timestamp_ms()) :: non_neg_integer() | :infinity | :hibernate | atom()
Provides a GenServer
compatible timeout from the queue, giving the time to
the next event.
Accepts the current time as a third argument or will default to the current system time.
Returns:
if_empty
when the queue is empty. A common value in that case is either:infinity
or:hibernate
.0
when there the next event time has been reached.- The delay to the next event otherwise.
For instance, when used in a GenServer
, this function can tell when to
automatically wakeup the process.
def handle_call(request, _from, state) do
state = do_stuff(state, request)
timeout = TimeQueue.GbTrees.timeout(state.time_queue)
{:reply, :ok, state, timeout}
end
By default, timeout/1
and timeout/2
(if called with an integer for the
current time) will return :infinity
if the queue if empty. But you may
pass :hibernate
as the second argument for timeout/2
or timeout/3
to
return :hibernate
instead.
Note that any other atom than :infinity
or :hibernate
will be returned
as-is if as well if the queue is empty.
@spec timestamp(event()) :: pos_integer()
Returns the absolute timestamp a queue event is scheduled for.
iex> tq = TimeQueue.GbTrees.new()
iex> {:ok, _, tq} = TimeQueue.GbTrees.enqueue_abs(tq, 1234, :my_value)
iex> {:ok, event} = TimeQueue.GbTrees.peek_event(tq)
iex> TimeQueue.GbTrees.timestamp(event)
1234
Returns the time reference of a queue event. This reference is used as a key to identify a unique event.
iex> tq = TimeQueue.GbTrees.new()
iex> {:ok, tref, tq} = TimeQueue.GbTrees.enqueue(tq, 10, :my_value)
iex> Process.sleep(10)
iex> {:ok, event} = TimeQueue.GbTrees.peek_event(tq)
iex> tref == TimeQueue.GbTrees.tref(event)
true
Returns the value of a queue event.
iex> tq = TimeQueue.GbTrees.new()
iex> {:ok, _, tq} = TimeQueue.GbTrees.enqueue(tq, 10, :my_value)
iex> Process.sleep(10)
iex> {:ok, event} = TimeQueue.GbTrees.peek_event(tq)
iex> TimeQueue.GbTrees.value(event)
:my_value