Rust at speed — building a fast concurrent database

This was a very good use of ~50 minutes.

  • Went over a couple of reasons Rust is possibly better than Go; two that resonate with me:

    • The type system, especially in the prevention of the result, err := (...) and if err != nil idioms.
    • Documentation is consistent, interlinked (even for third-party crates), and supported by the language as a fairly first-class entity.
  • Noria is a (research) database that plays with the idea of moving an application cache into the database and caching on write.

    • This cache requires fast read-write access.
    • Mutexes are too slow.
    • RwLocks are better, but for a fast critical section like this one (read a value from a hash map), the actual process of obtaining the lock is something of a bottleneck.
  • Use unsafe to build a lock-free data structure:

    • Maintain two caches (trade-off space for perf); at a given point in time, each cache is exclusively used by either readers or writers.
    • This is done by maintaining two separate unsafe pointers to these caches.
    • Once we have a critical mass of writes that can be flushed, switch the pointers so they point at the opposite cache.
    • The readers see all new writes, and the writers re-apply their changes to the new cache
      • Does this imply that writers have to buffer writes internally until they can write to both caches?
      • What happens in the case of multiple simultaneous writers? This explanation only covered a single writer.
      • The paper should answer these questions.
    • This pointer switch requires unsafe because Rust’s ownership system will not allow it.
    • This data structure performs great in micro-benchmarks and a simulated load test based on lobste.rs data:
  • This cache data structure is available as a crate: https://crates.io/crates/evmap

  • Some other general advice/tips for Rust:

    • If you feel like you’re fighting the language, pause and look for a better way.
      • A graph is extremely difficult to represent in the regular C/C++ structure without using unsafe
      • Using Rc is one way to solve this (I came to effectively the same conclusion yesterday)
      • Take this a step further by putting all graph nodes in a Vec and using vector indices in the actual graph data structure.
        • This is possibly unsuitable for a graph that requires heavy mutation.
    • A lint flag exists that fails compilation if any public module/method/API is undocumented. (I couldn’t find this)
    • clippy is a static analyzer that gives you advice about your code.
    • Rust makes it easy to split out your code into multiple crates; lean on this! (this feature is called “workspaces”)
Edit