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

allow export of sha256sum for snapshots #1979

Merged
merged 8 commits into from Oct 6, 2022
Merged

Conversation

LesnyRumcajs
Copy link
Member

Summary of changes
Changes introduced in this pull request:

  • adds an option to export a sha256 checksum after exporting the snapshot. This step adds around 20 seconds to the total export time for calibnet. Unfortunately, it would be tricky to do it with chunk hashing during snapshot creation.

Reference issue to close (if applicable)

Other information and links

Part of #1899

@lemmih
Copy link
Contributor

lemmih commented Sep 30, 2022

It's tricky to compute the hash concurrently with snapshot creation before it would have to happen in the daemon rather than in the client?

@LesnyRumcajs
Copy link
Member Author

LesnyRumcajs commented Sep 30, 2022

It's tricky to compute the hash concurrently with snapshot creation before it would have to happen in the daemon rather than in the client?

We would need to implement our own AsyncWrite as the non-trivial logic is nested in https://github.com/filecoin-project/ref-fvm/blob/8d3a6148cbb65b4ec469f5115277aa6c2ab6df31/ipld/car/src/lib.rs#L31-L51
I am not sure it's worth it though I'm happy to give it a go if you feel otherwise.

@lemmih
Copy link
Contributor

lemmih commented Sep 30, 2022

It's tricky to compute the hash concurrently with snapshot creation before it would have to happen in the daemon rather than in the client?

We would need to implement our own AsyncWrite as the non-trivial logic is nested in https://github.com/filecoin-project/ref-fvm/blob/8d3a6148cbb65b4ec469f5115277aa6c2ab6df31/ipld/car/src/lib.rs#L31-L51 I am not sure it's worth it though I'm happy to give it a go if you feel otherwise.

Nah, let's leave it for the future. Or maybe @hanabi1224 could have a look at it.

@LesnyRumcajs
Copy link
Member Author

LesnyRumcajs commented Sep 30, 2022

It's tricky to compute the hash concurrently with snapshot creation before it would have to happen in the daemon rather than in the client?

We would need to implement our own AsyncWrite as the non-trivial logic is nested in https://github.com/filecoin-project/ref-fvm/blob/8d3a6148cbb65b4ec469f5115277aa6c2ab6df31/ipld/car/src/lib.rs#L31-L51 I am not sure it's worth it though I'm happy to give it a go if you feel otherwise.

Nah, let's leave it for the future. Or maybe @hanabi1224 could have a look at it.

It shouldn't be that difficult, just a wrapper around a BufWriter. But still, it introduces some logic and would obviously require proper coverage. 😁

@lemmih lemmih enabled auto-merge (squash) October 3, 2022 09:55
@LesnyRumcajs
Copy link
Member Author

@lemmih I revamped the hashing technology, please take a look again as it has changed a bit.

@LesnyRumcajs LesnyRumcajs force-pushed the checksum-for-exported-snapshots branch from 79f6adf to c221c57 Compare October 3, 2022 17:53
@LesnyRumcajs LesnyRumcajs marked this pull request as draft October 3, 2022 18:33
@LesnyRumcajs
Copy link
Member Author

Something is not right after merging with mainstream, will investigate why.

@LesnyRumcajs LesnyRumcajs marked this pull request as ready for review October 3, 2022 20:27
@LesnyRumcajs
Copy link
Member Author

Should be fine now. I did not handle partial write on Poll::Ready.

@lemmih
Copy link
Contributor

lemmih commented Oct 3, 2022

Can forest_utils and forest_utils_sink be merged?

We'll end up using tokio::io::AsyncWrite rather than futures::AsyncWrite but not a big deal since we can freely convert between the two.

@LesnyRumcajs
Copy link
Member Author

@lemmih

Can forest_utils and forest_utils_sink be merged?

I can rename forest_utils_sink to forest_utils_io and move the contents of forest_utils there. Right now the code seems to sit in the node/ which is a bit counterintuitive. What do you think?

@lemmih
Copy link
Contributor

lemmih commented Oct 4, 2022

@lemmih

Can forest_utils and forest_utils_sink be merged?

I can rename forest_utils_sink to forest_utils_io and move the contents of forest_utils there. Right now the code seems to sit in the node/ which is a bit counterintuitive. What do you think?

I feel like we have too may forest_utils crates and having a single utility crate would be much easier to handle. Right now we have forest_net_utils, forest_hash_utils, forest_json_utils, forest_test_utils, and forest_utils. We also have other utility crates with different names: forest_macros and forest_auth. How about we merge these into a single crate? For now, you could put your code in forest_utils::io.

@LesnyRumcajs
Copy link
Member Author

LesnyRumcajs commented Oct 4, 2022

@lemmih

Can forest_utils and forest_utils_sink be merged?

I can rename forest_utils_sink to forest_utils_io and move the contents of forest_utils there. Right now the code seems to sit in the node/ which is a bit counterintuitive. What do you think?

I feel like we have too may forest_utils crates and having a single utility crate would be much easier to handle. Right now we have forest_net_utils, forest_hash_utils, forest_json_utils, forest_test_utils, and forest_utils. We also have other utility crates with different names: forest_macros and forest_auth. How about we merge these into a single crate?

I kind of prefer many smaller crates partitioned by their categories than one big crate. Makes it easier to reason about dependencies and cuts compilations times.

For now, you could put your code in forest_utils::io.

This also doesn't work for me, conceptually. Importing utils from node (which forest_utils is actually) is a bit off for blockchain/chain, no? I'd recommend the approach mentioned in previous comment but if you feel strongly about this then of course I can go ahead with what you proposed.

@LesnyRumcajs
Copy link
Member Author

We'll end up using tokio::io::AsyncWrite rather than futures::AsyncWrite but not a big deal since we can freely convert between the two.

I moved it to tokio::io::AsyncWrite.

@lemmih
Copy link
Contributor

lemmih commented Oct 4, 2022

I kind of prefer many smaller crates partitioned by their categories than one big crate. Makes it easier to reason about dependencies and cuts compilations times.

What does it mean to "reason about dependencies" and I don't think it would cut compilation time. In what scenario would it cut compilation time?

@LesnyRumcajs
Copy link
Member Author

What does it mean to "reason about dependencies" and I don't think it would cut compilation time.

If I would see tide dependency in utils_hash I would be really surprised and would investigate it further. Same dependency in utils and I wouldn't even blink because I'd just ignore the entire wall of dependencies.

In what scenario would it cut compilation time?

To my understanding, if you change something in one significant crate dependency (especially the Cargo.lock), all dependents would have to rebuild. Same goes for having different binaries, you would not need to pull everything from crates.io if you'd have only small subset of dependencies.

@lemmih
Copy link
Contributor

lemmih commented Oct 4, 2022

What does it mean to "reason about dependencies" and I don't think it would cut compilation time.

If I would see tide dependency in utils_hash I would be really surprised and would investigate it further. Same dependency in utils and I wouldn't even blink because I'd just ignore the entire wall of dependencies.

While nice to have, I don't think that justifies the significant administrative cost of having a plethora of crates.

In what scenario would it cut compilation time?

To my understanding, if you change something in one significant crate dependency (especially the Cargo.lock), all dependents would have to rebuild. Same goes for having different binaries, you would not need to pull everything from crates.io if you'd have only small subset of dependencies.

But the bulk of our code will use all of the utility crates. I have a hard time imagining that having two crates for forest_hash_utils and forest_json_utils could ever save any compilation time. How would we avoid recompilation by keeping those two crates separate? Do we have significant code bases that only use one crate but not the other? And do we modify those utility crates frequently enough to justify the administrative cost?

@LesnyRumcajs
Copy link
Member Author

LesnyRumcajs commented Oct 4, 2022

How could it not save compilation time? You change something in metrics, a dependency of only forest. Only this dependency tree will need to get checked and re-compiled.

❯ cargo build
   Compiling forest_metrics v0.2.0 (/home/rumcajs-work/prj/forest/utils/metrics)
   Compiling forest v0.4.0 (/home/rumcajs-work/prj/forest/forest)
    Finished dev [unoptimized] target(s) in 18.61s

You change something in forest_json which has a larger dependency tree

❯ cargo build
   Compiling forest_json v0.2.0 (/home/rumcajs-work/prj/forest/utils/json)
   Compiling forest_vm v0.4.0 (/home/rumcajs-work/prj/forest/vm)
   Compiling forest_networks v0.2.0 (/home/rumcajs-work/prj/forest/types/networks)
   Compiling forest_statediff v0.2.0 (/home/rumcajs-work/prj/forest/utils/statediff)
   Compiling forest_fil_types v0.4.0 (/home/rumcajs-work/prj/forest/types)
   Compiling forest_message v0.8.0 (/home/rumcajs-work/prj/forest/vm/message)
   Compiling forest_state_migration v0.2.0 (/home/rumcajs-work/prj/forest/vm/state_migration)
   Compiling forest_blocks v0.2.0 (/home/rumcajs-work/prj/forest/blockchain/blocks)
   Compiling forest_actor_interface v0.2.0 (/home/rumcajs-work/prj/forest/vm/actor_interface)
   Compiling forest_paramfetch v0.2.0 (/home/rumcajs-work/prj/forest/utils/paramfetch)
   Compiling forest_interpreter v0.2.0 (/home/rumcajs-work/prj/forest/vm/interpreter)
   Compiling forest_chain v0.2.0 (/home/rumcajs-work/prj/forest/blockchain/chain)
   Compiling forest_state_manager v0.1.0 (/home/rumcajs-work/prj/forest/blockchain/state_manager)
   Compiling forest_libp2p v0.2.0 (/home/rumcajs-work/prj/forest/node/forest_libp2p)
   Compiling forest_genesis v0.2.0 (/home/rumcajs-work/prj/forest/utils/genesis)
   Compiling forest_message_pool v0.2.0 (/home/rumcajs-work/prj/forest/blockchain/message_pool)
   Compiling forest_chain_sync v0.2.0 (/home/rumcajs-work/prj/forest/blockchain/chain_sync)
   Compiling forest_rpc-api v0.2.0 (/home/rumcajs-work/prj/forest/node/rpc-api)
   Compiling forest_fil_cns v0.2.0 (/home/rumcajs-work/prj/forest/blockchain/consensus/fil_cns)
   Compiling forest_deleg_cns v0.2.0 (/home/rumcajs-work/prj/forest/blockchain/consensus/deleg_cns)
   Compiling forest_rpc v0.2.0 (/home/rumcajs-work/prj/forest/node/rpc)
   Compiling forest_rpc-client v0.2.0 (/home/rumcajs-work/prj/forest/node/rpc-client)
   Compiling forest v0.4.0 (/home/rumcajs-work/prj/forest/forest)
    Finished dev [unoptimized] target(s) in 22.58s

Of course, it won't cut the time by 80%, but when you do changes and monitor everything with cargo watch it does matter.

All in all, up to you. Maybe it's only my unpopular opinion.

@lemmih
Copy link
Contributor

lemmih commented Oct 4, 2022

Your example highlights my point. Even in such an extreme case where lots of crates are recompiled, the difference is only a few seconds: 18.61s vs 22.58s.

It was good discussing the pros and cons. Let's not add any more crates at this time.

@hanabi1224
Copy link
Contributor

a few seconds: 18.61s vs 22.58s

In this case I think the linkage of forest executable takes ~15s (on my machine) for both cases, maybe cargo check is a better command to make the comparison. BTW, I tried RUSTFLAGS="-Cprefer-dynamic" locally to reduce linkage time for a dev build but it failed with tons of errors. : (

Copy link
Contributor

@elmattic elmattic left a comment

Choose a reason for hiding this comment

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

Good!

@@ -70,32 +77,56 @@ where
}

let file = File::create(&out).await.map_err(JsonRpcError::from)?;
let writer = BufWriter::new(file);
let writer = AsyncWriterWithChecksum::<Sha256, _>::new(BufWriter::new(file));
Copy link
Contributor

Choose a reason for hiding this comment

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

In the case we want to skip this checksum, it seems to me we are still paying the price of computing it, only skipping saving the file no?

Copy link
Contributor

Choose a reason for hiding this comment

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

Hm, indeed. We'll address that in another PR.

@lemmih lemmih enabled auto-merge (squash) October 6, 2022 09:31
@lemmih lemmih merged commit 83db96b into main Oct 6, 2022
@lemmih lemmih deleted the checksum-for-exported-snapshots branch October 6, 2022 10:00
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.

None yet

4 participants