-
Notifications
You must be signed in to change notification settings - Fork 385
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
Add utils to persist scorer in BackgroundProcessor #1416
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.
|
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
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.
@@ -277,6 +285,12 @@ impl BackgroundProcessor { | |||
if let Some(ref handler) = net_graph_msg_handler { | |||
persister.persist_graph(handler.network_graph())?; | |||
} | |||
|
|||
// 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?
@@ -418,6 +434,10 @@ mod tests { | |||
fn with_manager_error(self, error: std::io::ErrorKind, message: &'static str) -> Self { | |||
Self { manager_error: Some((error, message)), ..self } | |||
} | |||
|
|||
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
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 :)
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. |
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
where M::Target: 'static + chain::Watch<Signer>, | ||
T::Target: 'static + BroadcasterInterface, | ||
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
where M::Target: 'static + chain::Watch<Signer>, | ||
T::Target: 'static + BroadcasterInterface, | ||
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. 🙂
@@ -171,9 +173,11 @@ impl BackgroundProcessor { | |||
NG: 'static + Deref<Target = NetGraphMsgHandler<G, CA, L>> + Send + Sync, | |||
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
@@ -277,6 +285,12 @@ impl BackgroundProcessor { | |||
if let Some(ref handler) = net_graph_msg_handler { | |||
persister.persist_graph(handler.network_graph())?; | |||
} | |||
|
|||
// 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?
@@ -411,12 +426,13 @@ mod tests { | |||
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.
@@ -632,7 +663,8 @@ mod tests { | |||
let data_dir = nodes[0].persister.get_data_dir(); | |||
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
S
declared 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
None
because the compiler wasn't able to infer the type:cannot infer type for type parameter
S
declared 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
FixedPenaltyScorer
is 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
TestScorer
to return aProbabilisticScorer
instead 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
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
@@ -571,7 +600,8 @@ mod tests { | |||
let data_dir = nodes[0].persister.get_data_dir(); | |||
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
@@ -277,6 +281,11 @@ impl BackgroundProcessor { | |||
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
WriteableScore
that makesLockableScore
writeable.BackgroundProcessor.start
that takes in our newWriteableScore
persist_scorer
function toPersister
, and implemented it withBufWriter
(placeholder; to update after Pipe filesystem writes inlightning-persister
throughBufWriter
#1404) is mergedNotes/Questions
(see diff comments)