-
Notifications
You must be signed in to change notification settings - Fork 41
RFC: Generic Filters for Subscriptions and FETCH #1164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Based on proposal in #1068 One thing that is strange is allowing Group ID filters here, since these overlap with the built-in filters in Subscribe and Fetch. This may be what Victor was suggesting in Stockholm. The pathological case of this encoding is for every other object, which would double the length of the Values array. We could fix it by shifting the start value left by one and using the LSB to indicate single vs range, but it seemed like overkill.
| #### OBJECT FILTER Parameter | ||
|
|
||
| The OBJECT_FILTER parameter(Parameter Type 0x05) MAY appear in SUBSCRIBE, | ||
| SUBSCRIBE_UPDATE, PUBLISH_OK, TRACK_STATUS or FETCH message. It is a structure |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about adding this to SubscribeNamespace as well ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's unclear what adding a filter to SUBSCRIBE_NAMESPACE would do without #1047? Or you have different use cases in mind? Let's keep this focused on subscriptions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
adding it to namespace will enable object filtering across the tracks, where the base case is a single subscription . I was suggesting it would be nice to think the filter more generically
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@suhasHere I am amenable to using the same parameter to filter Tracks in response to SUBSCRIBE_NAMESPACE rather than Objects in SUBSCRIBE, but it requires more semantics (for example, most operands defined here don't make any sense). Can you file an issue explaining the requirements for Track filtering first?
draft-ietf-moq-transport.md
Outdated
| Object Filter { | ||
| Type (0x5), | ||
| Length (i), | ||
| Operand and Flag (i), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| Operand and Flag (i), | |
| Operand and Operator (i), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where Operator can be one !-, =, >, < . I think this will cover a good set of use-cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of those can be express via range filters + negation:
= -> Equal
!= -> Negate + Equal
> -> Range with no end
< -> Negate + Range with no end
It's also unclear what < > mean with multiple ranges.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realized < X is also trivially implemented as a range from [0,X]
fluffy
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can see how this might make sense for fetch but it seems to really complicate subscribe and I don't see the use cases it solves. To be specific, I can not imagine a subscriber where I want groups 100 to 200, then skip group 201 to 299, then give me groups 300 to 400.
This is a fairly significant breaking change and I think we should talk more about what we are trying to fix before getting into this. I do see some value in writing down a more generic and normalize filter that provides more capabilities as long as it does not complicate things so we may end up at exactly this but I'd like to consider the goals more fist.
draft-ietf-moq-transport.md
Outdated
| Operand No Filter. | ||
|
|
||
| This parameter MAY appear more than once, and filters are cumulative. When | ||
| filters are applied, delivery rules regarding Subgroups and FETCH responses are |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't want to deal with an unlimited number of filters operations. How about a max of 4 unless someone can come up with a very good use case for more. Keep in mind I would like to be able to implement this on something like a FPGA or silicon for wire speed filtering.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A max seems very sensible.
draft-ietf-moq-transport.md
Outdated
| filters are applied, delivery rules regarding Subgroups and FETCH responses are | ||
| modified. Within a Subgroup, the Publisher is allowed to send an Object on a | ||
| Subgroup stream even when it is not the next Object if the expected Objects | ||
| did not pass the filter. In a FETCH response, the Subscriber can only infer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might be reading what you are saying here wrong but ...
If you mean you can send stuff that does not pass the filter, then no, I don't think this should be allowed. I think the stream should be ended if this happens on reliable stream and the things should just be filtered if on datagram.
If you mean that if the filter remove object N but object N+1 is the subgroup passes the filter, you can send N+1 even though N is missing ... then I need to think about what this does to caches downstream.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not saying you should send stuff that doesn't pass the filter. I was thinking the latter. For example f you have a subgroup with objects 0-9, and a filter that says only even objects, then you can put [ 0, 2, 4, 5, 8 ] in a single stream, even though you know you are omitting objects.
That said, I think maybe that is a really bad idea, and we should just use the normal logic and the publisher has to reset the stream and open a new one wherever it skips.
afrind
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can see how this might make sense for fetch but it seems to really complicate subscribe and I don't see the use cases it solves. To be specific, I can not imagine a subscriber where I want groups 100 to 200, then skip group 201 to 299, then give me groups 300 to 400.
See the linked issue (and also #441) where @wilaw lists out some use cases. You may be right about having a list of allowed ranges though.
This is a fairly significant breaking change and I think we should talk more about what we are trying to fix before getting into this. I do see some value in writing down a more generic and normalize filter that provides more capabilities as long as it does not complicate things so we may end up at exactly this but I'd like to consider the goals more fist.
Completely agree we need to spend time discussing this before moving forward (note "RFC" in PR title). I wrote this to help kickstart the discussion, and because it's among the biggest "API level" changes remaining, which the chairs have asked us to prioritize.
draft-ietf-moq-transport.md
Outdated
| Object Filter { | ||
| Type (0x5), | ||
| Length (i), | ||
| Operand and Flag (i), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realized < X is also trivially implemented as a range from [0,X]
draft-ietf-moq-transport.md
Outdated
| Operand No Filter. | ||
|
|
||
| This parameter MAY appear more than once, and filters are cumulative. When | ||
| filters are applied, delivery rules regarding Subgroups and FETCH responses are |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A max seems very sensible.
draft-ietf-moq-transport.md
Outdated
| filters are applied, delivery rules regarding Subgroups and FETCH responses are | ||
| modified. Within a Subgroup, the Publisher is allowed to send an Object on a | ||
| Subgroup stream even when it is not the next Object if the expected Objects | ||
| did not pass the filter. In a FETCH response, the Subscriber can only infer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not saying you should send stuff that doesn't pass the filter. I was thinking the latter. For example f you have a subgroup with objects 0-9, and a filter that says only even objects, then you can put [ 0, 2, 4, 5, 8 ] in a single stream, even though you know you are omitting objects.
That said, I think maybe that is a really bad idea, and we should just use the normal logic and the publisher has to reset the stream and open a new one wherever it skips.
Sparse non-contiguous ranges are really a filter use-case for FETCH. Since we want a common filter parameter between FETCH and SUBSCRIBE, these just won't be used much in SUBSCRIBE, but will be used with FETCH. For SUBSCRIBE, the use-cases for filters outside of Sparse non-contiguous ranges are quite real and some examples are described below. Additionally, when combined with extensions, we get some very nice behaviors.
|
wilaw
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for implementing this Alan!
My main feedback is about making the length of the match inclusive rather than exclusive. When dealing with GroupIDs etc it doesn't matter much, but when we get into use-cases where the values represent real-world discrete things (like ZIP codes, device IDs, temperatures, serial numbers etc), then specifying the inclusive end of the range seems better than one more than that.
draft-ietf-moq-transport.md
Outdated
| Values is an array of integers which encode the values of interest. The | ||
| remainder of the array is a sequence of pairs indicating the start and length of | ||
| the matching range. The Start is encoded as a delta from the previous End, or |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The remainder of the array is a sequence of pairs indicating the start and length of
the matching range
Saying that the second value indicates the length of the matching range is contradictory to the examples, as it suggests the length within which samples will match. For example a start of 10 and a length of 3 indicates that the matching range is from 10..13 , whereas it is intended to be 10..12.
I think explicitly defining the matching range is more intuitive for users than specifying a non-inclusive final value. For example, if I am filtering on zip code data, and I want 94552, i have to set the filter length to point at the imaginary 94553, which is not a valid zip code.
So suggestion is modify the definition so that the length is an inclusive match. This changes the example given later and also relaxes the requirement around which values can be zero. To specify matches for 10, 11, 12, 14 and 34-max we would code [10, 2, 2, 0, 20]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
API and wire format don't need to be the same. I figured most APIs would take in a list of absolute ranges and run through an encoder which produce the values on the wire -- especially since subsequent range offsets are delta encoded. It's also a little strange to say it's a sequence of [Delta, Length-1] pairs, though it does buy one more value for one byte encodings by giving a meaning to 0 length.
draft-ietf-moq-transport.md
Outdated
| Values is an array of integers which encode the values of interest. The | ||
| remainder of the array is a sequence of pairs indicating the start and length of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does "the remainder" here mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a previous version had the first element optionally be the extension Id, but it was pulled out
| from 0 for the first element. The length indicates the number of elements | ||
| including Start to match. An odd number of elements indicates the final range |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we specify the length field to indicate the number of elements minus 1, then the same number of bits can represent more elements, i.e., the capability or bit efficiency is slightly improved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It only saves one value though at the expense of some readability?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Just a suggestion for consideration. In some other standards this is always done.
Co-authored-by: Ye-Kui Wang <[email protected]>
|
Parking pending Design Team input |
|
In the Toronto interim, it was decided to setup a design team for object/track filters (PR#1164, I#441, 1068, 1206). Mo, Martin, Suhas, Victor, Will, YK volunteered. Please let me know if you want to join these meetings. Next meeting is Friday October 10 at 9:00am PDT.
|
|
Oct 10, 2025 design meeting with Mo, Suhas, Victor, Will, YK. Parameters in Subscribe, Subscribe_Update, Fetch, Publish_Ok: Parameter in Subscribe_Namespace: Setup Parameters: Track Selection Details
Consider in later PR: Remove SUBSCRIPTION_FILTER parameter? Need another way to say Next Group. |
|
@mzanaty Thanks for the update.
Does that mean evicted tracks also get PUBLISH_DONE to keep the total number of subscriptions under this SUBSCRIBE_NAMESPACE=MaxTracksSelected? I'd prefer that because it keeps the subscription state machine the same. If you don't do this, you will leak subscriptions causing excessive state, and, with current mechanisms, likely run out of request IDs.
I'd prefer that the draft have only one group filter mechanism at a time, so if you want to replace SUBSCRIPTION_FILTER, wait to add |
This will be challenging. since this a dynamic selection and track can be selected at different points in time. Those tracks are all active , sending publish_done is incorrect here. |
What if MaxSelected is 5 and there are 1000 tracks, but every track has a moment where it's selector is in the top 5. Then I end up with 1000 subscriptions. Is that the intent? |
|
Oct 17, 2025 design meeting with Martin, Mo, Suhas, Victor, YK. Decided to defer details for Fetch and removing Subscription Filter until core design is done. Decided to put all Start/End ranges of a single filter type in a single parameter. Discussed but rejected putting all filter types in a single super parameter. Subscribe_Update always replaces all ranges of a given filter type, or removes the filter if no ranges (Length=0), which eliminated the "No Filter" type. Parameters in Subscribe, Subscribe_Update, Publish_Ok: (defer Fetch details) End is optional in the last range, meaning no End if omitted. For the Extension Filter, also allow End=0 to mean no End when Start>0, to allow different Extension IDs to have no End. Need to clarify how filters (specifically Object or Extension Filters) can cause object gaps in subgroup streams, and how FIN is handled. No changes to the Track Selection Filter. It remains as below. Parameter in Subscribe_Namespace: Discussed whether deselected tracks get signaled in control messages like Publish Done. That results in extra control messages and subscription state churn if deselcted tracks later get reselected. However, many deselected tracks can pollute subscription state, so it may be good to allow publishers to purge state for many old deselected tracks. Need more discussion if "many old" can be left to implementations or we need to specify guidance. |
For your next meeting can you discuss the interaction with SUBSCRIPTION_FILTER, or if you are replacing it entirely?
See #1295. I think the answer is along those lines -- if you omit an object from a subgroup, you MUST reset the stream.
We definitely need some guidance, even if the algorithm to close deselected subscriptions is implementation specific. Eventually you can run out of request IDs. |
|
The final design intends to replace SUBSCRIPTION_FILTER entirely. But there are details (such as Next Group) that the team wants to defer until the core design aspects are finalized first. |
Based on proposal in #1068
Fixes: #441
One thing that is strange is allowing Group ID filters here, since these overlap with the built-in filters in Subscribe and Fetch. This may be what Victor was suggesting in Stockholm.
The pathological case of this encoding is for every other object, which would double the length of the Values array. We could fix it by shifting the start value left by one and using the LSB to indicate single vs range, but it seemed like overkill.