-
Notifications
You must be signed in to change notification settings - Fork 976
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
kad: Change RecordStore trait interface - add results to methods. #3076
Closed
shamil-gadelshin
wants to merge
1
commit into
libp2p:master
from
shamil-gadelshin:record-store-operation-results
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Can you explain in more detail, what benefits you are expecting to see from this?
Removing an element should be an idempotent operation in my opinion. What failure scenarios would you like to express here?
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 current
RecordStore
implies theMemoryStore
implementation that could be considered infallible which is not the case for most other custom implementations. Custom stores implemented with DB or file layers are always fallible for multiple reasons.Just an example of a possible error for the
remove
operation: "No write permissions for the database file".Also, the
remove
operation is just an example of the wholeRecordStore
API. Specifically, the most problems I have are with therecords
operation. My database returns aResult
for such iterations and I needed to create a special empty iterator with some error logging which is not a good practice IMHO.The original issue contains a similar concern from other users: #3035 (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 understand that DB or file system APIs are fallible. But what is the
NetworkBehaviour
supposed to do with the error? Log it? If there is no reasonable error handling strategy, we might as well not allow the implementation to return one.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.
An implementation of
RecordStore
that interacts with a DB could also just represent aHandle
that sends commands to the actual implementation, similar to how SQL DBs usually write to a journal first before modifying data on disk.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.
That depends on the use case and libp2p implementation (architecture). Some use cases are compatible with the
Result
already, for example,remove_record
fromBehaviour
will return it to the caller. Some with the current code are hard to work with and logging seems the easiest change. I agree, that it will add complexity to the design, however, IMHO it makes the API more idiomatic and reflects a broader set of use cases.I'm not sure I follow here. There are a lot of ways to implement the storage indeed and some will hide the errors.
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.
One important property I’d like to uphold is that NetworkBehaviour is about networking stuff, connection handlers care about handling connections, and other things live outside these abstractions — at least in terms of code module structure. Kademlia might require an implementation of RecordStore in its constructor, and it might use the provided functions from the NetworkBehaviour or from the ConnectionHandler, but the actual RecordStore should live outside these two pieces — also regarding resource usage.
One somewhat similar case is bitswap, where our store also is structured like this, but it has a fully synchronous API and is spawned inside a dedicated thread, with communication over async channels. Failures will need to be bubbled up to the network peer, plus logging (with careful tuning of levels — only things like “disk full” warrant a WARN or ERROR, everything else should stay below INFO, or preferably below DEBUG for per-interaction events).
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 would vote for option 2 (direct integration into the ConnectionHandler). However, it seems like a major change. So, my question is: whether there is any benefit from this PR as the preparation for that refactoring (that unlikely will make it in the nearest working plan)? Otherwise, feel free to reject 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.
Did you mean this one?
rust-libp2p/protocols/kad/src/behaviour.rs
Line 405 in 5b4eab7
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.
Agreed.
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 reason I am challenging it is because we pay a very big price for this separation and the gains are hard to quantify for me:
ConnectionHandler
s andNetworkBehaviour
s, only because we can't access a shared resource directly from the handlers.The interface to
RecordStore
could still look something like this:This would force implementations to use channels or other things to communicate with the centralised store (self receiver is not mutable and future doesn't have a lifetime). Thus, we would still uphold the "share memory by communicating" mantra and the connections themselves would only wait for a channel wake-up but not perform any other work.
At the same time though, this
RecordStore
can be referenced within eachConnectionHandler
, the actual network protocol can be expressed in a few LoC and even adding things like timeouts for retrieving something from the store could be added trivially.