Skip to content
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

(4/6) Implement proper remove-before-add behavior in P2PDataStorage #3638

Merged
merged 14 commits into from
Nov 26, 2019

Conversation

julianknutsen
Copy link
Contributor

@julianknutsen julianknutsen commented Nov 20, 2019

New commits are at 526aee5

According to the original design doc, removes-before-adds were expected and should have the behavior that a remove with a larger sequence number will block a future add with a lower sequence number.

The idea is that you don't want out of order remove messages to get lost otherwise you may do more work then necessary by adding a stale ProtectedStorageEntry when you could have ignored it entirely. I'm not sure of any existing cases, but this may have been the cause of 'flapping' or 'undeleted' messages as nodes were starting.

I've left the existing behavior w.r.t. broadcasting. Even if this remove() is the first message we have seen for a payload, we don't rebroadcast it to our peers. I'm not exactly sure what we want here, but rebroadcasting, in this case, could help network propagation and we may want to adopt the invariant that ANY state updates caused by a message are worth of rebroadcasting because the same state updates may be relevant to our peers.

Instead of using a subclass that overwrites a value, utilize Guice
to inject the real value of 10000 in the app and let the tests overwrite
it with their own.
Remove unused imports and clean up some access modifiers now that
the final test structure is complete
Previously, this interface was called each time an item was changed. This
required listeners to understand performance implications of multiple
adds or removes in a short time span.

Instead, give each listener the ability to process a list of added or
removed entrys which can help them avoid performance issues.

This patch is just a refactor. Each listener is called once for each
ProtectedStorageEntry. Future patches will change this.
Minor performance overhead for constructing MapEntry and Collections
of one element, but keeps the code cleaner and all removes can still
use the same logic to remove from map, delete from data store, signal
listeners, etc.

The MapEntry type is used instead of Pair since it will require less
operations when this is eventually used in the removeExpiredEntries path.
…batch

All current users still call this one-at-a-time. But, it gives the ability
for the expire code path to remove in a batch.
This will cause HashMapChangedListeners to receive just one onRemoved()
call for the expire work instead of multiple onRemoved() calls for each
item.

This required a bit of updating for the remove validation in tests so
that it correctly compares onRemoved with multiple items.
…ch removes

bisq-network#3143 identified an issue that tempProposals listeners were being
signaled once for each item that was removed during the P2PDataStore
operation that expired old TempProposal objects. Some of the listeners
are very expensive (ProposalListPresentation::updateLists()) which results
in large UI performance issues.

Now that the infrastructure is in place to receive updates from the
P2PDataStore in a batch, the ProposalService can apply all of the removes
received from the P2PDataStore at once. This results in only 1 onChanged()
callback for each listener.

The end result is that updateLists() is only called once and the performance
problems are reduced.

This removes the need for bisq-network#3148 and those interfaces will be removed in
the next patch.
Now that the only user of this interface has been removed, go ahead
and delete it. This is a partial revert of
f5d75c4 that includes the code that was
added into ProposalService that subscribed to the P2PDataStore.
Write a test that shows the incorrect behavior for bisq-network#3629, the hashmap
is rebuilt from disk using the 20-byte key instead of the 32-byte key.
@julianknutsen julianknutsen changed the title Implement proper remove-before-add behavior in P2PDataStorage (4/5) Implement proper remove-before-add behavior in P2PDataStorage Nov 20, 2019
Addresses the first half of bisq-network#3629 by ensuring that the reconstructed
HashMap always has the 32-byte key for each payload.

It turns out, the TempProposalStore persists the ProtectedStorageEntrys
on-disk as a List and doesn't persist the key at all. Then, on
reconstruction, it creates the 20-byte key for its internal map.

The fix is to update the TempProposalStore to use the 32-byte key instead.
This means that all writes, reads, and reconstrution of the TempProposalStore
uses the 32-byte key which matches perfectly with the in-memory map
of the P2PDataStorage that expects 32-byte keys.

Important to note that until all seednodes receive this update, nodes
will continue to have both the 20-byte and 32-byte keys in their HashMap.
Addresses the second half of bisq-network#3629 by using the HashMap, not the
protectedDataStore to generate the known keys in the requestData path.

This won't have any bandwidth reduction until all seednodes have the
update and only have the 32-byte key in their HashMap.

fixes bisq-network#3629
The only user has been migrated to getMap(). Delete it so future
development doesn't have the same 20-byte vs 32-byte key issue.
In order to implement remove-before-add behavior, we need a way to
verify that the SequenceNumberMap was the only item updated.
It is possible to receive a RemoveData or RemoveMailboxData message
before the relevant AddData, but the current code does not handle
it.

This results in internal state updates and signal handler's being called
when an Add is received with a lower sequence number than a previously
seen Remove.

Minor test validation changes to allow tests to specify that only the
SequenceNumberMap should be written during an operation.
@ripcurlx
Copy link
Contributor

I've left the existing behavior w.r.t. broadcasting. Even if this remove() is the first message we have seen for a payload, we don't rebroadcast it to our peers. I'm not exactly sure what we want here, but rebroadcasting, in this case, could help network propagation and we may want to adopt the invariant that ANY state updates caused by a message are worth of rebroadcasting because the same state updates may be relevant to our peers.

@chimp1984 What do you think about that?

Copy link
Contributor

@freimair freimair left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utAck

ad rebroadcasting even if not applicable: I had that feeling for a long time now. We have stale messages in the network. Thought about resending remove messages e.g. 3 times to spread the news even if a couple of clients missed the first one. Pretty much the same for every remove message. Since the seq number is touched, there is no risk of overloading the network.

my opinion: rebroadcast even if we did not yet receive the respective add. revert if something bad happens.

@julianknutsen
Copy link
Contributor Author

julianknutsen commented Nov 22, 2019

I'll just make an additional PR that adds rebroadcasting in the remove-before-add case. It will involve a bit of validation work that will conflict with my patch stack so I won't be able to get it out until tomorrow. A different PR will also allow the approved patches to go in without forcing them back to stale.

Copy link
Contributor

@ripcurlx ripcurlx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK

@julianknutsen julianknutsen changed the title (4/5) Implement proper remove-before-add behavior in P2PDataStorage (4/6) Implement proper remove-before-add behavior in P2PDataStorage Nov 22, 2019
@ripcurlx ripcurlx merged commit 372c26d into bisq-network:master Nov 26, 2019
@julianknutsen julianknutsen deleted the remove-before-add branch November 26, 2019 16:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants