diff options
author | Anders Svensson <[email protected]> | 2015-07-07 13:34:57 +0200 |
---|---|---|
committer | Anders Svensson <[email protected]> | 2015-08-04 17:40:24 +0200 |
commit | 9ab5d8afedc6d2f56997276e3f016ec1c6dac6a5 (patch) | |
tree | d9a84cd1e37a257ccade39040f008737cd49ce01 /lib/diameter/include | |
parent | 16aaa29b7ce40596520d563b6f4a8e0aeba7b085 (diff) | |
download | otp-9ab5d8afedc6d2f56997276e3f016ec1c6dac6a5.tar.gz otp-9ab5d8afedc6d2f56997276e3f016ec1c6dac6a5.tar.bz2 otp-9ab5d8afedc6d2f56997276e3f016ec1c6dac6a5.zip |
Don't compute AVP list length unnecessarily at AVP decode
This has had a hugely negative impact on performance when decoding
messages containing many AVP: each decode of an AVP having variable
arity computed the length of the list of previously decoded AVPs when
checking that the allowed arity was not exceeded, even if the allowed
arity was infinite, making for O(n^2) cost. Here are some execution
times, for diameter_codec:decode/2 on a representative message with n
integer AVPs in the Common application (on the host at hand):
Before After
------- ---------
n = 1K 5 ms 2 ms
n = 10K 500 ms 25 ms
n = 100K 75 sec 225 ms
n = 1M 2.6 sec
Note the nearly linear increase following the change.
Remove the dire documentation warning for incoming_maxlen as a
consequence. It can still be useful to set, but not doing so won't have
the same consequences as previously.
Diffstat (limited to 'lib/diameter/include')
-rw-r--r-- | lib/diameter/include/diameter_gen.hrl | 32 |
1 files changed, 22 insertions, 10 deletions
diff --git a/lib/diameter/include/diameter_gen.hrl b/lib/diameter/include/diameter_gen.hrl index 79b8e6ecde..ebe9e6363d 100644 --- a/lib/diameter/include/diameter_gen.hrl +++ b/lib/diameter/include/diameter_gen.hrl @@ -210,18 +210,27 @@ missing(Rec, Name, Failed) -> sets:new(), Failed), [{5005, A} || F <- '#info-'(element(1, Rec), fields), - not have_arity(avp_arity(Name, F), '#get-'(F, Rec)), + not has_arity(avp_arity(Name, F), '#get-'(F, Rec)), #diameter_avp{code = C, vendor_id = V} = A <- [empty_avp(F)], not sets:is_element({C,V}, Avps)]. %% Maximum arities have already been checked in building the record. -have_arity({Min, _}, L) -> - Min =< length(L); -have_arity(N, V) -> +has_arity({Min, _}, L) -> + has_prefix(Min, L); +has_arity(N, V) -> N /= 1 orelse V /= undefined. +%% Compare a non-negative integer and the length of a list without +%% computing the length. +has_prefix(0, _) -> + true; +has_prefix(_, []) -> + false; +has_prefix(N, L) -> + has_prefix(N-1, tl(L)). + %% empty_avp/1 empty_avp(Name) -> @@ -589,14 +598,17 @@ pack(undefined, 1, FieldName, Avp, Acc) -> %% AVP MUST be included and contain a copy of the first instance of %% the offending AVP that exceeded the maximum number of occurrences %% + pack(_, 1, _, Avp, {Rec, Failed}) -> {Rec, [{5009, Avp} | Failed]}; -pack(L, {_, Max}, _, Avp, {Rec, Failed}) - when length(L) == Max -> - {Rec, [{5009, Avp} | Failed]}; - -pack(L, _, FieldName, Avp, Acc) -> - p(FieldName, fun(V) -> [V|L] end, Avp, Acc). +pack(L, {_, Max}, FieldName, Avp, Acc) -> + case '*' /= Max andalso has_prefix(Max, L) of + true -> + {Rec, Failed} = Acc, + {Rec, [{5009, Avp} | Failed]}; + false -> + p(FieldName, fun(V) -> [V|L] end, Avp, Acc) + end. %% p/4 |