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

feat: async peerstore #182

Merged
merged 3 commits into from
Jan 20, 2022
Merged

Conversation

achingbrain
Copy link
Collaborator

Refactors interfaces and classes used by libp2p-interfaces to use the async peer store from libp2p/js-libp2p#1058

Fixes a memory leak where peer data (multiaddrs, protocols, etc) is never evicted from memory.

BREAKING CHANGE: peerstore methods and pubsub start/stop are now all async

@codecov-commenter
Copy link

codecov-commenter commented Dec 31, 2021

Codecov Report

Merging #182 (a8f5849) into master (38ee6e1) will not change coverage.
The diff coverage is n/a.

❗ Current head a8f5849 differs from pull request most recent head 5c3491c. Consider uploading reports for the commit 5c3491c to get more accurate results
Impacted file tree graph

@@           Coverage Diff           @@
##           master     #182   +/-   ##
=======================================
  Coverage   76.58%   76.58%           
=======================================
  Files           2        2           
  Lines        1905     1905           
  Branches      141      144    +3     
=======================================
  Hits         1459     1459           
  Misses        446      446           
Impacted Files Coverage Δ
test/utils/index.js 87.50% <ø> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 38ee6e1...5c3491c. Read the comment docs.

"libp2p": "^0.35.0",
"libp2p-floodsub": "^0.28.0",
"libp2p-interfaces-compliance-tests": "^2.0.3",
"libp2p": "libp2p/js-libp2p#feat/async-peerstore",
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This will need to be removed after the next libp2p release.

Longer term we need to break the circular dependencies of these components.

Copy link
Collaborator

Choose a reason for hiding this comment

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

We can, this was already done for pubsub as part of libp2p/js-libp2p#857 but we need to do for the other modules. Just opened a PR to remove the dev deps: libp2p/js-libp2p#1107

@dapplion
Copy link
Contributor

Fixes a memory leak where peer data (multiaddrs, protocols, etc) is never evicted from memory.

Where was the leak exactly?

@achingbrain
Copy link
Collaborator Author

Where was the leak exactly?

See the discussion in libp2p/js-libp2p#1058

In brief the peer store has various Maps that we add peer data to when we discover them on the network - multiaddrs, protocols, etc. The leak is that we never evict anything from the Map so it just grows and grows.

The fix is to use the datastore to store and read peer data instead of holding it all in memory.

@achingbrain
Copy link
Collaborator Author

There seem to be quite a few flaky tests here, from what it looks like, the errors are the same as in master & other PRs - @dapplion any ideas?

@dapplion
Copy link
Contributor

dapplion commented Jan 2, 2022

The fix is to use the datastore to store and read peer data instead of holding it all in memory.

So everytime libp2p needs to lookup protocols for a peer it will do a database disk read?

@achingbrain
Copy link
Collaborator Author

It’ll do a datastore read - that datastore could have an in-memory cache which would replicate the previous behaviour but you could add an eviction strategy to stop your nodes eventually falling over.

@dapplion
Copy link
Contributor

dapplion commented Jan 3, 2022

I feel a better solution would be to fix the in-memory cache first instead of moving to a disk database. If those values have to be persisted, the app layer can choose when to do so, for example right before shutting down.

@achingbrain
Copy link
Collaborator Author

This PR enables the fix for the in-memory cache and does not move to a disk database. It allows libp2p to use a datastore which makes the actual storage configurable - it could be in-memory or a database or a combination of both.

At the moment peer store access is synchronous, which means you are stuck with in-memory storage since every storage method that's not in-memory requires async accessors.

You then can't evict peer information as there's no way to retrieve it later from a secondary async storage medium without requiring the calling code to null-guard on every peer store access and go to the secondary storage medium instead. This would add significant complexity to any part of the stack that touches the peer store which is quite a lot of it.

The change here is just to move to async accessors which then lets you configure the datastore as your application requires.

For the next IPFS release this will be an in-memory datastore with a configurable LRU cache that falls back to something that can store larger amounts of data without impacting memory use such as level or IndexedDB while also periodically writing cache data into the store in the same way the current persistent peer store works.

If you want to be able to hold the peer info of every node in the network in memory as we do now, just configure the LRU cache to be something very large. Even then you'll still gain some protection against OOM errors as the LRU cache will have a limit.

@dapplion
Copy link
Contributor

dapplion commented Jan 3, 2022

That sounds good @achingbrain ! Thanks for the thorough explanation 👍

vasco-santos
vasco-santos previously approved these changes Jan 5, 2022
Copy link
Collaborator

@vasco-santos vasco-santos left a comment

Choose a reason for hiding this comment

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

LGTM

"libp2p": "^0.35.0",
"libp2p-floodsub": "^0.28.0",
"libp2p-interfaces-compliance-tests": "^2.0.3",
"libp2p": "libp2p/js-libp2p#feat/async-peerstore",
Copy link
Collaborator

Choose a reason for hiding this comment

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

We can, this was already done for pubsub as part of libp2p/js-libp2p#857 but we need to do for the other modules. Just opened a PR to remove the dev deps: libp2p/js-libp2p#1107

@@ -2,7 +2,9 @@
* These tests were translated from:
* https://github.com/libp2p/go-libp2p-pubsub/blob/master/gossipsub_test.go
*/
const { expect } = require('chai')
const chai = require('chai')
chai.use(require('dirty-chai'))
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: use aegir exported chai instead

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That would be my preference too, but it's not used anywhere else in this module so I did the manual .use to be consistent with the other tests.

@wemeetagain
Copy link
Member

@achingbrain
Copy link
Collaborator Author

@wemeetagain the type error has been resolved, the CI problems are back to the flakiness observed earlier.

Refactors interfaces and classes used by `libp2p-interfaces` to use the async peer store from libp2p/js-libp2p#1058

Fixes a memory leak where peer data (multiaddrs, protocols, etc) is never evicted from memory.

BREAKING CHANGE: peerstore methods and pubsub start/stop are now all async
dapplion
dapplion previously approved these changes Jan 19, 2022
@wemeetagain
Copy link
Member

This PR introduces some subtle difference in timing that results in the tests inconsistently failing.
IMO we need to diagnose the issue/resolve it before merging this

ts/index.ts Outdated Show resolved Hide resolved
@wemeetagain
Copy link
Member

Maybe we can just disable the unreliable tests for now

@wemeetagain wemeetagain merged commit f938782 into ChainSafe:master Jan 20, 2022
achingbrain added a commit to libp2p/js-libp2p-daemon that referenced this pull request Jan 25, 2022
ChainSafe/js-libp2p-gossipsub#182 shipped so
the fork is no longer required.
achingbrain added a commit to libp2p/js-libp2p-daemon that referenced this pull request Jan 25, 2022
ChainSafe/js-libp2p-gossipsub#182 shipped so the fork is no longer required.
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.

5 participants