# Neon DevZen ## Selling points (10-15 mins, maybe 18 if discussion rises) * Formal guarantees: not only the powerful type system with borrowck, but also pluggable formal verification! - MUST: Rodionov: Newtypes (talk about ZId/ZTimelineId) - MUST: Rodionov: Error handling: Result and Option versus C-style -1, mention panics, helps to pay attention to various error conditions (this fsync failed etc) - MUST: Ivanov: Borrow checker: interating over a vector and trying to extend it - MUST: Rust basically requies that your code is completely UB-free / `#![forbid(unsafe_code)]` [cargo-fuzz](https://github.com/rust-fuzz/cargo-fuzz) (llvm libFuzzer) - MUST: Rodionov: Testing frameworks: the built-in is good enough, but there's also [proptest](https://github.com/altsysrq/proptest) / QuickCheck (courtesy of Haskell) - Paper: Rodionov: [Using Lightweight Formal Methods to Validate a Key-Value Storage Node in Amazon S3](https://dl.acm.org/doi/abs/10.1145/3477132.3483540) (Tokio maintainer works for amazon) TLDR property based testing, failure injection, model checking (loom), other tools... * Rust is a healthy community (kind and smart people, no stale problems) * Everybody can contribute: rust-analyzer (mention Kirill), documentation, various workgroups (async/graphics/stdlib/borrowck/types) - Rodionov: Rust Formal Methods Interest Group https://rust-formal-methods.github.io/ * Rodionov: Rust ecosystem is a young adult: crates.io works like a charm (think CMake/Autotools + vendoring) * Rodionov: Rust is big: we have a foundation and major players, i.e. Amazon, Microsoft, Google Fuchsia has rust code, yada-yada * Rust is popular among new database/data management projects * [quickwit](https://github.com/quickwit-oss/quickwit) Quickwit is the next-gen search & analytics engine built for logs. It is a highly reliable & cost-efficient alternative to Elasticsearch. * [databend](https://github.com/datafuselabs/databend) A Modern Cloud Data Warehouse with the Elasticity and Performance both on Object Storage * [materialize](https://github.com/MaterializeInc/materialize) Materialize is a streaming database for real-time applications. * Rodionov: Some people say that nightly is a must, but we (Neon) use stable and have everything we need ## Async woes/rant (20-40 mins, the more the better) * Introduction (5 min) - `std::future::Future` and `poll` and `waker`, __stackless__ coroutines - `async fn` === `fn -> impl Future` - Uses unstable generators feature under the hood (thus backtraces are bad, but there's [tokio-tracing](https://github.com/tokio-rs/tracing)) - GOTCHA: futures may be self-referential, what about rust's guarantees? Talk about `Pin` [Pin and suffering](https://fasterthanli.me/articles/pin-and-suffering) - Rodionov: Function colors: red vs blue, dual APIs: poll based api vs async fn (AsyncWrite: `poll_write`, AsyncWriteExt `async fn write` (not really fn write(...) -> Write + impl Future for Write)) * Async: async methods in traits (5 min) - Give definition - BRIEF: Missing feature: GATs (mostly for lifetimes) TODO: link to issue - BRIEF: Missing feature: TAITs (for anonymous futures) TODO: link to issue - Rodionov: MUST: Temp solution: async\_trait by dtolnay. Minuses: * boxed futures __per call__ * proc macro: comptime, IDE experience * various problems with lifetimes * Async: cancellation (5-8 min) - Give definition - How do we run __sync__ code on a future cancellation? * defer-ish drop guards (that was an easy one :) - How do we run __async__ code on a future cancellation? * Async drop et al * Spawn a new task for cleanup (talk more about problems, i.e. error propagation, GC-like properties, delays) - How do we write __correct__ code? What if we lose data that's stuck in an idle future? think `futures::select!` https://tomaka.medium.com/a-look-back-at-asynchronous-rust-d54d63934a1c Rodionov: Tokio docs: cancel-safe functions - Rodionov: structured concurrency: - Structured Concurrency is a programming paradigm that lets asynchronous operations run only within certain scopes so that they form an operation stack like a regular function call stack. As the parent operation waits until all children complete, Structured Concurrency helps local reasoning of concurrent programs. - It is supported, see FuturesUnordered, tokio LocalSet. There are some rust specific problems related to lifetims which arise if you want to safely share data between scopes without copying or passing pointers e g Arc's. This is the problem with absence of async drop - Tokio issue: https://github.com/tokio-rs/tokio/issues/1879 * Async: executor of your choice (5-12 min) - Tokio has mostly won (for now), but is it good? [Good work stealing scheduler (like go's) etc](https://tokio.rs/blog/2019-10-scheduler) - There are competitors: glommio (feature parity isn't there yet), how do we integrate them? - Lack of runtime-agnostic traits and APIs: * AsyncRead/AsyncWrite (tokio and futures-rs DO NOT agree on definitions!) * How do we spawn/cancel a future? (false dependency: we HAVE TO depend on the runtime, see global-runtime/[futures-rs](https://docs.rs/futures/latest/futures/task/trait.Spawn.html)) - Not all hope is lost: see async-wg (workgroup), issues are being worked on - Rodionov: Deep dive into glommio, monoio, iouring (discussion) - Completion vs Poll Based. Polling: During cancellationn for epoll you can stop polling a socket, but in completion you can receive a completion after future has been dropped. Thus causing use-after-free. Need further development, new traits, etc. Ongoing work: - https://www.ncameron.org/blog/async-io-with-completion-model-io-systems/ * Async: accindental calls of blocking functions (5 min) - Rodionov: Troubleshooting: tokio-console story, (experimental stall detector in glommio) - Rodionov: Unexpected goodness: mutex guards are NOT send, so they don't live across yield points! - Rodionov: NOT every sync primitives (e.g. Mutex) must be async! [Which kind of mutex should you use](https://docs.rs/tokio/latest/tokio/sync/struct.Mutex.html#which-kind-of-mutex-should-you-use) * Async: sometimes combinators do not feel 1st class (4 min) - Lifetimes across funtion boundaries (mutable aliasing). What can we do? - Rodionov: anecodal evidence: problems with concurrent file APIs (open and_then sync_all leads to boilerplate) * Async: futures might be HUGE (2 min) - Several kilabytes per one future! - Troubleshooting: `std::mem::size_of::<MyFuture>()`, compiler pass for struct sizes ## Rodionov: More about formal methods topics (approx 5 mins IF we have time) * prusti https://github.com/viperproject/prusti-dev Prototype verifier based on Viper * stateright https://docs.rs/stateright/latest/stateright/ A model checker for implementing distributed systems. Can compile models to actors and actually run them * Bright future: FERROCENE: RUST FOR CRITICAL SYSTEMS https://ferrous-systems.com/ferrocene/ ## Good to know (misc) * Code coverage - Newly stabilized in 1.60, previosly required `export RUSTC_BOOTSTRAP=1` (workaround!) - Had to invent bespoke script for capturing LLVM coverage data and rendering - Prior art: [tarpaulin](https://github.com/xd009642/tarpaulin), [cargo-llvm-cov](https://github.com/taiki-e/cargo-llvm-cov) * Allocation story - Fallible allocations: WIP rust in linux kernel gave it another spin (some std APIs already stable) - Custom allocators: WIP (there's some support in std, but mostly nightly) * [How to speed up the Rust compiler in 2022](https://nnethercote.github.io/2022/02/25/how-to-speed-up-the-rust-compiler-in-2022.html) (previously 2021, 2020 etc) * From the period 2021-11-11 to 2022-02-25 there were 303 improvements to the results of the rustc benchmark suite, many of which were over 10%, and only 21 regressions, as the following screenshot summarizes. * Incremental compilation woes - At any moment something remains broken! (just kidding :) - Tick-tock cycle: it's contantly turned off and then on and then off again