@@ -23,7 +23,7 @@ defmodule Tidefall.Queue do
2323 | | |
2424 v v v
2525 +-------+ +-------+ +-------+ ETS :ordered_set
26- | P 0 | | P 1 | | P N-1 | Key: {monotonic_time , ref}
26+ | P 0 | | P 1 | | P N-1 | Key: {sort_key , ref}
2727 +-------+ +-------+ +-------+ Val: item
2828 | | |
2929 v v v
@@ -34,17 +34,20 @@ defmodule Tidefall.Queue do
3434 ```
3535
3636 Items are routed to partitions via `phash2`, stored in
37- `:ordered_set` ETS tables keyed by `{monotonic_time, ref}`
38- (ensuring insertion-time ordering with uniqueness), and
39- periodically flushed to the processor in batches.
37+ `:ordered_set` ETS tables keyed by `{sort_key, ref}`, and
38+ periodically flushed to the processor in batches. `sort_key`
39+ is `System.monotonic_time()` by default — giving insertion-time
40+ order — or the term produced by the `:sort_key` runtime option;
41+ `ref` keeps every key unique so no item is ever overwritten.
42+ Ordering is **per partition** (see `:sort_key` under runtime options).
4043
4144 ## Start options
4245
4346 #{ Tidefall.Buffer.Options . start_options_docs ( ) }
4447
4548 ## Runtime options
4649
47- #{ Tidefall.Buffer .Options . runtime_options_docs ( ) }
50+ #{ Tidefall.Queue .Options . runtime_options_docs ( ) }
4851
4952 ## Examples
5053
@@ -112,13 +115,18 @@ defmodule Tidefall.Queue do
112115 import Record , only: [ defrecordp: 2 ]
113116
114117 alias Tidefall.Buffer
115- alias Tidefall.Buffer . { Definition , Options , Partition }
116-
117- # Queue-specific key record (ordered by insertion time).
118- # The `timestamp` ensures order by insertion time (asc) while the
119- # `ref` makes each entry unique since there may be multiple entries
120- # with the same timestamp.
121- defrecordp ( :key , timestamp: nil , ref: nil )
118+ alias Tidefall.Buffer . { Definition , Partition }
119+ alias Tidefall.Queue.Options
120+
121+ # Queue-specific key record.
122+ #
123+ # `sort_key` is the primary ordering term — `System.monotonic_time()`
124+ # by default (insertion order), or whatever the `:sort_key` runtime
125+ # option resolves to. `ref` is always retained as the uniqueness
126+ # tiebreaker: since `make_ref()` is unique, distinct items never
127+ # collide in the `:ordered_set`, so nothing is overwritten even when
128+ # two items share the same `sort_key`.
129+ defrecordp ( :key , sort_key: nil , ref: nil )
122130
123131 # Entry record stored in ETS. Queue only needs key/value; the
124132 # match spec returns just the value to the processor.
@@ -223,20 +231,24 @@ defmodule Tidefall.Queue do
223231 # Custom partition routing with fixed key (all items to same partition)
224232 push(:my_buffer, log_entry, partition_key: :logs)
225233
234+ # Custom ordering: drain by a value-derived sort key (per partition)
235+ push(:my_buffer, event, sort_key: & &1.priority)
236+
226237 """
227238 @ spec push ( buffer ( ) , item ( ) | [ item ( ) ] , keyword ( ) ) :: :ok
228239 def push ( buffer , item_or_batch , opts \\ [ ] )
229240
230241 def push ( buffer , batch , opts ) when is_list ( batch ) do
231242 opts = Options . validate_runtime_options! ( opts )
232243 partition_key = Keyword . fetch! ( opts , :partition_key )
244+ sort_key = Keyword . get ( opts , :sort_key )
233245
234246 batch
235247 |> Enum . group_by ( & Buffer . get_partition ( buffer , partition_key , & 1 ) )
236248 |> Enum . each ( fn { partition , items } ->
237249 partition
238250 |> Partition . current_table ( )
239- |> :ets . insert ( Enum . map ( items , & new_entry ( build_key ( ) , & 1 ) ) )
251+ |> :ets . insert ( Enum . map ( items , & new_entry ( build_key ( sort_key , & 1 ) , & 1 ) ) )
240252 end )
241253 end
242254
@@ -300,9 +312,22 @@ defmodule Tidefall.Queue do
300312 ## Private functions
301313
302314 # Iniline common instructions
303- @ compile [ inline: [ build_key: 0 , new_entry: 2 ] ]
315+ @ compile inline: [ new_entry: 2 ]
316+
317+ # Default (no `:sort_key`): order by insertion time.
318+ defp build_key ( nil , _item ) do
319+ key ( sort_key: System . monotonic_time ( ) , ref: make_ref ( ) )
320+ end
304321
305- defp build_key , do: key ( timestamp: System . monotonic_time ( ) , ref: make_ref ( ) )
322+ # Arity-1: derive the sort term from the item.
323+ defp build_key ( fun , item ) when is_function ( fun , 1 ) do
324+ key ( sort_key: fun . ( item ) , ref: make_ref ( ) )
325+ end
326+
327+ # Arity-0: generate the sort term at push time.
328+ defp build_key ( fun , _item ) when is_function ( fun , 0 ) do
329+ key ( sort_key: fun . ( ) , ref: make_ref ( ) )
330+ end
306331
307332 defp new_entry ( key , value ) , do: entry ( key: key , value: value )
308333end
0 commit comments