1%% This Source Code Form is subject to the terms of the Mozilla Public 2%% License, v. 2.0. If a copy of the MPL was not distributed with this 3%% file, You can obtain one at https://mozilla.org/MPL/2.0/. 4%% 5%% Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. 6%% 7 8-module(rabbit_router). 9-include_lib("stdlib/include/qlc.hrl"). 10-include_lib("rabbit_common/include/rabbit.hrl"). 11 12-export([match_bindings/2, match_routing_key/2]). 13 14%%---------------------------------------------------------------------------- 15 16-export_type([routing_key/0, match_result/0]). 17 18-type routing_key() :: binary(). 19-type match_result() :: [rabbit_types:binding_destination()]. 20 21%%---------------------------------------------------------------------------- 22 23-spec match_bindings(rabbit_types:binding_source(), 24 fun ((rabbit_types:binding()) -> boolean())) -> 25 match_result(). 26 27match_bindings(SrcName, Match) -> 28 MatchHead = #route{binding = #binding{source = SrcName, 29 _ = '_'}}, 30 Routes = ets:select(rabbit_route, [{MatchHead, [], [['$_']]}]), 31 [Dest || [#route{binding = Binding = #binding{destination = Dest}}] <- 32 Routes, Match(Binding)]. 33 34-spec match_routing_key(rabbit_types:binding_source(), 35 [routing_key()] | ['_']) -> 36 match_result(). 37 38match_routing_key(SrcName, [RoutingKey]) -> 39 find_routes(#route{binding = #binding{source = SrcName, 40 destination = '$1', 41 key = RoutingKey, 42 _ = '_'}}, 43 []); 44match_routing_key(SrcName, [_|_] = RoutingKeys) -> 45 find_routes(#route{binding = #binding{source = SrcName, 46 destination = '$1', 47 key = '$2', 48 _ = '_'}}, 49 [list_to_tuple(['orelse' | [{'=:=', '$2', RKey} || 50 RKey <- RoutingKeys]])]). 51 52%%-------------------------------------------------------------------- 53 54%% Normally we'd call mnesia:dirty_select/2 here, but that is quite 55%% expensive for the same reasons as above, and, additionally, due to 56%% mnesia 'fixing' the table with ets:safe_fixtable/2, which is wholly 57%% unnecessary. According to the ets docs (and the code in erl_db.c), 58%% 'select' is safe anyway ("Functions that internally traverse over a 59%% table, like select and match, will give the same guarantee as 60%% safe_fixtable.") and, furthermore, even the lower level iterators 61%% ('first' and 'next') are safe on ordered_set tables ("Note that for 62%% tables of the ordered_set type, safe_fixtable/2 is not necessary as 63%% calls to first/1 and next/2 will always succeed."), which 64%% rabbit_route is. 65find_routes(MatchHead, Conditions) -> 66 ets:select(rabbit_route, [{MatchHead, Conditions, ['$1']}]). 67