Jon Gjengset
Eliminating reader-writer locks in favor of epoch-tracked dual maps allows write-driven dataflow databases to double the throughput of dedicated in-memory caches.
AI-assisted summary of Rust at speed — building a fast concurrent database — original source. Check the original for full context.
Source published:
Key ideas
- Noria, a 60,000-line research database prototype built in Rust at MIT CSAIL, replaces read-time query execution with write-driven incremental dataflow, turning reads into O(1) materialized view lookups. (1:21)
- Standard reader-writer locks (RwLock) fail under fast, short critical sections like hash map lookups because pthreads internally serializes reads using an exclusive lock to manage reader counts. (27:57)
- Using a dual-buffered Left-Right map with epoch tracking (evmap), Noria achieves 14 million operations per second on vote-count queries, outperforming memcached (7M ops/sec) and relational engines like MySQL (200k ops/sec). (40:19)
- The core lock-free evmap data structure relies on only 7 lines of unsafe Rust code, demonstrating that high-performance concurrent systems can isolate manual invariants to minimal, auditable blocks. (37:27)
Detailed notes
## Background Published on YouTube by Jon Gjengset on January 5, 2019, this video records a guest lecture delivered at Two Sigma Labs in November 2018. According to the page description, the talk covers Gjengset's experience using Rust to build large, high-performance systems, focusing on the architecture of Noria—a research database prototype built at MIT—and a specialized concurrent data structure designed for it.
## TL;DR Gjengset explains how traditional relational databases waste CPU cycles recomputing queries for read-heavy workloads and demonstrates how Noria addresses this by maintaining dynamic, self-updating materialized views through write-driven incremental dataflow. To eliminate contention on the shared results cache without stalling reads, he breaks down the Left-Right concurrency pattern and reader-epoch mechanics behind the lock-free `evmap` data structure. Microbenchmarks and realistic Lobsters production traces demonstrate Noria substantially outperforming MySQL, commercial databases, and Memcached under high concurrency. He concludes by offering practical advice for adopting Rust, illustrating how to work collaboratively with the borrow checker, leverage tooling like Clippy, and embrace compiler-guided refactoring.
## Atmosphere & style The presentation carries the engaging, articulate cadence of an advanced systems seminar, seamlessly bridging high-level language philosophy with low-level mechanical sympathy. Following Larry Rudolph's warm, collegiate introduction, Gjengset delivers an approachable yet deeply technical walkthrough, punctuating complex concurrency concepts with dry humor and reassuring calm around taboo topics like `unsafe`. It feels like an intimate masterclass from a battle-tested systems engineer who genuinely empathizes with the friction of the borrow checker while revealing how its strict discipline makes programmers fundamentally better at reasoning about correctness.
## Bulletin - [01:21](https://www.youtube.com/watch?v=s19G6n0UjsM&t=81s) Noria, a 60,000-line research database prototype built in Rust at MIT CSAIL, replaces read-time query execution with write-driven incremental dataflow, turning reads into O(1) materialized view lookups. - [27:57](https://www.youtube.com/watch?v=s19G6n0UjsM&t=1677s) Standard reader-writer locks (RwLock) fail under fast, short critical sections like hash map lookups because pthreads internally serializes reads using an exclusive lock to manage reader counts. - [40:19](https://www.youtube.com/watch?v=s19G6n0UjsM&t=2419s) Using a dual-buffered Left-Right map with epoch tracking (evmap), Noria achieves 14 million operations per second on vote-count queries, outperforming memcached (7M ops/sec) and relational engines like MySQL (200k ops/sec). - [37:27](https://www.youtube.com/watch?v=s19G6n0UjsM&t=2247s) The core lock-free evmap data structure relies on only 7 lines of unsafe Rust code, demonstrating that high-performance concurrent systems can isolate manual invariants to minimal, auditable blocks.
## Key takeaways - [03:19](https://www.youtube.com/watch?v=s19G6n0UjsM&t=199s) Rust breaks traditional systems programming trade-offs by combining C-level performance and zero-cost abstractions with compile-time memory safety and data-race prevention. - [07:11](https://www.youtube.com/watch?v=s19G6n0UjsM&t=431s) Algebraic data types like Result and Option, paired with expressive pattern matching, eliminate null-pointer dereferences and force exhaustive compile-time error handling. - [09:20](https://www.youtube.com/watch?v=s19G6n0UjsM&t=560s) Integrated tooling such as Cargo, automatic executable doctests, and frictionless C/C++ FFI make Rust development ergonomic and practical for incremental adoption. - [10:58](https://www.youtube.com/watch?v=s19G6n0UjsM&t=658s) Rust remains challenging for rapid prototyping, GUI programming, bare-metal no_std kernels, and vendor-heavy C frameworks like Intel DPDK due to strict compiler guardrails and manual binding overhead. - [13:35](https://www.youtube.com/watch?v=s19G6n0UjsM&t=815s) Web architectures are heavily read-dominated, but traditional relational databases repeatedly recompute expensive joins and aggregates, while external caches introduce invalidation bugs and thundering herd failures. - [16:09](https://www.youtube.com/watch?v=s19G6n0UjsM&t=969s) Noria addresses database read bottlenecks by maintaining precomputed state incrementally on writes through a directed dataflow graph of relational operators. - [18:37](https://www.youtube.com/watch?v=s19G6n0UjsM&t=1117s) Handling real-world workloads in Noria required solving partial materialization to prevent unbounded memory growth and enabling live, dynamic dataflow graph migrations without tearing down running state. - [21:01](https://www.youtube.com/watch?v=s19G6n0UjsM&t=1261s) Rust's ownership and borrow checker enforce safety by ensuring memory is either accessed via multiple immutable references (&T) or a single exclusive mutable reference (&mut T) at compile time. - [27:57](https://www.youtube.com/watch?v=s19G6n0UjsM&t=1677s) For short operations like hash map lookups, reader-writer locks bottleneck throughput because acquiring and releasing the lock requires internal serialization that dwarfs the lookup time. - [30:27](https://www.youtube.com/watch?v=s19G6n0UjsM&t=1827s) Rust's unsafe keyword does not disable all compiler guarantees; it specifically permits low-level operations like dereferencing raw pointers while localizing verification to auditable blocks. - [33:15](https://www.youtube.com/watch?v=s19G6n0UjsM&t=1995s) The Left-Right pattern avoids read locks by maintaining duplicate maps, swapping atomic read/write pointers, and tracking reader epochs to detect when concurrent readers have cleared old state. - [40:19](https://www.youtube.com/watch?v=s19G6n0UjsM&t=2419s) On an end-to-end trace replay of the Lobsters web service, Noria handled 5,000 to 6,000 page views per second on a 16-core machine compared to 800 to 1,100 on MySQL. - [43:23](https://www.youtube.com/watch?v=s19G6n0UjsM&t=2603s) Learning Rust requires understanding ownership semantics rather than treating it like C or Go; compiler friction typically signals unidiomatic designs such as cyclic pointer graphs. - [46:57](https://www.youtube.com/watch?v=s19G6n0UjsM&t=2817s) Decomposing systems into modular crates improves architecture, speeds up parallel compilation, and allows enforcing documentation coverage with compiler flags like #![deny(missing_docs)]. - [49:32](https://www.youtube.com/watch?v=s19G6n0UjsM&t=2972s) The rigor of the Rust type system enables fearless compiler-guided refactoring, turning compiler error diagnostics into an actionable checklist when altering complex systems. - [51:02](https://www.youtube.com/watch?v=s19G6n0UjsM&t=3062s) Internalizing Rust's borrow checker alters how developers reason about concurrency and resource ownership across all other programming languages.
## Detailed walkthrough ### [00:00](https://www.youtube.com/watch?v=s19G6n0UjsM&t=0s) Introduction and Jon Gjengset's Background
Larry Rudolph introduces the guest lecture hosted by the Two Sigma Labs team, explaining that one of the team's core missions is bridging industry with academia. Rudolph recalls meeting Jon Gjengset at MIT CSAIL while working with Trevor on firmware security:
> “We had this idea that we should use Rust and so we met, so there's the MIT Rust expert, or the Northeast Rust expert, or the worldwide Rust expert, I don't know which one call yourself with, but his research is also on databases, novel ways databases, and coordination and conflicts and stuff that I really like.”
Rudolph outlines Gjengset's geographic trajectory—growing up in Norway, completing his undergraduate degree in Australia, moving to London, and ultimately coming to MIT as a graduate student in CSAIL. Rudolph asked Gjengset to cover both topics: the Rust programming language and database research. Gjengset confirms that the lecture will be followed by a deep dive and extended Q&A session.
[01:21](https://www.youtube.com/watch?v=s19G6n0UjsM&t=81s) Talk Roadmap: Rust in Practice and the Noria Database
Jon Gjengset sets expectations for the lecture, stating that the talk addresses Rust from a practical perspective based on his three years of building Noria at MIT. Noria is a high-performance research database prototype developed within the Parallel and Distributed Operating Systems (PDOS) group. Gjengset explains that he wants to demystify what it feels like to build a real, large-scale production-grade system in Rust, directly addressing common industry reservations about the language.
```mermaid flowchart TD accTitle: Scope of the Talk accDescr: High-level overview of covered and excluded topics in Jon Gjengset's talk. subgraph Covered["Topics Covered"] direction TB C1["High-level Rust & ownership fundamentals"] C2["Noria high-performance database architecture"] C3["Novel concurrent data structure design"] C4["Practical experience building large systems"] end subgraph Excluded["Deferred to Q&A / Research Paper"] direction TB E1["Syntax deep-dives & low-level compiler code"] E2["Query planning & query execution internals"] E3["Formal database theory"] end ```
Rather than focusing on syntax or low-level compiler details, the talk concentrates on higher-level trade-offs, Rust's ownership model, and the overall architecture of Noria. Gjengset also highlights that he will present a specialized concurrent data structure designed specifically for Noria that should appeal to systems engineers. Query execution and planning details are left to the published paper or follow-up discussions.
- Noria comprises approximately 60,000 lines of Rust code developed over three years. - Jon Gjengset maintains multiple open-source Rust libraries, contributes to Rust's asynchronous I/O ecosystem, and has published over 30 hours of live Rust coding streams.
[03:19](https://www.youtube.com/watch?v=s19G6n0UjsM&t=199s) What Is Rust? Fast, Reliable, Productive
Gjengset explains that Rust is an open-source systems programming language created by Mozilla that reached version 1.0 roughly four years prior. While systems programming is traditionally a vague term applied to servers, clients, and infrastructure software, Gjengset emphasizes that Rust aims to fundamentally eliminate long-standing compromises in systems software design.
> “One of the ones they're relatively well-known for is this 'fast, reliable, productive, pick three', and the idea is that in a lot of existing production languages you're sort of forced into this 'I have to choose away something, I have to choose to not get a particular feature'—like in C you don't get safe code, but you get really high performance, and Rust wants to sort of do away with those trade-offs instead saying let's try to do all of them.”
A primary example is Rust's philosophy of "fearless concurrency," enabling engineers to author highly concurrent systems without constant fear of subtle data races or runtime memory corruption. Gjengset also emphasizes Rust’s open, community-driven governance: development takes place publicly on GitHub, language and compiler enhancements go through an open Request for Comments (RFC) process, and stable releases ship on a predictable six-week cadence.
[05:01](https://www.youtube.com/watch?v=s19G6n0UjsM&t=301s) Core Technical Differentiators of Rust
Contrasting Rust with alternative languages like Haskell, OCaml, and Go, Gjengset breaks down the core technical attributes that make Rust uniquely suited for robust systems programming:
- **Expressive Type System:** Much closer to Haskell than to C, allowing complex invariant checks and state constraints to be enforced entirely at compile time. - **Zero-Cost Abstractions:** Interfaces and polymorphic abstraction layers are monomorphized at compile time, matching C and C++ runtime speeds without virtual call penalties where avoidable. - **The Borrow Checker:** Static analysis guarantees memory safety and freedom from data races at compile time before any binary is produced. - **Modern Infrastructure:** The language tooling incorporates decades of lessons learned in package management, compilation, documentation, and continuous integration.
Because Rust is engineered to interoperate seamlessly with existing C and C++ codebases, organizations can selectively swap out fragile, race-prone subcomponents inside legacy software without rewriting entire architectures. Gjengset notes that this interoperability was Mozilla’s original motivation for creating Rust: they needed a way to incrementally replace components of the Firefox browser with safe, concurrent modules that guaranteed absence of crashes. At the same time, the language ergonomically scales up to high-level application services and command-line tooling, feeling almost as expressive as Python while retaining native execution speed and strict compile-time verification.
[07:11](https://www.youtube.com/watch?v=s19G6n0UjsM&t=431s) Memory Safety, Algebraic Data Types, and Pattern Matching
Gjengset highlights concrete features that eliminate broad categories of bugs common in languages like C, C++, and Go. In traditional systems code, developers take it for granted that programs will crash during early runs due to memory errors or concurrency races.
> “In Rust, lots of concurrency bugs are impossible—the compiler will not let you compile a program that has a data race in it, and if you come from basically any other language this is very surprising, right? In C you will write a program and you expect it to crash at runtime the first few times you run it; this is not the case with Rust code.”
Static compile-time ownership semantics completely eliminate use-after-free and double-free vulnerabilities. Beyond memory safety, Gjengset details how Rust structures data and control flow through Algebraic Data Types (ADTs):
| Type / Feature | Rust Implementation | Traditional Language Parallel | Practical Safety Advantage | |:--- |:--- |:--- |:--- | | **Error Handling** | `Result<T, E>` enum with `Ok(T)` and `Err(E)` | Go multi-value returns `(val, err)` or C error codes | The compiler forces explicit checking of both variants before values can be accessed; unhandled errors cannot slip past unnoticed. | | **Absence of Value** | `Option<T>` enum with `Some(T)` and `None` | Null pointers (`NULL`, `nil`, `None`) | Completely removes null-pointer dereference exceptions; values must be unpacked safely. | | **Control Flow** | Rich Pattern Matching | Switch statements | Enables deep destructuring and complex condition matching (e.g., matching a success result containing an integer between 4 and 17 alongside a specific string) with zero runtime cost. |
[09:20](https://www.youtube.com/watch?v=s19G6n0UjsM&t=560s) Rust Tooling, Built-in Documentation, and FFI Interoperability
Rust’s development ergonomics feel remarkably lightweight and modern, despite compiling down to bare-metal performance. Gjengset observes that writing Rust often feels more like Python or JavaScript than low-level C code, largely due to its polished developer tooling. Dependency management is baked directly into the default tooling via Cargo, surpassing package managers like npm for JavaScript, PyPI for Python, or `go get` for Go. It natively handles standard central repository crates, local path dependencies, and remote Git dependencies out of the box without requiring external plugins.
Documentation is similarly treated as a first-class citizen embedded into the language itself. By prefixing any function, module, or constant with three slashes (`///`) instead of two, developers produce markdown documentation. Crucially, code snippets written inside these doc comments are automatically compiled and run as tests during `cargo test`. This guarantees that code examples stay permanently up to date with implementation changes. Furthermore, the central package repository automatically builds, formats, and cross-links all crate documentation, giving the entire ecosystem a uniform, navigable interface. Interoperability with foreign code is equally frictionless: foreign function interfaces (FFI) make calling into C or C++ libraries straightforward, and bidirectional bindings allow seamless integration with languages like Python, Ruby, and Go.
> “It will always be interact with other crates is actually fabulous to use and I do not use that term lightly.” — Jon Gjengset
- **Integrated Package Management:** First-class support for Git repositories, file system paths, and central package registries directly in Cargo. - **Doctests:** Triple-slash doc comments (`///`) execute code samples during unit testing to eliminate stale documentation. - **Foreign Function Interface (FFI):** Direct, low-overhead interop allows existing C, C++, Python, Ruby, or Go applications to incrementally adopt Rust.
---
[10:58](https://www.youtube.com/watch?v=s19G6n0UjsM&t=658s) Current Limitations: Where Rust Struggles
Despite its advantages, Rust is not a silver bullet, and Gjengset emphasizes several domains where the language is still maturing or poorly suited. First, interfacing with highly specialized, vendor-heavy C frameworks—such as Intel’s DPDK (Data Plane Development Kit)—presents high friction. While tools exist to generate bindings from C header files, maintaining vast wrappers for complex APIs requires enormous overhead if nobody in the open-source community has already built them. Second, Rust is fundamentally ill-suited for quick, throwaway prototyping where a developer just wants to write dirty code and run it once without caring about panics. The compiler's relentless insistence on exhaustively handling error states, checking nullable cases via `Option`, and verifying memory safety strictly fights against rough, rapid hacking.
Other problem spaces face ongoing ecosystem growth. Kernel-level development remains finicky because bare-metal code must forgo standard runtime facilities like `libc` and the standard library (`std`). Desktop GUI programming is notoriously challenging across all languages; although Rust has bindings for GTK, Qt, Win32, and macOS Cocoa, the abstractions are young and awkward to map to Rust's ownership model. Finally, asynchronous networking and I/O remain an area of intense work. While Rust's promise-like `Future` abstraction delivers exceptional throughput in high-performance engines like Noria, the ergonomics can become convoluted because higher-level language primitives are still evolving.
> “If you just want to write something and not worry about the details, Rust is an awful language for that job because Rust will force you to write correct code.” — Jon Gjengset
- **Specialized Native Stacks:** Integrating massive C ecosystems like Intel DPDK or complex cloud SDKs incurs heavy binding maintenance. - **Prototype Friction:** Exhaustive type checking, lifetime tracking, and mandatory error handling impede fast, disposable scripting. - **Kernel & GUI Development:** Writing `no_std` kernel extensions requires extra effort, and GUI libraries struggle to align cleanly with Rust's single-ownership model. - **Asynchronous I/O:** The primitives deliver raw performance, but writing complex async dataflows can become visually complex and verbose.
---
[13:35](https://www.youtube.com/watch?v=s19G6n0UjsM&t=815s) The Relational Database Bottleneck and the Cache Problem
Transitioning into the database portion of the lecture, Gjengset introduces Noria, a research database prototype designed to eliminate unnecessary query overhead. In modern web architectures, applications constantly issue SQL queries that join and aggregate relational tables—such as calculating the aggregate vote count for an article by joining a `stories` table with a `votes` table. Traditional relational databases parse the query, devise an execution plan, run the table scans, compute aggregates, join the tables, filter the results, and stream the answer back to the frontend.
```mermaid flowchart TD accTitle: Traditional Database Read Flow vs External Cache accDescr: Diagram contrasting standard database read planning with external cache invalidation challenges.
subgraph RelationalDB ["Traditional Relational Database"] Q["Read Query: SELECT COUNT..."] --> QP["Query Planner"] QP --> Agg["Count Votes"] Agg --> Join["Join with Stories"] Join --> Res["Stream Result"] end
subgraph ExternalCache ["External Cache Pattern"] App["Web Application"] -->|"Check Cache"| Cache["Memcached / Redis"] Cache -.->|"Cache Miss"| DB["Backend Database"] App -->|"Write"| DB App -.->|"Manual Invalidation"| Cache end ```
The fundamental design flaw is that web workloads are overwhelmingly read-heavy, often exceeding 90% read traffic. Because relational engines execute queries upon read, they repeatedly recompute identical joins and aggregates even when underlying data has not changed, wasting immense CPU cycles. Developers typically attempt to patch this inefficiency by deploying an external caching layer like Memcached or Redis. However, external caches burden application code with manual cache invalidation logic. Invalidate too aggressively, and the cache evaporates; invalidate incorrectly, and users serve stale data. Crucially, external caching introduces catastrophic failure modes like the "thundering herd" problem: when a write invalidates an entry for a heavily trafficked key, subsequent concurrent reads all miss simultaneously, overwhelming the database backend at once.
> “All of this seems like so much complexity in order to make your application fast.” — Jon Gjengset
- **Read Dominated Workloads:** Standard applications waste significant CPU power recalculating identical relational views on repetitive reads. - **Invalidation Complexity:** Application developers are forced to manually coordinate cache evictions and writes, opening doors to stale data. - **Thundering Herd Problem:** Evicting a single highly popular key causes concurrent incoming reads to bypass the cache and crush the primary relational database.
---
[16:09](https://www.youtube.com/watch?v=s19G6n0UjsM&t=969s) Noria’s Core Architecture: Incremental Dataflow on Writes
Noria inverts traditional database architecture by observing that the database already knows the queries the application cares about, meaning the database engine itself should maintain the cache. Rather than evaluating a query execution plan on read, Noria evaluates the query incrementally on write. When an application registers a SQL query, Noria constructs an internal dataflow graph consisting of relational operators (such as aggregators, filters, and joins) terminating in a materialized view, which acts as a concurrent in-memory cache.
```mermaid flowchart LR accTitle: Noria Incremental Dataflow Architecture accDescr: Flow diagram tracing an incoming vote write through Noria operators directly updating an in-memory materialized view.
subgraph DataflowPipeline ["Dataflow Pipeline (Executes on Write)"] W["Incoming Write (Vote +1 for A)"] --> CountOp["Count Operator (Updates 41 to 42)"] CountOp -->|"Record: (A, 42)"| JoinOp["Join Operator (Looks up Story Title)"] JoinOp -->|"Record: (A, 42, 'foo')"| MV["Materialized View / Cache"] end
subgraph ApplicationRead ["Application Reads"] Client["Frontend Client"] -->|"Single Direct Lookup"| MV end ```
When a write arrives—such as a new vote for story `A`—it enters the dataflow graph at the base operators. The `count` operator inspects its local state, sees that the prior count was 41, increments it to 42, and emits a delta record containing `(A, 42)`. That record passes downstream into the `join` operator, which resolves story `A`'s title (`"foo"`) and emits `(A, 42, "foo")`. Finally, this record enters the materialized view cache at the leaf node, updating story `A`'s precomputed row directly in memory. When the frontend issues a query, it executes a single instantaneous key-value lookup against this pre-materialized view. The application never performs cache invalidations, writes execute asynchronously through the graph, and the cache remains perpetually updated. Gjengset notes, however, that while this model delivers exceptional throughput, it introduces fundamental research challenges: an engine cannot practically afford to store materialized state for every query and key across all time.
> “The database has your queries, so why can't the database just maintain the cache? Wouldn't that be a lot easier?” — Jon Gjengset
- **Write-Driven Incremental Evaluation:** Queries compile into persistent dataflow graphs that compute state transitions only when base tables change. - **Zero-Invalidation Frontend:** Applications treat the database as a self-updating cache, executing simple O(1) index lookups on read without managing external TTLs. - **Memory Footprint Challenge:** Precomputing and caching every intermediate relation and final view for infinite keys rapidly exhausts physical memory, creating the central engineering challenge Noria must solve.
[18:37](https://www.youtube.com/watch?v=s19G6n0UjsM&t=1117s) Core Challenges in Noria: Partial Materialization and Dynamic Query Adaptation
Jon Gjengset steps back from the basic dataflow architecture to highlight the severe practical challenges encountered when building a real-world database like Noria. The first hurdle is memory exhaustion: systems do not have infinite RAM, meaning data must be evicted from the cache. However, eviction in an incremental dataflow graph is notoriously hard. If the system throws away cached intermediate counts—such as all the computed results for a given "story A"—and an upvote later arrives for that same story, the downstream count operator no longer has the previous vote count available to emit the updated total. As Gjengset puts it: “and so you need a mechanism your system to ensure that even if you throw something away or something gets asked for that you've never been asked for before that you have some way of computing it or recomputing it this is the problem of partial materialization that we will not get into in this talk”.
The second challenge involves handling schema and query evolution over time. While pedagogical examples assume a single, static query, real production applications run hundreds of queries that continuously change, grow, and evolve as features are added. Traditional distributed dataflow runtimes such as Naiad or Apache Spark cannot seamlessly alter query graphs while live traffic is flowing; operators typically have to tear down the entire pipeline and instantiate a brand-new instance containing the updated queries. Noria avoids this brute-force approach by dynamically adapting the dataflow topology on the fly while retaining state—a feat detailed extensively in the Noria research paper.
```mermaid flowchart TD accTitle: Noria Research Challenges accDescr: The three major systems challenges in building Noria.
subgraph Memory ["1. Memory Limits"] A["Cache Eviction"] --> B["Partial Materialization<br>(Recompute on demand)"] end
subgraph Dynamic ["2. Dynamic Topology"] C["Query & Schema Changes"] --> D["Live Graph Rewriting<br>(No tear-down like Spark/Naiad)"] end
subgraph Concurrency ["3. Shared Results State"] E["High-Throughput Reads & Writes"] --> F["Concurrent Results Table<br>(Requires custom synchronization)"] end ```
- **Partial Materialization**: Enables the dataflow engine to compute and store only subset slices of downstream state on demand rather than the entire universe of records. - **Dynamic Migration**: Modifies the operator graph online in response to application migrations without downtime, distinct from batch or static streaming systems. - **Paper Reference**: Gjengset notes that the detailed algorithmic solutions to partial materialization and dynamic dataflow adaptivity can be explored in the published Noria paper.
---
[20:08](https://www.youtube.com/watch?v=s19G6n0UjsM&t=1208s) The Concurrency Bottleneck: Readers vs. Writers in the Results Table
Gjengset focuses on the third critical challenge: synchronizing concurrent access to the materialized results table. In Noria's architecture, this results table serves as the primary cache where all write operations from the upstream dataflow terminate, and simultaneously acts as the destination where client read queries arrive. The table is hammered by hordes of concurrent readers alongside concurrent writes streaming from database updates.
Allowing raw, uncoordinated reads and writes across this shared memory table invites race conditions, torn reads, and data corruption. “You can't just do that unless you have some kind of synchronization because a writer might update a record while it's being written so we need some kind of synchronization here and we want that to be really fast because they're gonna be lots of reads and lots of writes to this at the same time,” Gjengset explains. Finding a synchronization mechanism that does not destroy read throughput while accommodating high write volumes necessitates diving into fundamental computer science principles and examining how Rust models memory access.
---
[21:01](https://www.youtube.com/watch?v=s19G6n0UjsM&t=1261s) Rust's Ownership and Borrowing Model
To understand why traditional synchronization primitives fail this workload, Gjengset breaks down Rust's core ownership mechanism, comparing its underlying philosophy to RAII (Resource Acquisition Is Initialization) in C++. In Rust, every value has a unique owner responsible for reclaiming and freeing its memory when it goes out of scope. Crucially, that owner controls precisely how and when other parts of the program may access that resource.
When handling any arbitrary type `T` (whether an integer, an array, or a string), Rust strictly limits access to one of three variants:
1. **Owned `T`**: You hold exclusive ownership and bear the duty of deallocating it. 2. **Mutable Reference `&mut T`**: Modeled like an exclusive pointer. You gain the privilege of modifying the resource without the duty of freeing it, guaranteed by the compiler that no other thread or pointer can read or write to it concurrently. 3. **Immutable Reference `&T`**: A shared pointer granting read-only access, permitting any number of concurrent readers while strictly forbidding any mutations.
Rust enforces these access contracts at compile time. It checks that a resource never has an active mutable reference (`&mut T`) simultaneously with any immutable references (`&T`), nor may multiple mutable references coexist. Gjengset summarizes the consequence: “it turns out that's all you need to guarantee the program has no data races right if you never have something modify a thing while it's being read or modified you cannot have data races because you will either just have multiple readers or you'll have a single writer which is fine”.
```mermaid flowchart LR accTitle: Rust Borrowing Invariants accDescr: The two mutually exclusive compile-time borrowing states allowed in Rust.
subgraph Shared ["Shared Mode (Safe)"] R1["&T (Reader 1)"] R2["&T (Reader 2)"] RN["&T (Reader N)"] end
subgraph Exclusive ["Exclusive Mode (Safe)"] W["&mut T (Sole Writer)"] end
Shared -. "XOR (Compile Check)".- Exclusive ```
Lifetimes tie borrowed references to the dynamic scope of the owner—such as a specific stack frame. If a function attempts to capture a reference to a stack-allocated buffer and dispatch it to an independent thread that might outlive the current stack frame, the compiler rejects the program during compile time.
- **Double-Free Prevention**: Enforcing a single owner guarantees resources are freed exactly once when that owner drops out of scope. - **Use-After-Free Elimination**: The borrow checker prevents reading from or writing to invalid references by guaranteeing lifetimes never outlive the underlying resource. - **Data-Race Freedom**: The mutual exclusion rule between `&mut T` and `&T` eradicates data races without runtime garbage collection overhead.
---
[24:34](https://www.youtube.com/watch?v=s19G6n0UjsM&t=1474s) Framing Shared Tables as an Ownership Problem: Mutex vs. RwLock
The high-performance results table problem maps directly into Rust's ownership domain: Noria requires concurrent readers and writers to interact with a shared structure simultaneously, which Rust’s compiler outright rejects under raw references. To bridge this gap, Rust requires synchronization types capable of providing safe "interior mutability," allowing a program to turn a shared handle (`&Self`) into an exclusive reference (`&mut T`).
The most canonical synchronization primitive is the `Mutex<T>`. In Rust, a mutex is not an isolated flag sitting next to arbitrary memory; it directly wraps the inner data type `T`. To inspect or update `T`, a caller must invoke `.lock()`, which borrows the mutex immutably and yields an RAII guard (`MutexGuard<'a, T>`). As long as that guard remains alive and holds mutual exclusion, it confers safe mutable access (`&mut T`) to the interior data.
```mermaid flowchart LR accTitle: Rust Mutex Guard Pattern accDescr: The chain from a shared Mutex reference to an exclusive mutable reference via a MutexGuard.
A["Shared Mutex Reference<br>&'a Mutex<T>"] -->|".lock()"| B["Credential<br>MutexGuard<'a, T>"] B -->|".get() / DerefMut"| C["Exclusive Access<br>&mut T"] ```
However, wrapping the results table in a simple `Mutex` completely ruins database performance. Gjengset rejects this outright: “mutexes are terrible because well they can be ok but in this particular instance they're really bad because they force you to have sequential access if you think of our results table you either have to do a read or a write for any given unit time which is terrible because we want to do things in parallel we want this to be current and fast and new Texas are neither concurrent nor fast”.
A common alternative is a reader-writer lock (`RwLock<T>`), which mirrors Rust’s borrowing rules dynamically: it permits either an arbitrary count of parallel readers holding a read lock or a single exclusive writer holding a write lock. While this allows parallel reads, Gjengset hints that when high-frequency writes continuously interleave with constant reads, even an `RwLock` introduces intolerable contention and blocking.
[27:57](https://www.youtube.com/watch?v=s19G6n0UjsM&t=1677s) The Pitfalls of Reader-Writer Locks on Fast Workloads
Jon examines whether wrapping a standard `HashMap` in a reader-writer lock (`RwLock`) actually solves the concurrency bottleneck for read-heavy workloads. He points to the underlying implementation of reader-writer locks in POSIX threads (`pthreads`) to explain why they fall short. To allow multiple threads to acquire the read lock concurrently, the lock implementation must internally acquire an exclusive mutual exclusion lock briefly to update reader state, releasing it right before returning the read handle.
This hidden exclusive lock fundamentally alters the performance characteristics depending on the length of the critical section. If a thread holds the read lock across a massive amount of computation, the lock acquisition overhead is negligible, and concurrency scales effectively. However, when the critical section is extremely short—such as looking up an entry in a hash map—the lock acquisition dominates the execution time. Because acquiring that internal lock is a strictly sequential operation, the program is serialized. Jon presents a benchmark graph comparing read and write throughput against the number of threads: initially, throughput increases with a few threads, but quickly plateaus and degrades as the system spends all its time contending on the lock rather than performing hash lookups.
```mermaid flowchart TD accTitle: Reader-Writer Lock Internal Bottleneck accDescr: Diagram showing how pthreads RwLock serializes reads through an internal exclusive lock.
subgraph RwLock["pthreads RwLock Read Path"] direction TB A["Reader Thread arrives"] --> B["Acquire internal exclusive lock"] B --> C["Increment active reader count"] C --> D["Release internal exclusive lock"] D --> E["Execute hashmap lookup"] E --> F["Re-acquire internal exclusive lock"] F --> G["Decrement active reader count & release"] end
H["Concurrent Reader Threads"] -->|Contention bottleneck| B ```
Jon emphasizes that benchmarking this naive setup reveals we are not measuring map performance at all: “All we're doing while holding the reader lock is doing a hashmap lookup, hashmap lookups are really fast, therefore we're basically benchmarking the performance of taking a lock.” To achieve ideal linear scalability without lock contention, he notes that they must eliminate locks entirely.
- In a pthreads reader-writer lock, acquiring the reader handle requires briefly taking an exclusive lock both when acquiring and releasing. - For short critical sections, taking the lock becomes the bottleneck, forcing concurrent threads into sequential execution. - Benchmark results show read throughput scaling modestly with very few threads, but rapidly flatlining as lock contention dominates.
---
[30:27](https://www.youtube.com/watch?v=s19G6n0UjsM&t=1827s) Demystifying `unsafe` in Rust
To eliminate locks, the system must handle aliased, shared pointers without the compiler's built-in locking abstractions. Under normal Rust rules, shared pointers cannot grant mutable access because aliasing creates data races. Working around this requires the `unsafe` keyword. Jon acknowledges the reflexive panic this often induces among developers who assume `unsafe` throws away all language guarantees and reduces Rust to C. He reassures the audience to “please breathe, it will be okay,” explaining that `unsafe` is simply an explicit mechanism allowing operations permitted in C, specifically dereferencing raw pointers.
In safe Rust, references (`&T` and `&mut T`) come with strict lifetime and exclusivity contracts enforced by the compiler. A raw pointer (`*mut T`), by contrast, represents merely an address in memory with no attached lifetime or ownership guarantees; it could point anywhere, including an expired stack frame. The `unsafe` keyword grants the programmer permission to dereference raw pointers or cast them into exclusive references (`&mut T`), asserting an internal invariant that no other thread is concurrently accessing that data. When data races or memory corruption occur, developers know precisely where to audit because safety contracts are only bypassed within delimited `unsafe` blocks.
> “Whenever you type the unsafe keyword, Rust is saying you're now allowed to do the things you're allowed to do in C, there's nothing more or less magical to it.” — Jon Gjengset
- Raw pointers (`*mut T`) denote a memory address without lifetime or exclusivity contracts. - Dereferencing raw pointers or converting a raw pointer into a mutable reference (`&mut T`) requires an `unsafe` block. - `unsafe` isolates manual invariants to specific code sections, drastically narrowing down the regions that need auditing in the event of memory corruption.
---
[33:15](https://www.youtube.com/watch?v=s19G6n0UjsM&t=1995s) Left-Right Concurrency and Epoch Tracking
Jon lays out the design of an alternative lock-free data structure designed for high-throughput reads (the Left-Right pattern). The structure maintains two identical hash maps—a left map and a right map—and two atomic pointers. Readers access maps exclusively via the top read pointer, while writers access maps through the bottom write pointer. Readers initially query the left map while the writer applies updates exclusively to the right map. When the writer wants to publish modifications, it atomically swaps the pointers: incoming readers immediately traverse the updated right map, while the writer applies the modifications to the left map to synchronize both copies.
```mermaid flowchart LR accTitle: Left-Right Dual Map Architecture accDescr: Flow showing readers reading from Map 1 via Read Pointer while Writer modifies Map 2 via Write Pointer before swapping.
subgraph Pointers["Atomic Pointers"] RP["Read Pointer"] WP["Write Pointer"] end
subgraph DataMaps["Internal HashMaps"] M1["Left Map (Map 1)"] M2["Right Map (Map 2)"] end
Readers["Concurrent Readers"] --> RP Writer["Single Writer"] --> WP
RP -.->|"Initially reads"| M1 WP -.->|"Initially writes"| M2 ```
A severe race condition arises if this swap is done naively: readers that began querying the left map prior to the pointer swap may still be actively traversing hash buckets when the writer begins mutating that same left map. Adding locks to detect when readers clear out would destroy read performance, so the architecture turns to epoch counters. Each reader thread maintains an independent, unsynchronized local counter that it increments on map operations. After swapping pointers, the writer observes every reader's epoch counter, waiting until each counter has incremented by at least one tick before touching the old map. Seeing an increment guarantees that a reader finished any in-flight lookup that started before the swap and must read the new pointer for subsequent operations.
However, a remaining flaw exists: an inactive reader thread that holds a handle but performs no queries will never increment its counter, causing the writer to wait indefinitely. Jon explains the solution: incrementing the epoch counter twice per operation—once immediately before beginning the read, and once immediately upon completion. If the writer observes an even epoch value, it knows the reader is completely inactive and holds no references to either map, allowing writes to safely proceed without blocking.
> “If you observe a tick in every reader after you swap the pointer, you know that all of the readers must now have seen the new value, therefore they must all now be in the right map and therefore the writer has exclusive access to the left side.” — Jon Gjengset
- The structure utilizes two internal hash maps and two atomic pointers so writers and readers operate on disjoint maps. - A naive pointer swap risks data races with pre-existing readers still traversing buckets in the old map. - Local, unsynchronized reader epoch counters let the writer verify that readers have observed the pointer swap without using locks. - Readers increment their epoch counters twice (entering on an odd count, exiting on an even count); an even counter signals to the writer that the reader is inactive.
[37:27](https://www.youtube.com/watch?v=s19G6n0UjsM&t=2247s) Benchmarking evmap Against Reader-Writer Locks
Jon Gjengset finishes explaining the mechanics behind the double-buffered lock-free map (`evmap`). The writer only needs to observe two possible states for a reader's epoch value to know it can safely modify or reclaim a buffer: either the reader has incremented the value by one, or the value is even. An even value signifies that the reader is currently outside of the critical section and not examining the map; if it decides to read later, it will inevitably pick up the newly published pointer. Combined, these invariants mean readers and writers never acquire mutual exclusion locks. Read operations stay entirely thread-local, yet both maps remain safely accessible under full concurrency.
```mermaid flowchart TD accTitle: evmap Reader State Evaluation accDescr: Flowchart illustrating how a writer verifies whether a reader can be safely ignored based on its atomic epoch counter.
subgraph WriterCheck["Writer Inspects Reader Epoch"] Check["Examine Reader's Counter"] IsOdd["Counter is Odd?"] Increased["Incremented by 1?"] IsEven["Counter is Even?"] end
subgraph Decision["Safety Decision"] Safe["Safe: Ignore Reader<br/>(Proceed with write/swap)"] Wait["Must Wait / Retry"] end
Check --> IsEven Check --> IsOdd IsEven -->|"Not inside map read"| Safe IsOdd --> Increased Increased -->|"Advanced to current epoch"| Safe Increased -->|"Still reading old epoch"| Wait ```
When comparing this data structure against a standard reader-writer lock (`RwLock`) on identical workloads—swapping maps on every single write without batching or amortization—the throughput differences are striking. While write throughput still slopes downward as reader concurrency scales up (because the writer simply gets scheduled less frequently among competing threads), it outperforms the lock-based approach significantly. But the contrast on reads is so vast that Gjengset has to rescale the y-axis entirely just to keep both on the same slide. As Gjengset quips:
> “Can you see how much it matters to not use locks, right?”
With 16 threads, `evmap` handles 25 million read operations per second. Gjengset points out that this implementation is open-source and published as a documented Rust crate, complete with open benchmarks. The entire library relies on a remarkably tiny footprint of `unsafe`:
- Exactly 7 lines of `unsafe` code exist in the core library, exclusively used when invariants prove exclusive writer access so a raw pointer can be safely cast into a Rust `&mut` reference. - An additional 7 lines of `unsafe` are used for an optional optimization that deduplicates data between the left and right maps rather than storing two distinct complete copies.
---
[40:19](https://www.youtube.com/watch?v=s19G6n0UjsM&t=2419s) Microbenchmarks and Production Lobsters Traces
Moving beyond isolated data-structure tests, Gjengset evaluates `evmap` inside Noria against traditional storage architectures on real-world queries. He begins with a standard vote-aggregation query common to news aggregator sites like Reddit, Hacker News, and Lobsters: counting votes for a specific entity. The benchmark compares MySQL, an unnamed commercial database designated as "System Z" due to vendor benchmarking clause restrictions, a pure memcached instance, and Noria. Memcached does not execute SQL, so it is given an unfair advantage using single-roundtrip multi-increments (`incr`) and multi-gets without persistence.
At the 95th percentile latency threshold, MySQL and System Z collapse early, topping out around 200,000 operations per second. Memcached scales to roughly 7 million operations per second. Noria, despite running a complete SQL execution layer, delivers 14 million operations per second—doubling memcached. Gjengset explains that memcached still acquires internal locks on its hash tables during read operations, whereas Noria reads directly out of an un-locked, cache-materialized `evmap`.
| System Under Test | Approx. Throughput (Vote Count Query) | Operational Characteristics | |:--- |:--- |:--- | | MySQL | ~200,000 ops/sec | Latency spikes early; standard relational execution | | System Z | ~200,000 ops/sec | Protected by strict de-anonymizing benchmark clauses | | memcached | ~7,000,000 ops/sec | In-memory, non-persistent, locks table buckets on reads | | **Noria** | **~14,000,000 ops/sec** | Fully materialized SQL cache backed by lockless `evmap` |
To demonstrate real application behavior rather than synthetic single queries, the team ran an end-to-end trace from Lobsters. Because Lobsters is open source, they collected real production traffic traces and built a workload generator to replay realistic page requests and distributions against a 16-core server. When serving full web page query sets:
- MySQL sustained roughly 1,100 page views per second in initial benchmarks. Gjengset notes that upon correcting a query test where MySQL had accidentally been given an artificially simplified query, its actual throughput dropped further, to around 800 to 900 requests per second. - Noria sustained approximately 5,000 to 6,000 page views per second on the same hardware, proving that combined dynamic caching and lockless materialization deliver massive end-to-end performance gains on realistic workloads.
---
[43:23](https://www.youtube.com/watch?v=s19G6n0UjsM&t=2603s) Learning Rust and Working With the Borrow Checker
Having demonstrated that Noria is a fully functioning, high-throughput system rather than an academic toy, Gjengset turns to the realities of adopting Rust for large software systems. He cautions that newcomers often fail because they assume Rust is just another syntactic flavor of familiar imperative languages:
> “The first thing I want to tell you is Rust is different. You cannot go about learning Rust the same way you learn all these other languages you've learned in the past.”
Its syntax looks comfortable—resembling C, C++, or ML dialects—but treating it like C, Go, or C++ leads straight into an impasse with the borrow checker. Developers unfamiliar with the underlying memory model end up "fighting the borrow checker," shouting at the compiler without understanding why it is rejecting their design.
Gjengset insists that the learning curve is entirely about mastering borrow semantics. Rather than hacking away aimlessly, newcomers should sit down and read *The Rust Programming Language* book cover to cover, a practice rarely required for other languages but essential here. For developers who learn better through executable code, *Rust by Example* covers the same terrain through interactive, runnable samples.
Crucially, developers must learn to treat friction with the compiler as an architectural design signal. When a pattern feels unreasonably difficult, it usually means the developer is attempting an unidiomatic layout. For instance, building a cyclic graph using raw inter-object pointers—a reflex from C—forces complex reference counting or unsafe code in Rust. By contrast, reshaping the graph into a flat vector of nodes referenced by numeric array indices eliminates pointer cycles entirely and satisfies borrow rules without resistance. When compiler friction cannot be diagnosed alone, Gjengset suggests leveraging the community:
- The `#rust` and `#rust-beginners` channels on Mozilla IRC (`irc.mozilla.org`, often referred to as Moznet) provide rapid support. - Questions posted in those IRC channels are frequently answered within five minutes, often directly by Rust core team members.
[46:57](https://www.youtube.com/watch?v=s19G6n0UjsM&t=2817s) Idiomatic Rust, Clippy, and Modular Crates
Jon Gjengset stresses the value of working with the compiler rather than fighting it. If the borrow checker can understand your code, a human teammate is vastly more likely to understand it too. Developers tempted to bypass the borrow checker by sprinkling raw pointers, complex aliasing, and `unsafe` blocks often regret it down the road: “chances are like six months later or three months later when you come back and look at this code you will not understand why you did what you did or what invariants are being enforced by the unsafe and no one else is gonna understand it either.” Avoiding `unsafe` wherever possible yields code that remains comprehensible and maintainable over time.
He encourages newcomers to master the specific idioms and patterns native to Rust. Concepts like iterators introduce functional programming techniques—reminiscent of Haskell or Python generators—that make walking data structures clean and expressive. Other indispensable language features include pattern matching, expressive error handling, and the `?` operator for streamlined error and `None` propagation. To accelerate learning, Gjengset points out an earlier blog post he wrote on these idiomatic patterns and highly recommends Clippy, the official Rust linter: “Clippy is a tool that will take your rust code and tell you all the things you probably shouldn't be doing it's like basically someone wrote a thing that's gonna do peer review for you and it's gonna yell at you for like don't do that don't do that don't do that it's great it's like `go vet` for those who used to go.”
Gjengset also urges developers to break their code into independent crates early and often. Because creating and depending on crates in Rust incurs minimal overhead, splitting projects enforces strict separation of concerns and modular architecture. Beyond modularity, modular crates bring immediate practical benefits: Cargo compiles independent crates in parallel, accelerating build times, and the crate boundary encourages isolated, comprehensive documentation. Developers can enforce this via the language-level compiler attribute `#![deny(missing_docs)]`, which rejects the compilation of any crate containing undocumented public items.
- **Rust Idioms to Adopt:** Iterators for functional traversal, robust pattern matching, and the `?` operator for terse error/null handling. - **Automated Peer Review:** Clippy provides community-driven lints catching anti-patterns before human code review. - **Crate-Driven Architecture:** Breaking large codebases into crates enables modular design, faster parallel builds, and compiler-enforced documentation using `#![deny(missing_docs)]`.
[49:32](https://www.youtube.com/watch?v=s19G6n0UjsM&t=2972s) Compiler-Guided Refactoring and the Crates.io Ecosystem
A standout quality of Rust is the confidence and ease it brings to large-scale refactoring. Thanks to the expressiveness and rigor of the type system, engineers can fearlessly reorganize data structures and move entire chunks of logic around, allowing the compiler errors to act as a step-by-step checklist of necessary updates: “you can do compiler guided refactoring and you can basically trust the compiler this is for those of you program in Haskell in the past is a similar kind of feeling of when it compiles it's probably pretty close to correct.” While semantic logic bugs can still slip through, the type checker catches structural mismatches, missing branches, and memory-safety violations long before runtime.
Gjengset similarly highlights the strength of the Rust packaging and tooling ecosystem. Rust's dependency manager (`cargo`) makes importing and integrating external open-source crates painless. Because formatting via `rustfmt` is widely standardized and documentation on Docs.rs is automatically generated and cross-linked across crates, evaluating and reading third-party code feels seamless. If you publish your own crate, its types automatically link back to its dependencies' documentation. While the ecosystem was still maturing in late 2018, missing components simply offer opportunities to author new libraries for the broader community.
```mermaid flowchart TD accTitle: Compiler-Guided Refactoring Flow accDescr: A cyclical refactoring workflow where type changes prompt compiler errors that guide the developer until the code compiles correctly.
subgraph Refactor["Refactoring Loop"] A["Architectural / Type Changes"] --> B["Run Compiler (`cargo check`)"] B --> C{"Does it compile?"} C -- "No: Compiler reports type/borrow errors" --> D["Address Diagnostics as a Checklist"] D --> B end
C -- "Yes" --> E["Working, High-Confidence Code"] ```
[51:02](https://www.youtube.com/watch?v=s19G6n0UjsM&t=3062s) How the Borrow Checker Rewires a Programmer's Mindset
To conclude his presentation, Gjengset reads a quote reflecting on how Rust fundamentally transforms how engineers reason about concurrency and correctness across all languages:
> “One of the value propositions most frequently lauded by Rust developers is its freedom from data races. The compiler will literally not allow you to build code that could ever produce a situation where two threads can mutate the same data. This teaches us two things: loathing of the Rust compiler and its borrow checker until we make things work, and two, the extent to which we've written unsafe, race-prone code in other languages. I've learned a great deal from that second bullet point. I look back at some of the code I've written in the past and I realized the only reason it worked is because some other library had guardrails in place, or the lack of data races was an accident. In other words, my lack of failure is more attributable to random chance than skill.”
Jon emphasizes how deeply this realization resonated with his personal growth as an engineer: “I really feel like this when writing rusts code now that it has made me a better programmer.” Returning to dynamic or unconstrained systems like Python or C, he now instinctively spots latent concurrency races because he recognizes patterns the Rust compiler would outright reject. When reviewing legacy code written in prior languages, he often concludes that it is likely flawed or fragile, leaving him wishing he had the Rust compiler at hand to pin down exactly what is wrong.
He wraps up the session by summarizing that the talk aimed to bridge low-level implementation details of the Noria database prototype with high-level takeaways about Rust's engineering ergonomics. He opens the floor for questions, offering his contact details via email, Twitter, GitHub, or through the host Larry, followed by applause from the audience.
## Notable quotes > [10:58](https://www.youtube.com/watch?v=s19G6n0UjsM&t=658s) If you just want to write something and not worry about the details, Rust is an awful language for that job because Rust will force you to write correct code. — Jon Gjengset
> [07:11](https://www.youtube.com/watch?v=s19G6n0UjsM&t=431s) In Rust, lots of concurrency bugs are impossible—the compiler will not let you compile a program that has a data race in it — Jon Gjengset
> [30:27](https://www.youtube.com/watch?v=s19G6n0UjsM&t=1827s) Whenever you type the unsafe keyword, Rust is saying you're now allowed to do the things you're allowed to do in C, there's nothing more or less magical to it. — Jon Gjengset
> [43:23](https://www.youtube.com/watch?v=s19G6n0UjsM&t=2603s) The first thing I want to tell you is Rust is different. You cannot go about learning Rust the same way you learn all these other languages you've learned in the past. — Jon Gjengset
## Mentioned Jon Gjengset, Larry Rudolph, Two Sigma, Two Sigma Labs, MIT CSAIL, Parallel and Distributed Operating Systems (PDOS), Noria, Rust, Mozilla, C, C++, Haskell, OCaml, Go, Python, JavaScript, Ruby, Firefox, Cargo, Intel DPDK, GTK, Qt, Win32, macOS Cocoa, Memcached, Redis, Naiad, Apache Spark, POSIX threads (pthreads), Lobsters, MySQL, Reddit, Hacker News, Clippy, Docs.rs, Crates.io
## Video description This is a guest lecture I gave at Two Sigma in November 2018 where I discussed the experience of using Rust for building larger, high-performance systems. In it, I cover what makes Rust an attractive option for such projects; Noria, the high-performance research database prototype I've built using Rust; an interesting concurrent data-structure we use in Noria; and how I've found Rust to work in that context.
The presentation slides are available at https://jon.thesquareplanet.com/slides/rust-twosigma/ . You can read more about Noria at https://pdos.csail.mit.edu/noria .
[Source](https://www.youtube.com/watch?v=s19G6n0UjsM)