-
Couldn't load subscription status.
- Fork 29
add swip-25: pullsync protocol improvement #66
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: master
Are you sure you want to change the base?
Conversation
|
Adding more context to this; when a peer pullsync with another peer, it will first request chunk addresses from a particular bin and will only then request the actual chunk data for the chunks it does not have locally. This is done for every bin >= storage depth and with every neighbor peer, and this is where the inefficiency comes in. One might argue that because it's only the chunk address request that is replicated by a factor of the size of neighborhood, the inefficiency is somewhat tolerable. Another detail is that only reachable nodes will store the chunk and terminate a pushsync request. Then all peers in the neighborhood, reachable or not, will pullsync the chunk. I wonder how this will play out with the more efficient syncing strategy proposed by the SWIP? I guess since the new strategy only reduces the replicated requests of the same chunk, and not favor efficiency over replication reliability or something like that, it should be ok. |
SWIPs/swip-pullsync.md
Outdated
|
|
||
| ## Specification | ||
| <!--The technical specification should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for the current Swarm platform and future client implementations.--> | ||
| Each peer takes all their neighbours they are allowed to synchronise with (have full node ambitions): p_0, p_1, ..., p_n. For each peer, they decide their uniquness depth, i.e., the PO, within which they are the only peer in the set: `UD_i, UD_1, ... UD_n`. Now for each peer `p_i` we start subscribing to all POs greater or equal to `UD_i`. Note that unlike the earlier algorithm, this one is extremely sensitive to the changing peerset, so every single time there is a change in the neighbours, pullsync stretegy needs to be reevaluated. In addition to `po>=UD_i`, our pivot peer needs to sync the PO corresponding to their PO with the peer in order to get all the chunks that they are closer to than their peer. To sum up, for any pivot peer P: |
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.
for me it is a bit unclear by what rule the peers get their uniqueness depth. maybe, some examples could resolve my issue but from the text it is a bit hard for me to catch it.
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.
"uniquness depth, i.e., the PO, within which they are the only peer in the set"
the depth of your exclusive neighbourhood
SWIPs/swip-pullsync.md
Outdated
|
|
||
| ## Specification | ||
| <!--The technical specification should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for the current Swarm platform and future client implementations.--> | ||
| Each peer takes all their neighbours they are allowed to synchronise with (have full node ambitions): p_0, p_1, ..., p_n. For each peer, they decide their uniquness depth, i.e., the PO, within which they are the only peer in the set: `UD_i, UD_1, ... UD_n`. Now for each peer `p_i` we start subscribing to all POs greater or equal to `UD_i`. Note that unlike the earlier algorithm, this one is extremely sensitive to the changing peerset, so every single time there is a change in the neighbours, pullsync stretegy needs to be reevaluated. In addition to `po>=UD_i`, our pivot peer needs to sync the PO corresponding to their PO with the peer in order to get all the chunks that they are closer to than their peer. To sum up, for any pivot peer P: |
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.
"uniquness depth, i.e., the PO, within which they are the only peer in the set"
the depth of your exclusive neighbourhood
|
|
||
| ## Test Cases | ||
| <!--Test cases for an implementation are mandatory for SWIPs that are affecting changes to data and message formats. Other SWIPs can choose to include links to test cases if applicable.--> | ||
| Thorough testing is neeeded, cos this can produce inconsistencies in the localstore and has major impact for retrievebility. |
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 get this @nugaon
|
i think it is important that we thoroughly consider and explore all possible edge cases especially during network merges and splits and also when this is concurrent with the various configurations of unbalanced neighbourhoods |
|
I just removed original comment but it did not close the whole tab... (I mistakenly proposed the current workflow to ensure certainty in reserve sync.) The rationale could include explanation how this pull sync strategy syncs the whole reserve. You detailed that how respective bin X of peers are distinct from each other, but the subscriptions for those bins do not change from the current workflow. The proposal states that it is enough to additionally sync the PO(p, P) bin at each |
SWIPs/swip-pullsync.md
Outdated
| <!--The rationale fleshes out the specification by describing what motivated the design and why particular design decisions were made. It should describe alternate designs that were considered and related work, e.g. how the feature is supported in other languages. The rationale may also provide evidence of consensus within the community, and should discuss important objections or concerns raised during discussion.--> | ||
|
|
||
| One can see that each chunk is taken from its most immediate neighbourhood only. So depending on to what extent the peer addresses are balanced we save a lot on not taking anything twice. Imagine a peer with neighbourhood depth `d`, and in the hood 3 neighbours each having a different 2 bit prefix within the neighbourhood. Then `UD_i=d+3` for each peer, so we synchronise PO=d+3,d+4,d+5,etc. from each peer. | ||
| this is exactly 16 times less chunks than what we need to syncronise with the current process. Also we need to synchronise PO=d+2 chunks from each peer. |
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 is it 16 times less and is it together with d+2 syncs?
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.
which node will synchronize bin 0 if storageRadius is 0 and the neighbor nodes are 1111, 1100, 1000 and the pivot node is 1101.
| One can see that each chunk is taken from its most immediate neighbourhood only. So depending on to what extent the peer addresses are balanced we save a lot on not taking anything twice. Imagine a peer with neighbourhood depth `d`, and in the hood 3 neighbours each having a different 2 bit prefix within the neighbourhood. Then `UD_i=d+3` for each peer, so we synchronise PO=d+3,d+4,d+5,etc. from each peer. | ||
| this is exactly 16 times less chunks than what we need to syncronise with the current process. Also we need to synchronise PO=d+2 chunks from each peer. | ||
|
|
||
| One potential caveat is that if a peer quits or is no longer contactable before the pivot finished syncing with them, then another peer needs to start the process. |
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 needs recalculating all UDs and maybe add or drop bin subscriptions at each peer in my understanding.
It is a bit vague what process the another peer should start.
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 I meant is that then we would need to start the same sync process with another peer and that will be from the start if the peer is new.
* bin sync with binary tree * compactible node sync * comments
Refine glossary terms related to pull-sync protocol and neighbourhood depth for clarity and precision.
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.
Pull Request Overview
This PR introduces SWIP-25, proposing a more efficient pullsync protocol for synchronizing content between peers in the same neighborhood. The improvement aims to reduce redundant chunk exchanges by having each chunk synchronized from only its closest peer.
Key Changes:
- Introduces a new pullsync strategy using a leaf-compacted binary tree to identify which peer should sync each chunk
- Reduces synchronization overhead from
N*Schunk hashes (where N is neighborhood size and S is reserve size) by eliminating redundant exchanges - Maintains backward compatibility by keeping the subscription request wire protocol unchanged
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ## Motivation | ||
| <!--The motivation is critical for SWIPs that want to change the Swarm protocol. It should clearly explain why the existing protocol specification is inadequate to address the problem that the SWIP solves. SWIP submissions without sufficient motivation may be rejected outright.--> | ||
| Imagine, that a naive peer joins a neighbourhood, then they will 'subscribe to' each | ||
| depth of their peers within the neighbourhood. As they are receiving new chunks of course these are offering it too back to the peer they got it from. Plus they try to synchronise from each peer the entire reserve, not just part, which means a naive node's synchronisation involves exchange of `N*S` chunk hashrd where N is the neighbourhood size and S is the size of the reserve. This is hugely inefficient. |
Copilot
AI
Oct 27, 2025
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.
Corrected spelling of 'hashrd' to 'hashes'.
| depth of their peers within the neighbourhood. As they are receiving new chunks of course these are offering it too back to the peer they got it from. Plus they try to synchronise from each peer the entire reserve, not just part, which means a naive node's synchronisation involves exchange of `N*S` chunk hashrd where N is the neighbourhood size and S is the size of the reserve. This is hugely inefficient. | |
| depth of their peers within the neighbourhood. As they are receiving new chunks of course these are offering it too back to the peer they got it from. Plus they try to synchronise from each peer the entire reserve, not just part, which means a naive node's synchronisation involves exchange of `N*S` chunk hashes where N is the neighbourhood size and S is the size of the reserve. This is hugely inefficient. |
| All chunks need to be syncronized only once. | ||
| How about we syncronize each chunks from its closest peer among the neighborhood peers. |
Copilot
AI
Oct 27, 2025
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.
Corrected spelling of 'syncronized' to 'synchronized' and 'syncronize' to 'synchronize'.
| All chunks need to be syncronized only once. | |
| How about we syncronize each chunks from its closest peer among the neighborhood peers. | |
| All chunks need to be synchronized only once. | |
| How about we synchronize each chunk from its closest peer among the neighborhood peers. |
|
|
||
| If all the peers we synced from are finished, the respective nodes reserve for any depth equal or higher to storage radius will be the same. | ||
|
|
||
| Unlike the earlier algorithm, this one is extremely sensitive to the changing peerset, so every single time there is a change in the neighbours, pullsync stretegy needs to be reevaluated. |
Copilot
AI
Oct 27, 2025
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.
Corrected spelling of 'stretegy' to 'strategy'.
| Unlike the earlier algorithm, this one is extremely sensitive to the changing peerset, so every single time there is a change in the neighbours, pullsync stretegy needs to be reevaluated. | |
| Unlike the earlier algorithm, this one is extremely sensitive to the changing peerset, so every single time there is a change in the neighbours, pullsync strategy needs to be reevaluated. |
|
|
||
| ## Test Cases | ||
| <!--Test cases for an implementation are mandatory for SWIPs that are affecting changes to data and message formats. Other SWIPs can choose to include links to test cases if applicable.--> | ||
| Thorough testing is neeeded, cos this can produce inconsistencies in the localstore and has major impact for retrievebility. |
Copilot
AI
Oct 27, 2025
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.
Corrected spelling of 'neeeded' to 'needed' and 'retrievebility' to 'retrievability'. Additionally, 'cos' should be 'because' in formal documentation.
| Thorough testing is neeeded, cos this can produce inconsistencies in the localstore and has major impact for retrievebility. | |
| Thorough testing is needed, because this can produce inconsistencies in the localstore and has major impact for retrievability. |
| Each compactible node (i.e. that has one child) is the indication that all the chunks on the missing branch has no single closest peer and are equidistant from two or more peers on the existing branch. | ||
|
|
||
| Ideally To sync all the chunks we need to cover all the branches of the trie: | ||
| - all chunks of leaf nodes must be syncronized from its stored peer. |
Copilot
AI
Oct 27, 2025
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.
Corrected spelling of 'syncronized' to 'synchronized'.
| - all chunks of leaf nodes must be syncronized from its stored peer. | |
| - all chunks of leaf nodes must be synchronized from its stored peer. |
| - as secondary ordering within a bin is based on first time of storage. | ||
| - the chronology makes it possible to have live (during session) and historical syncing. | ||
|
|
||
| ## Copyright/ |
Copilot
AI
Oct 27, 2025
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.
Remove trailing slash from 'Copyright/' header.
| ## Copyright/ | |
| ## Copyright |
Submitted a preliminary SWIP for pullsync changes