-
Notifications
You must be signed in to change notification settings - Fork 424
Add utils to persist scorer in BackgroundProcessor #1416
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
Conversation
lightning-persister/src/lib.rs
Outdated
| Ok(()) | ||
| } | ||
| } | ||
|
|
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.
This is a placeholder implementation I borrowed from combining ideas from the sample and #1404. I will change it after that PR is merged.
I reckon it is probably best to use utils::write_to_file, but that currently requires D to be DiskWriteable, which may conflict with our new trait WriteableScore. Any advice?
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.
You can implement DiskWriteable for any WriteableScore to fix it. DiskWriteable is also removed in #1417 so you can also wait for that to go in first (but I'll let you and @johncantrell97 figure out which order y'all want to land these).
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.
yeah I think you'll want to use utils::write_to_file for this. in my PR I have removed DiskWriteable and updated write_to_file to operate on any object that implements Writeable.
you'll also just need to implement persist_scorer on the blanket implementation of Persister using the new KVStorePersister trait. this just means making sure the scorer is Writeable. at that point it will automatically be implemented using write_to_file for FilesystemPersister.
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.
@johncantrell97 got it, thanks for clarifying!
Codecov Report
@@ Coverage Diff @@
## main #1416 +/- ##
==========================================
+ Coverage 90.88% 91.87% +0.99%
==========================================
Files 75 75
Lines 41517 47909 +6392
Branches 41517 47909 +6392
==========================================
+ Hits 37734 44018 +6284
- Misses 3783 3891 +108
Continue to review full report at Codecov.
|
TheBlueMatt
left a 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.
Thanks! Sorry for the review delay - been travelling for Bitcoin Miami.
| // Persist Scorer on exit | ||
| persister.persist_scorer(&scorer)?; | ||
|
|
||
| Ok(()) |
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.
| // Persist Scorer on exit | |
| persister.persist_scorer(&scorer)?; | |
| Ok(()) | |
| // Persist Scorer on exit | |
| persister.persist_scorer(&scorer)?; | |
| Ok(()) |
Why the failure is ignored and reported Ok() any way? not able to catch this, sorry
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.
good question. I put this in in #1376 because in the past we always persist channel_manager last and will just simply return the Result from that block.
However, since we added NetworkGraph and Scorer persistence, they run depending on whether or not we can get them from net_graph_msg_handler or scorer. The compiler does not know ahead of time what will exactly run, so it complains if I do not have an Ok(()) there. In other words, Ok() does not run on failure, it just runs once it finishes attempting to persist the channel manager, scorer, and networkgraph, ignoring errors along the way.
Open to any suggestions to improve this, though!
lightning/src/routing/scoring.rs
Outdated
| /// use the Persister to persist it. | ||
| pub trait WriteableScore<'a>: LockableScore<'a> { | ||
| /// Locks the LockableScore and writes it to disk | ||
| fn write<W: Writer>(&'a self, writer: &mut W) -> Result<(), io::Error>; |
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.
Hmm, why not just make WriteableScore extend Writeable instead of having a new write function?
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.
hm, I just assumed from the sample app that we wanted to make sure that the scorer is lockable so we can do .lock().write(). If WriteableScore were to just only extend Writeable, we won't be able to lock it before writing 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.
Sure, but the write implementation of the LockableScore will presumably do the locking internally, which is also totally fine.
lightning-persister/src/lib.rs
Outdated
| Ok(()) | ||
| } | ||
| } | ||
|
|
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.
You can implement DiskWriteable for any WriteableScore to fix it. DiskWriteable is also removed in #1417 so you can also wait for that to go in first (but I'll let you and @johncantrell97 figure out which order y'all want to land these).
|
sounds good, thanks for your review. @johncantrell97 it looks like you have some good stuff in that PR so I'll let you merge that in first and build scorer persistence around your changes! |
|
Needs rebase now that #1417 has landed. |
5001146 to
76619e6
Compare
TheBlueMatt
left a 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.
Nice! Thanks. Some relatively minor nits and minor comments.
lightning/src/routing/scoring.rs
Outdated
| impl<'a, U: Writeable, T: LockableScore<'a>> WriteableScore<'a> for T | ||
| where T::Locked: DerefMut<Target=U> | ||
| { | ||
| fn write<W: Writer>(&'a self, writer: &mut W) -> Result<(), io::Error> { |
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.
nit: tabs not spaces.
lightning/src/routing/scoring.rs
Outdated
| /// use the Persister to persist it. | ||
| pub trait WriteableScore<'a>: LockableScore<'a> { | ||
| /// Locks the LockableScore and writes it to disk | ||
| fn write<W: Writer>(&'a self, writer: &mut W) -> Result<(), io::Error>; |
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.
Sure, but the write implementation of the LockableScore will presumably do the locking internally, which is also totally fine.
lightning/src/routing/scoring.rs
Outdated
| /// | ||
| /// We need this trait to be able to pass in a scorer to `lightning-background-processor` that will enable us to | ||
| /// use the Persister to persist it. | ||
| pub trait WriteableScore<'a>: LockableScore<'a> { |
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.
Nice, I think with this we can simplify some of the bindings changes we've been maintaining on previous versions. Don't need to bother with it here but I'll take a look as a followup after we land this.
| } | ||
|
|
||
| // Persist Scorer on exit | ||
| if let Some(ref scorer) = scorer { |
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.
nit: lets do this before the network graph.
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.
Would it be worth doing the same in the loop?
| } | ||
|
|
||
| fn with_scorer_error(self, error: std::io::ErrorKind, message: &'static str) -> Self { | ||
| Self { scorer_error: Some((error, message)), ..self } |
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 looks like the scorer_error isn't used - need to update the persist method below.
lightning/src/util/persist.rs
Outdated
|
|
||
| /// Persist the given [`WriteableScore`] to disk, returning an error if persistence failed. | ||
| fn persist_scorer(&self, scorer: &'a S) -> Result<(), io::Error> { | ||
| self.persist("scorer", scorer) |
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.
Lets mention the key used here in the docs, sadly that's currently part of the public API ;/.
bafd8f8 to
6097f18
Compare
lightning/src/routing/scoring.rs
Outdated
| where T: LockableScore<'a> + Writeable | ||
| {} | ||
|
|
||
| impl<'a, T> LockableScore<'a> for Arc<T> |
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.
This can be blanket, no? Instead of implementing it only for Arc we can implement it for any Deref<T> where T: LockableScore and T::Locked: Writeable.
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.
touché, not sure why I didn't think of that
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.
@TheBlueMatt I tried implementing a blanket using what you suggested:
impl<'a, T, S> LockableScore<'a> for S
where S: Deref<Target = T>,
T: LockableScore<'a>,
T::Locked: Writeable {
type Locked = T::Locked;
fn lock(&'a self) -> Self::Locked {
self.deref().lock()
}
}
but it looks like it may be too generic as it conflicts with our implementation of LockableScore<'a> for Mutex and RefCell a couple of lines below. thoughts?
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.
Ah, yea, lets not go that way - instead lets just make the WriteableScore we pass to the BackgroundProcessor actually a Deref<WriteableScore>, then we can drop both of the Arc implementations. You'll need to have two bounds - one for the WriteableScore and one for the Deref as you'll want to re-use the WriteableScore bound on the `Persister.
6097f18 to
f43c10b
Compare
TheBlueMatt
left a 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.
Two comments left, then I'm happy :)
TheBlueMatt
left a 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.
LGTM! Can you rebase and clean up the git history here a bit? You can make it one commit if you really want, but either way lets not clean up previous commits in later ones.
52cb1b8 to
199f46d
Compare
|
@TheBlueMatt fixed and squashed.
I didn't know what you meant by this, but all the commits look like they are squashable so I did it anyways. |
Right, I just meant that you had a commit that added some code (eg the macro), and then a later commit that removed that code. |
jkczyz
left a 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.
Looks good! Mostly just some trivial clean-ups / nits.
lightning/src/util/persist.rs
Outdated
| K::Target: 'static + KeysInterface<Signer = Signer>, | ||
| F::Target: 'static + FeeEstimator, | ||
| L::Target: 'static + Logger, | ||
| S: WriteableScore<'a> |
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.
nit: add trailing comma
lightning/src/util/persist.rs
Outdated
| K::Target: 'static + KeysInterface<Signer = Signer>, | ||
| F::Target: 'static + FeeEstimator, | ||
| L::Target: 'static + Logger, | ||
| S: WriteableScore<'a> |
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.
nit: add trailing comma
lightning/src/routing/scoring.rs
Outdated
| impl<'a, T> WriteableScore<'a> for T | ||
| where T: LockableScore<'a> + Writeable | ||
| {} |
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.
This can fit on one line within a 100 characters, which is our aspirational line length limit. 🙂
| UMH: 'static + Deref + Send + Sync, | ||
| PM: 'static + Deref<Target = PeerManager<Descriptor, CMH, RMH, L, UMH>> + Send + Sync, | ||
| S: 'static + Deref<Target = SC> + Send + Sync, | ||
| SC: WriteableScore<'a> |
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.
nit: add trailing comma
| } | ||
|
|
||
| // Persist Scorer on exit | ||
| if let Some(ref scorer) = scorer { |
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.
Would it be worth doing the same in the loop?
| graph_error: Option<(std::io::ErrorKind, &'static str)>, | ||
| manager_error: Option<(std::io::ErrorKind, &'static str)>, | ||
| filesystem_persister: FilesystemPersister, | ||
| scorer_error: Option<(std::io::ErrorKind, &'static str)> |
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.
Let's move this before the prior field, which feels more logically consistent.
| let persister = Arc::new(Persister::new(data_dir)); | ||
| let event_handler = |_: &_| {}; | ||
| let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].net_graph_msg_handler.clone(), nodes[0].peer_manager.clone(), nodes[0].logger.clone()); | ||
| let scorer = Arc::new(Mutex::new(test_utils::TestScorer::with_penalty(0))); |
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.
Here and later tests, if the test doesn't explicitly check scoring, can we pass in None instead? Alternatively, add it the test Node struct so it only needs to be created in one place.
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.
Done. I wasn't able to use just None because the compiler wasn't able to infer the type:
cannot infer type for type parameter
Sdeclared on the associated function
so I added None::<Arc<Mutex<FixedPenaltyScorer>>>.
I know FixedPenaltyScorer is deprecated, however, when I tried None::<Arc<Mutex<ProbabilisticScorer<NetworkGraph, TestLogger>>>, the compiler complains:
669 | ...e(), None::<Arc<Mutex<ProbabilisticScorer<NetworkGraph, Logger>>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Deref` is not implemented for `NetworkGraph`
is that a problem?
also, should we create a follow-up issue for updating TestScorer to return a ProbabilisticScorer instead of FixedPenaltyScorer?
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.
Done. I wasn't able to use just
Nonebecause the compiler wasn't able to infer the type:cannot infer type for type parameter
Sdeclared on the associated functionso I added
None::<Arc<Mutex<FixedPenaltyScorer>>>.
Hmm... right, that's a bit verbose. I'd say add a scorer field to Node and do nodes[0].scorer.clone().
I know
FixedPenaltyScoreris deprecated, however, when I triedNone::<Arc<Mutex<ProbabilisticScorer<NetworkGraph, TestLogger>>>, the compiler complains:669 | ...e(), None::<Arc<Mutex<ProbabilisticScorer<NetworkGraph, Logger>>>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Deref` is not implemented for `NetworkGraph`is that a problem?
With this approach you would need to use &NetworkGraph or Arc<NetworkGraph> since the type parameter must implement Deref.
also, should we create a follow-up issue for updating
TestScorerto return aProbabilisticScorerinstead ofFixedPenaltyScorer?
No need. Scorer is deprecated not, FixedPenaltyScorer.
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.
@jkczyz gotcha. I guess if FixedPenaltyScorer is not deprecated I won't change it to ProbabilisticScorer then. Just added the scorer field to Node. should be ready for review again :) thanks!
199f46d to
de96726
Compare
de96726 to
434979e
Compare
jkczyz
left a 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.
Looks good modulo one comment.
| let scorer = Arc::new(Mutex::new(test_utils::TestScorer::with_penalty(0))); | ||
| let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].net_graph_msg_handler.clone(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(scorer.clone())); |
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 use the scorer in Node here now.
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.
oops, thanks for catching that.
434979e to
42383e4
Compare
| let persister = Arc::new(Persister::new(data_dir)); | ||
| let event_handler = |_: &_| {}; | ||
| let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].net_graph_msg_handler.clone(), nodes[0].peer_manager.clone(), nodes[0].logger.clone()); | ||
| let scorer = Arc::new(Mutex::new(test_utils::TestScorer::with_penalty(0))); |
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.
Will want to remove this and replace the usage below now. 🙂
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'm so sorry -- fixed
42383e4 to
4506b9f
Compare
| last_prune_call = Instant::now(); | ||
| have_pruned = true; | ||
| } | ||
| if let Some(ref scorer) = scorer { |
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.
Oops, this logic is busted if we don't have a net_graph_msg_handler provided (which, okay, should be rare). Just need to move the last_prune_call and have_pruned updates out of the above if. While you're at it, can you add a trace-level log before calling persist_scorer?
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.
Looks like this predates this change. @jurvis Could you make a separate commit for this fix?
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.
sure, I can do that 😄
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.
@jkczyz done
4506b9f to
b7533b4
Compare
|
@TheBlueMatt good catch! resolved. |
move last_prune_call back
b7533b4 to
e06bfdf
Compare
Addresses #1191
Implementation
WriteableScorethat makesLockableScorewriteable.BackgroundProcessor.startthat takes in our newWriteableScorepersist_scorerfunction toPersister, and implemented it withBufWriter(placeholder; to update after Pipe filesystem writes inlightning-persisterthroughBufWriter#1404) is mergedNotes/Questions
(see diff comments)