Martin Sustrik wrote: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > Hi Alex, > > Couple of comments: > > 1. The subscriber should start with no subscriptions rather that > "subscribe to all" subscription. In the latter case it could be > overloaded by incoming messages before it manages to turn to "all" > subsription off. I was under the impression that currently, entering a topology with no explicit subscriptions at all subscribed to everything; thus I didn't want to break ABI. If that's not the case, then the initial subscription to the empty string can go away, yes - It's not especially core to the protocol. However, it has a benefit in the case of failure to upstream (see below). > 2. The fundamental problem with subscription upstreaming is the case > when there are multiple producers attached to a single consumer. In > such case you can handle slow/stuck producer in two ways: a.) you can > drop subscriptions to that producer b.) you can block adding new > subscripions. Both options have undesirable consequences. The only > good solution I've heard so far was limiting the amount of > subscriptions (e.g. at most 1 subscription) so that the upsreaming > never gets stuck. That, however, prevents upstreaming subscriptions > beyone 1 hop (the device in the middle would have to aggregate the > subscriptions from the downstream and thus exceed the limit). Well, since this is defined as a synchronization protocol (and the user needs to do receive-side filtering anyway), they can continue adding new subscriptions at the API level even if the upstreaming hangs. Similarly, since a separate trie is kept for each upstream, a slow upstream cannot block other upstreams. If you want to avoid backlogging, you could limit the SUBSCRIBE/REJECT/RESET messages in-flight to a fixed value, add another bit to the bitmap for "UNTRIED", and add a scan-for-UNTRIED step to the CONFIRM-received step. In that case, failure-to-upstream-subscriptions simply results in the same behavior as no-sender-side-filtering - and is one of the reasons that the initial "" subscription is valuable, since you still have the "firehose" minus any negative subscriptions that _were_ successfully upstreamed (an efficiency win). It fails safe. It would also force the multi-hop upstreamer to upstream a "" subscription, so that again makes it work - if the aggregating node hits the limit during the sync protocol, it can fail-safe to "", and the protocol "peaks" in the middle and then _declines_ in terms of memory usage as it prunes the non- CANONICAL entries. Since the final "commit" of removing "" occurs after the pruning, any memory allocation failure will occur when a "" subscription is present. However, if a user adds a POSITIVE CANONICAL child for a NEGATIVE SYNCED not-CANONICAL node, and cannot sync it, they'd have to drop and reconnect regardless. > Thoughts? > Martin > > On 20/09/14 01:47, Alex Elsayed wrote: >> This is an attempt to define a general system for upstreaming >> subscriptions on bidirectional transports. All comments welcome and >> deeply appreciated. >> >> Note that all messages from subscribers to producers expect a >> confirmation, and thus when I say that S sends something, it is >> assumed that S will resend the message if a timeout elapses. To >> facilitate this, the effects of repeat messages on producers are >> idempotent. >> >> The subscriber maintains a trie of subscriptions, where each leaf >> carries a bitfield of the following: POSITIVE (when absent, is a >> "negative" or "ignore" subscription) SYNCHRONIZED (Has the upstream >> acknowledged the subscription?) PENDING (...have we asked them?) >> CANONICAL (Is this a subscription by the user, or an internal >> synchronization artifact?) >> >> the subscriber S' trie begins with a single subscription to "", >> which is POSITIVE, SYNCHRONIZED, CANONICAL, and not PENDING. >> >> When the user explicitly subscribes to a topic, the CANONICAL flag >> is cleared from the empty-string subscription. The inserted entry >> for the explicit subscription is POSITIVE and CANONICAL, but >> neither SYNCHRONIZED nor PENDING. >> >> If the empty-string subscription is not present, a SUBSCRIBE >> message is immediately sent upstream, and the PENDING flag _is_ >> set. >> >> On receiving a normal message, S will look up the topic in the >> trie. >> >> If no prefix of the topic is found in the trie, a leaf is created >> for shortest prefix for which there was no entry, with PENDING true >> and all other fields false. The subscriber then sends a REJECT >> message upstream. >> >> Otherwise, over a list of all leaves that are prefixes to the topic >> (root first, end last), the following occurs: >> >> for leaf in list: if leaf is SYNCHRONIZED or PENDING: continue >> else if leaf is CANONICAL and POSITIVE: mark leaf PENDING send >> SUBSCRIBE message upstream break >> >> With this, a natural throttle is placed on the rate of >> subscriptions. >> >> P also keeps a trie, but a much simpler one - the value is a single >> bit, indicating POSITIVE vs NEGATIVE. >> >> On P receiving a REJECT message, a NEGATIVE entry is inserted, and >> on receiving a SUBSCRIBE message, a POSITIVE entry is inserted. >> Then, P sends S a CONFIRM (REJECT|SUBSCRIBE) message as >> appropriate. >> >> On receiving a CONFIRM (REJECT or SUBSCRIBE) message, S: 1.) Marks >> the appropriate node N as SYNCHRONIZED and clears PENDING 2.) Walks >> from the node towards the root until it encounters a node X that is >> not CANONICAL 3.) If all entries in the tree under X either: a.) >> Are SUBSCRIBED or b.) Have a SUBSCRIBED node on the path between >> them and X, then S sets the PENDING flag on X, and sends a RESET >> message upstream for X. >> >> On P receiving a RESET message, it deletes the relevant node from >> its trie, and sends a CONFIRM RESET message to S. >> >> On S receiving a CONFIRM RESET message, it removes the node from >> its trie, and then executes steps 2 and 3 from above. >> >> >> With this, the subscription state of the producer converges on that >> of the subscriber, while restricting the subscription messages to 1 >> per producer message. Negative subscriptions suppress broad >> categories of useless messages, and then are removed once all >> canonical subscriptions have been upstreamed. In the case of an >> unresponsive peer, disconnection is viable, because re-connection >> will not cause a flood of subscription messages. >> >> A subscriber wishing to subscribe to multiple producers would keep >> one trie for each producer, and insert CANONICAL entries into all >> tries. >> >> Adding a producer after tries already exist also works, as one can >> simply walk any of the existing tries and insert the CANONICAL >> nodes into the new trie. >> >> Messages are only passed to the user if they match a POSITIVE, >> CANONICAL entry in the trie. >> >> > > -----BEGIN PGP SIGNATURE----- > Version: GnuPG v1.4.11 (GNU/Linux) > Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ > > iQEcBAEBAgAGBQJUHTbbAAoJENTpVjxCNN9YOrkH/iOiez9Nz5uJCUjemcco0zbI > 3CXQucHxlZ6lHfuuX78YZ+LJJTrwJujO+Nebo2Sm+GeJOfEgbC03u8K6PpA0WRFI > XFPUZM9SYsc7y6bT9+Tbm16aAteVWCW8SSJZqrqqfaATohJrzLvWl/LNCwmO0/EI > 6cw43hjKmMOWGngNDOfZFeqfMrbxDJBLYIZa21ey82sNbo8pVHh6rMIcjuhIsxie > oAMJCy0EypfaClPyQQgPN3QrGZsZe/JdBTMG34COw+NYYBj3LxkYDohRyCCSE6os > eWG0Znigvs/0fGttsmcwsKli2EYW4wH9/1BitWIym/0VuvMcRRQeMxGrGNf9Zgs= > =iBCI > -----END PGP SIGNATURE-----