<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://www.garillot.net/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.garillot.net/" rel="alternate" type="text/html" /><updated>2026-04-25T07:18:17-07:00</updated><id>https://www.garillot.net/feed.xml</id><title type="html">François Garillot</title><subtitle>François Garillot is a lead engineer at Miden since 2025, focused on zero-knowledge proofs, cryptography, distributed systems, and blockchain infrastructure.</subtitle><author><name>François Garillot</name></author><entry><title type="html">Drilling down on Rust Performance Bottlenecks with tokio-tracing and texray</title><link href="https://www.garillot.net/posts/2025/04/drilling-down-texray/" rel="alternate" type="text/html" title="Drilling down on Rust Performance Bottlenecks with tokio-tracing and texray" /><published>2025-04-28T00:00:00-07:00</published><updated>2025-04-28T00:00:00-07:00</updated><id>https://www.garillot.net/posts/2025/04/drilling-down-texray</id><content type="html" xml:base="https://www.garillot.net/posts/2025/04/drilling-down-texray/"><![CDATA[<p>When a Rust program feels sluggish, adding instrumentation can shine a light on <em>where</em> the time is going. In this post, we’ll walk through a guided journey of using Tokio’s <code class="language-plaintext highlighter-rouge">tracing</code> framework and the <code class="language-plaintext highlighter-rouge">tracing-texray</code> tool to drill into performance issues. We assume you’re familiar with the basics of <code class="language-plaintext highlighter-rouge">tokio-tracing</code> (if not, see the <a href="https://tokio.rs/tokio/topics/tracing#:~:text=In%20asynchronous%20systems%20like%20Tokio%2C,tracing">Tokio tracing introduction</a> for spans and events fundamentals). Our journey will start with a simple sequential task, then ramp up to parallel execution and illustrate how to maintain insight at each step.</p>

<h2 id="setting-the-stage-a-sequential-file-reader">Setting the Stage: A Sequential File Reader</h2>

<p>Imagine we have a Rust program that reads a list of files one by one. Perhaps it’s processing log files or loading data at startup. For this example, we’ll use a mock scenario of reading a few files from disk sequentially. Here’s a simplified version of the code without any instrumentation:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="n">fs</span><span class="p">;</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">files</span> <span class="o">=</span> <span class="nd">vec!</span><span class="p">[</span><span class="s">"small.txt"</span><span class="p">,</span> <span class="s">"medium.txt"</span><span class="p">,</span> <span class="s">"large.txt"</span><span class="p">,</span> <span class="s">"huge.txt"</span><span class="p">];</span>
    <span class="k">for</span> <span class="n">file</span> <span class="k">in</span> <span class="n">files</span> <span class="p">{</span>
        <span class="c1">// Read the entire file</span>
        <span class="k">let</span> <span class="n">_data</span> <span class="o">=</span> <span class="nn">fs</span><span class="p">::</span><span class="nf">read_to_string</span><span class="p">(</span><span class="n">file</span><span class="p">)</span>
            <span class="nf">.expect</span><span class="p">(</span><span class="s">"Failed to read file"</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This code will successfully read the files, but if the overall operation is slow, we have no visibility into which file or step is the culprit. We could measure the total execution time, but that wouldn’t tell us <em>which file</em> took most of the time. We need more granular insight.</p>

<h2 id="instrumenting-with-spans-for-insight">Instrumenting with Spans for Insight</h2>

<p>To get visibility, we’ll instrument the code using <strong><code class="language-plaintext highlighter-rouge">tracing</code> spans</strong>. A span represents a period of time in the program (it has a start and end) and can carry contextual information. By placing spans around regions of interest (like our file-read loop and each file read), we can collect timing data. We’ll use <strong>Tokio’s <code class="language-plaintext highlighter-rouge">tracing</code></strong> crate to create spans and <strong><code class="language-plaintext highlighter-rouge">tracing-texray</code></strong> as a subscriber to visualize them.</p>

<p>First, we set up <a href="https://github.com/rcoh/tracing-texray"><code class="language-plaintext highlighter-rouge">tracing-texray</code></a> as our global tracing subscriber. <code class="language-plaintext highlighter-rouge">tracing-texray</code> is a tracing layer that outputs a plaintext timeline of spans and events. It stays dormant until we mark a span to examine, then prints the span’s entire subtree when that span completes. In our code, we call <code class="language-plaintext highlighter-rouge">tracing_texray::init()</code> to initialize it, and then wrap our code in an <code class="language-plaintext highlighter-rouge">examine</code> span. Let’s add an outer span for the whole file-reading loop:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">use</span> <span class="nn">tracing_texray</span><span class="p">::</span><span class="n">examine</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">tracing</span><span class="p">::{</span><span class="n">info_span</span><span class="p">,</span> <span class="n">Span</span><span class="p">};</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="nn">tracing_texray</span><span class="p">::</span><span class="nf">init</span><span class="p">();</span> <span class="c1">// Initialize `texray` as the global subscriber</span>
    <span class="k">let</span> <span class="n">files</span> <span class="o">=</span> <span class="nd">vec!</span><span class="p">[</span><span class="s">"small.txt"</span><span class="p">,</span> <span class="s">"medium.txt"</span><span class="p">,</span> <span class="s">"large.txt"</span><span class="p">,</span> <span class="s">"huge.txt"</span><span class="p">];</span>

    <span class="c1">// Examine the root span for the entire operation</span>
    <span class="nf">examine</span><span class="p">(</span><span class="nd">info_span!</span><span class="p">(</span><span class="s">"process_files"</span><span class="p">))</span><span class="nf">.in_scope</span><span class="p">(||</span> <span class="p">{</span>
        <span class="k">for</span> <span class="n">file</span> <span class="k">in</span> <span class="o">&amp;</span><span class="n">files</span> <span class="p">{</span>
            <span class="c1">// Create a child span with file name, and enter its scope</span>
            <span class="k">let</span> <span class="n">span</span> <span class="o">=</span> <span class="nd">info_span!</span><span class="p">(</span><span class="s">"read_file"</span><span class="p">,</span> <span class="n">file</span> <span class="o">=</span> <span class="o">%</span><span class="n">file</span><span class="p">);</span>
            <span class="n">span</span><span class="nf">.in_scope</span><span class="p">(||</span> <span class="p">{</span>
                <span class="k">let</span> <span class="n">contents</span> <span class="o">=</span> <span class="nn">std</span><span class="p">::</span><span class="nn">fs</span><span class="p">::</span><span class="nf">read_to_string</span><span class="p">(</span><span class="n">file</span><span class="p">)</span>
                    <span class="nf">.expect</span><span class="p">(</span><span class="s">"Failed to read file"</span><span class="p">);</span>
                <span class="c1">// (Use contents if needed to avoid compiler optimizations)</span>
                <span class="nd">println!</span><span class="p">(</span><span class="s">"Read {} bytes from {}"</span><span class="p">,</span> <span class="n">contents</span><span class="nf">.len</span><span class="p">(),</span> <span class="n">file</span><span class="p">);</span>
            <span class="p">});</span>
        <span class="p">}</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>When running this program, <code class="language-plaintext highlighter-rouge">texray</code> prints a timeline to <code class="language-plaintext highlighter-rouge">stderr</code> when the <code class="language-plaintext highlighter-rouge">"process_files"</code> span completes. The output timeline for <strong>Example 1</strong> (sequential read) might look like this:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== Example 1: Sequential File Reading ===
read_files                     728μs ├─────────────────────────────────────────────────┤
  read_file{file: small.txt}    39μs    ├─┤
  read_file{file: medium.txt}   27μs       ├┤
  read_file{file: large.txt}    58μs         ├──┤
  read_file{file: huge.txt}    535μs              ├───────────────────────────────────┤
</code></pre></div></div>

<p>Here, the top-level span <strong>process_files</strong> took 728μs in total. Each <code class="language-plaintext highlighter-rouge">read_file{file: ...}</code> line is a child span showing how long it took to read that specific file. Because the files were read sequentially, their timeline bars appear one after another (no overlaps). For instance, <code class="language-plaintext highlighter-rouge">small.txt</code> took 39μs, then <code class="language-plaintext highlighter-rouge">medium.txt</code> took 27μs, and so on. The ASCII bars give a visual sense of timing: each bar’s length corresponds to its duration, and since these reads happened back-to-back, the bars are placed end-to-end.</p>

<p>At this point, we’ve used <code class="language-plaintext highlighter-rouge">tracing-texray</code> to pinpoint which file(s) are slow. In a real scenario, this insight might prompt us to investigate why <code class="language-plaintext highlighter-rouge">huge.txt</code> is slow (perhaps it’s larger or on a slower disk). It might also prompt us to consider optimizations, such as reading files in parallel to reduce overall time. Let’s try that next.</p>

<h2 id="parallelizing-with-rayon-for-speed">Parallelizing with Rayon for Speed</h2>

<p>Knowing that one file dominates the timeline, a natural approach (for this contrived example) is to read the files in parallel. We can use the <strong>Rayon</strong> crate for data parallelism. <strong>Rayon</strong> makes it easy to convert sequential iterators into parallel iterators, safely distributing work across threads (<a href="https://docs.rs/rayon/latest/rayon/">rayon - Rust</a>). For our file reader, switching to Rayon is straightforward: we replace the sequential loop with Rayon’s <code class="language-plaintext highlighter-rouge">par_iter()</code> over the file list.</p>

<p>First, ensure we add Rayon to our dependencies. Then our code becomes:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">use</span> <span class="nn">rayon</span><span class="p">::</span><span class="nn">prelude</span><span class="p">::</span><span class="o">*</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">tracing_texray</span><span class="p">::</span><span class="n">examine</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">tracing</span><span class="p">::</span><span class="n">info_span</span><span class="p">;</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="nn">tracing_texray</span><span class="p">::</span><span class="nf">init</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">files</span> <span class="o">=</span> <span class="nd">vec!</span><span class="p">[</span><span class="s">"small.txt"</span><span class="p">,</span> <span class="s">"medium.txt"</span><span class="p">,</span> <span class="s">"large.txt"</span><span class="p">,</span> <span class="s">"huge.txt"</span><span class="p">];</span>

    <span class="c1">// Examine the root span for parallel processing</span>
    <span class="nf">examine</span><span class="p">(</span><span class="nd">info_span!</span><span class="p">(</span><span class="s">"process_files"</span><span class="p">))</span><span class="nf">.in_scope</span><span class="p">(||</span> <span class="p">{</span>
        <span class="c1">// Parallel iteration over files</span>
        <span class="n">files</span><span class="nf">.par_iter</span><span class="p">()</span><span class="nf">.for_each</span><span class="p">(|</span><span class="n">file</span><span class="p">|</span> <span class="p">{</span>
            <span class="k">let</span> <span class="n">span</span> <span class="o">=</span> <span class="nd">info_span!</span><span class="p">(</span><span class="s">"read_file"</span><span class="p">,</span> <span class="n">file</span> <span class="o">=</span> <span class="o">%</span><span class="n">file</span><span class="p">);</span>
            <span class="n">span</span><span class="nf">.in_scope</span><span class="p">(||</span> <span class="p">{</span>
                <span class="k">let</span> <span class="n">contents</span> <span class="o">=</span> <span class="nn">std</span><span class="p">::</span><span class="nn">fs</span><span class="p">::</span><span class="nf">read_to_string</span><span class="p">(</span><span class="n">file</span><span class="p">)</span>
                    <span class="nf">.expect</span><span class="p">(</span><span class="s">"Failed to read file"</span><span class="p">);</span>
                <span class="nd">println!</span><span class="p">(</span><span class="s">"Read {} bytes from {}"</span><span class="p">,</span> <span class="n">contents</span><span class="nf">.len</span><span class="p">(),</span> <span class="n">file</span><span class="p">);</span>
            <span class="p">});</span>
        <span class="p">});</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>With these small changes, our program will read files in parallel. If we run this, we should see a significant speed-up in total execution time.</p>

<p>However, when we check the <code class="language-plaintext highlighter-rouge">tracing-texray</code> output now, we encounter a problem: <strong>the timeline is not showing the inner <code class="language-plaintext highlighter-rouge">read_file</code> spans at all under the <code class="language-plaintext highlighter-rouge">read_files</code> span.</strong> In fact, you might only see the outer <code class="language-plaintext highlighter-rouge">read_files</code> span with no children, or the output might be missing details of the file reads. What happened to our nice breakdown?</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== Example 2: Rayon Parallel File Reading ===
read_files  619μs ├────────────────────────────────────────────────────────────────────┤
</code></pre></div></div>

<p>Where did the child spans go? We only see the top-level span <strong>process_files</strong> (taking about 61ms total) and no <code class="language-plaintext highlighter-rouge">read_file</code> spans underneath it. This happens because the spans created inside Rayon threads are not being recorded as children of the examined span. The <code class="language-plaintext highlighter-rouge">tracing</code> context (which carries the parent span) isn’t automatically propagated to new threads spawned by Rayon’s thread pool. As a result, <code class="language-plaintext highlighter-rouge">texray</code> doesn’t realize those <code class="language-plaintext highlighter-rouge">"read_file"</code> spans are part of <strong>process_files</strong>, and so it omits them from the timeline. We end up with a single flat span indicating the total time for processing all files in parallel, but without any breakdown per file.</p>

<p>In other words, the parallel file reads did happen (the total time dropped to ~619μs, roughly the duration of the slowest file), but <code class="language-plaintext highlighter-rouge">texray</code> couldn’t trace the inner spans across threads. This can make debugging parallel operations tricky, since we lose visibility into the concurrent tasks.</p>
<h2 id="the-challenge-tracing-spans-across-threads">The Challenge: Tracing Spans Across Threads</h2>

<p>The missing spans are a result of how tracing contexts propagate (or rather, don’t propagate) across threads. By default, a span entered on one thread isn’t automatically carried into work happening on other threads. In our parallel code, we start the <code class="language-plaintext highlighter-rouge">"read_files"</code> span on the main thread, but the file reading happens on Rayon’s thread pool threads. Those threads create new <code class="language-plaintext highlighter-rouge">"read_file"</code> spans, yet they don’t inherit the parent span context. In other words, the child spans are <strong>disconnected</strong> from the parent.</p>

<p>This behavior is a known aspect of <code class="language-plaintext highlighter-rouge">tracing</code>. The core tracing library doesn’t <em>implicitly</em> track spans across thread or task boundaries (<a href="https://github.com/tokio-rs/tokio/discussions/6008#discussioncomment-7005633">tasks</a><a href="https://github.com/tokio-rs/tracing/issues/1188">threads</a>). If we want a span’s context to continue on another thread, we have to do it manually. If we want tracing to embed spans properly, the recommendation is to pass the span handle to the new thread or task and enter it there. In our case, that would mean capturing the <code class="language-plaintext highlighter-rouge">"read_files"</code> span and inside the <code class="language-plaintext highlighter-rouge">par_iter</code> closure. This would explicitly re-establish the parent context on each worker thread.</p>

<p>Doing this by hand is possible, but it’s a bit tricky and adds extra complexity to our nicely abstracted Rayon loop. We’d rather not mess with manually managing span guards in every thread. So, how can we regain our tracing insight without abandoning Rayon or significantly complicating our code?</p>

<h2 id="a-workaround-using-maybe-rayon-for-consistent-traces">A Workaround: Using <code class="language-plaintext highlighter-rouge">maybe-rayon</code> for Consistent Traces</h2>

<p>One way to regain that visibility is to run the tasks on a single thread (so that span context is preserved), while still keeping the option to use multiple threads when we need raw speed. This is where <strong>p3-maybe-rayon</strong> comes in. The <strong>p3-maybe-rayon</strong> crate (a modern alternative to the now-abandoned <em>maybe-rayon</em> crate) is a feature-gated wrapper around Rayon. It can act as Rayon (parallel) or as a single-threaded facade​ depending on a compile-time feature flag, allowing us to easily toggle parallelism.</p>

<p>We replace Rayon’s import with <code class="language-plaintext highlighter-rouge">p3_maybe_rayon::prelude::*</code> and use the same <code class="language-plaintext highlighter-rouge">par_iter()</code> code:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">use</span> <span class="nn">p3_maybe_rayon</span><span class="p">::</span><span class="nn">prelude</span><span class="p">::</span><span class="o">*</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">tracing_texray</span><span class="p">::</span><span class="n">examine</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">tracing</span><span class="p">::</span><span class="n">info_span</span><span class="p">;</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="nn">tracing_texray</span><span class="p">::</span><span class="nf">init</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">files</span> <span class="o">=</span> <span class="nd">vec!</span><span class="p">[</span><span class="s">"small.txt"</span><span class="p">,</span> <span class="s">"medium.txt"</span><span class="p">,</span> <span class="s">"large.txt"</span><span class="p">,</span> <span class="s">"huge.txt"</span><span class="p">];</span>

    <span class="c1">// Examine the root span (using maybe-rayon for optional parallelism)</span>
    <span class="nf">examine</span><span class="p">(</span><span class="nd">info_span!</span><span class="p">(</span><span class="s">"process_files"</span><span class="p">))</span><span class="nf">.in_scope</span><span class="p">(||</span> <span class="p">{</span>
        <span class="n">files</span><span class="nf">.par_iter</span><span class="p">()</span><span class="nf">.for_each</span><span class="p">(|</span><span class="n">file</span><span class="p">|</span> <span class="p">{</span>
            <span class="k">let</span> <span class="n">span</span> <span class="o">=</span> <span class="nd">info_span!</span><span class="p">(</span><span class="s">"read_file"</span><span class="p">,</span> <span class="n">file</span> <span class="o">=</span> <span class="o">%</span><span class="n">file</span><span class="p">);</span>
            <span class="n">span</span><span class="nf">.in_scope</span><span class="p">(||</span> <span class="p">{</span>
                <span class="k">let</span> <span class="n">contents</span> <span class="o">=</span> <span class="nn">std</span><span class="p">::</span><span class="nn">fs</span><span class="p">::</span><span class="nf">read_to_string</span><span class="p">(</span><span class="n">file</span><span class="p">)</span>
                    <span class="nf">.expect</span><span class="p">(</span><span class="s">"Failed to read file"</span><span class="p">);</span>
                <span class="nd">println!</span><span class="p">(</span><span class="s">"Read {} bytes from {}"</span><span class="p">,</span> <span class="n">contents</span><span class="nf">.len</span><span class="p">(),</span> <span class="n">file</span><span class="p">);</span>
            <span class="p">});</span>
        <span class="p">});</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>
<p>If we run this with the <strong>parallel feature turned off</strong> (by not passing the <code class="language-plaintext highlighter-rouge">"parallel"</code> feature to <code class="language-plaintext highlighter-rouge">p3-maybe-rayon</code>, so that <code class="language-plaintext highlighter-rouge">par_iter()</code> actually runs sequentially on the current thread), <code class="language-plaintext highlighter-rouge">texray</code> will be able to capture all the file-reading spans just like in the purely sequential Example 1. The <strong>Example 3</strong> output shows the nested spans properly:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== Example 3: Maybe-rayon for Debugging ===
read_files                     846μs ├─────────────────────────────────────────────────┤
  read_file{file: small.txt}    42μs  ├─┤
  read_file{file: medium.txt}   26μs     ├┤
  read_file{file: large.txt}    35μs       ├┤
  read_file{file: huge.txt}    698μs          ├────────────────────────────────────────┤
</code></pre></div></div>

<h2 id="wrapping-up">Wrapping Up</h2>

<p>All the code for this post is available at <a href="https://github.com/huitseeker/texray-demo"><code class="language-plaintext highlighter-rouge">https://github.com/huitseeker/texray-demo</code></a>.</p>

<p>Using <code class="language-plaintext highlighter-rouge">tracing-texray</code> we visualized the execution of reading multiple files under different modes. In sequential mode, <code class="language-plaintext highlighter-rouge">texray</code> clearly showed each file read span and how long it took relative to the others. With naive Rayon-based parallelism, the timeline lost detail due to span context not carrying over to new threads. By using the <strong>p3-maybe-rayon</strong> crate (essentially running the tasks serially for tracing purposes), we regained the detailed breakdown.</p>

<blockquote>
  <p><strong>Note:</strong> If we enable parallelism in p3-maybe-rayon (making it use Rayon internally), we would again face the same issue as Example 2 – the spans would execute on worker threads without the parent context, and <code class="language-plaintext highlighter-rouge">texray</code>’s output would look empty like before. The crate doesn’t magically propagate tracing contexts for us; it simply gives the flexibility to switch between parallel and serial execution. In a real application, to trace multi-threaded spans properly, we might need to propagate the span context manually or use tracing facilities that support cross-thread span relationships.</p>
</blockquote>

<p><code class="language-plaintext highlighter-rouge">texray</code> proved useful for quickly understanding the performance characteristics of our code. We saw which file was the slowest and how the total time was distributed among tasks. When writing parallel code, tools like <code class="language-plaintext highlighter-rouge">texray</code> can help ensure that we don’t sacrifice observability for speed. And with crates like <code class="language-plaintext highlighter-rouge">p3-maybe-rayon</code>, we have the option to turn off parallelism when debugging, giving us the best of both worlds: clarity during development and concurrency in production.</p>]]></content><author><name>François Garillot</name></author><category term="tracing" /><category term="rust" /><summary type="html"><![CDATA[When a Rust program feels sluggish, adding instrumentation can shine a light on where the time is going. In this post, we’ll walk through a guided journey of using Tokio’s tracing framework and the tracing-texray tool to drill into performance issues. We assume you’re familiar with the basics of tokio-tracing (if not, see the Tokio tracing introduction for spans and events fundamentals). Our journey will start with a simple sequential task, then ramp up to parallel execution and illustrate how to maintain insight at each step.]]></summary></entry><entry><title type="html">Byzantine-Consistent Broadcast- A Promising Yet Challenging Frontier in Digital Asset Transfers</title><link href="https://www.garillot.net/posts/2025/03/bcb-promises-challenges/" rel="alternate" type="text/html" title="Byzantine-Consistent Broadcast- A Promising Yet Challenging Frontier in Digital Asset Transfers" /><published>2025-03-31T00:00:00-07:00</published><updated>2025-03-31T00:00:00-07:00</updated><id>https://www.garillot.net/posts/2025/03/bcb-promises-challenges</id><content type="html" xml:base="https://www.garillot.net/posts/2025/03/bcb-promises-challenges/"><![CDATA[<p>Digital asset transfer systems are at a crossroads. An idea that first captured attention between 2020 and 2022—Byzantine Consistent Broadcast (BCB)—is now experiencing a revival with projects like <a href="https://arxiv.org/abs/2501.14931">Pod</a> and <a href="https://cdn.prod.website-files.com/66e2c06b9d2650e91a88b6b1/6706852b548dcdb6540a9c92_litepaper.pdf">Delta</a>. In this post, we to show that while BCB can unlock incredible performance through parallel state execution, it also introduces important challenges, especially around expressivity and the scalability of reads. The goal is to explain why this approach is both exciting and demanding.</p>

<h2 id="the-rise-and-revival-of-byzantine-consistent-broadcast">The Rise and Revival of Byzantine Consistent Broadcast</h2>

<p>BCB is not just a technical detail—it is rooted in powerful distributed systems theory. The <strong>CALM Conjecture</strong> (Consistency As Logical Monotonicity) was introduced by Hellerstein in 2010 and later formalized by Ameloot et al. in 2011 (<a href="https://doi.org/10.1145/1989284.1989321">paper</a>). CALM tells us that distributed systems can be consistent without coordination, provided that decisions (or state changes) are never retracted. This insight was reignited in 2019 by Peter Alvaro’s work (<a href="https://arxiv.org/abs/1901.01930">paper</a>), sparking a wave of interest among blockchain researchers.</p>

<p>Between 2020 and 2022, projects like <a href="https://arxiv.org/pdf/2003.11506">FastPay</a>, <a href="https://linera.io/whitepaper">Linera</a>, and <a href="https://arxiv.org/abs/2310.18042">Sui</a> embraced these ideas, showing that BCB protocols can enable systems where each transaction works on its own independent piece of state. Today, with the emergence of <a href="https://arxiv.org/abs/2501.14931">Pod</a> and <a href="https://cdn.prod.website-files.com/66e2c06b9d2650e91a88b6b1/6706852b548dcdb6540a9c92_litepaper.pdf">Delta</a>, the approach is back and demands our attention.</p>

<h2 id="unlocking-parallelism-with-independent-state">Unlocking Parallelism with Independent State</h2>

<p>The core strength of BCB-based protocols lies in their ability to execute transactions in parallel. By forcing digital asset systems to adopt a model where each account or piece of state is fully independently owned, these systems remove the need for global coordination. This design has two major implications:</p>

<ul>
  <li>
    <p><strong>No Shared State:</strong> Every transaction operates on its own shard of data. Validators check that the “debits” (the existing state) are valid without the need to sequence every “credit” (new state addition) immediately. This results in linear communication complexity versus the quadratic worst-case overhead seen in traditional Byzantine consensus algorithms.</p>
  </li>
  <li>
    <p><strong>Parallel Execution:</strong> Crucially, BCB protocols don’t inherently eliminate state contention—their semantics require designers to adopt a state model that avoids contention altogether. Thus, the real source of parallelism and speed is the explicit design choice of independently-owned, minimally-contended state. But by encouraging this choice, these protocols push in an important direction, that could finally melt the execution bottleneck that has long plagued blockchain systems.</p>
  </li>
</ul>

<p>The performance potential here is enormous. With fewer delays and more parallelism, blockchains can process many transactions at once—making systems like <a href="https://arxiv.org/abs/2310.18042">Sui Lutris</a> and <a href="https://linera.io/whitepaper">Linera</a> prime examples of how to harness this power.</p>

<h2 id="the-challenges-expressivity-atomicity-and-read-scalability">The Challenges: Expressivity, Atomicity, and Read Scalability</h2>

<p>However, with great promise come significant challenges:</p>

<h3 id="limited-expressivity-and-complex-atomicity">Limited Expressivity and Complex Atomicity</h3>

<p>BCB-based blockchains have realized that state contention is inevitable, so they must offer a programming model that addresses it. There are two main strategies. One strategy uses built-in concurrency primitives—like the CRDTs employed by <a href="https://cdn.prod.website-files.com/66e2c06b9d2650e91a88b6b1/6706852b548dcdb6540a9c92_litepaper.pdf">Delta</a> or the actor model powered by asynchronous explicit cross-chain messaging in <a href="https://linera.io/whitepaper">Linera</a>. These models assume that most operations occur concurrently, allowing the system to operate on sharded, independently owned state without heavy coordination.</p>

<p>The alternative strategy abandons the sharded, parallel model for a more centralized approach to handling state contention by relying on a consensus algorithm. This is the method adopted by <a href="https://arxiv.org/abs/2310.18042">Sui</a> since its Sui-Lutris design.</p>

<p>The choice between these approaches is not straightforward. Research, including the <a href="https://doi.org/10.1007/s10664-019-09796-5">Oliva et al. (2020)</a>, indicates that blockchains frequently encounter state contention. If most use cases demand robust management of state contention, then designing a system solely for parallel execution might be less beneficial than one that effectively leverages consensus.</p>

<p>Ultimately, this is less about raw technical capability and more about product design: we must align our blockchain architectures with how users actually interact with state, ensuring that the chosen model meets real-world demands.</p>

<h3 id="the-read-path-bottleneck">The Read Path Bottleneck</h3>

<p>One of the most critical challenges for BCB is ensuring reliable and scalable reads:</p>

<ul>
  <li>
    <p><strong>Complexity of Reads:</strong> In consensus-based blockchains, clients can verify state using simple cryptographic proofs, such as Merkle proofs. In contrast, BCB-based systems require clients to query multiple validators. This is because the state is managed in an eventually consistent manner, and eventually consistent protocols by nature do not address censorship: they can’t see daylight between a censoring node and one that’s simply late in receiving data —validators guarantee “nothing but the truth,” but not “the whole truth.” In order to get “the whole truth”, the client must query a large fraction of the validators, relying on Byzantine Fault Tolerance assumptions of a honest super-majority — they cannot request that data from any other actor.</p>
  </li>
  <li>
    <p><strong>Scalability Issues:</strong> This multi-node querying increases latency and puts a heavy burden on every validator to handle a large fraction of global read requests. Unlike consensus systems where full nodes can easily serve delegated read responsibilities, BCB systems force every validator to directly serve client queries, creating a bottleneck that hampers scalability.</p>
  </li>
</ul>

<h2 id="hybrid-approaches-striking-the-right-balance">Hybrid Approaches: Striking the Right Balance</h2>

<p>The challenges of expressivity and read scalability do not spell doom for BCB protocols. In fact, many projects are exploring hybrid models that combine the best of both worlds:</p>

<ul>
  <li><strong>Periodic Consensus Checkpoints:</strong> Systems like <a href="https://arxiv.org/abs/2310.18042">Sui</a> and <a href="https://linera.io/whitepaper">Linera</a> integrate periodic consensus steps or asynchronous messaging to handle shared-state operations.</li>
  <li><strong>Timestamping and Cross-Validation:</strong> <a href="https://arxiv.org/abs/2501.14931">Pod</a> uses timestamp-based ordering to help align state across validators, offering a path toward more scalable reads, along with an optimistic approach and a read-oriented fraud proof mechanism. This is certainly interesting, though the jury’s still out on whether this will be enough to solve the <a href="https://medium.com/offchainlabs/cheater-checking-how-attention-challenges-solve-the-verifiers-dilemma-681a92d9948e">verifier’s dilemma</a> inherent in this setup.</li>
</ul>

<p>These hybrid approaches suggest that it is possible to make progress on enjoying the benefits of BCB-driven parallelism while mitigating the downsides. They encourage us to think creatively about blending broadcast protocols with consensus mechanisms to build systems that are both fast and robust.</p>

<h2 id="why-this-matters-a-call-to-action">Why This Matters: A Call to Action</h2>

<p>Embracing Byzantine-Consistent Broadcast protocols is not just a technical choice—it is a call for a new way of thinking about digital asset transfers. The BCB approach challenges us to break free from the limitations of traditional blockchains by designing systems that maximize parallelism and performance. However, it also reminds us that every gain comes with trade-offs in expressivity and read scalability.</p>

<p>Byzantine-Consistent Broadcast protocols offer a vision rooted in a more parallel, efficient blockchain world. Yet, they bring significant challenges in expressivity, and especially in the scalability of reads. Both early projects from 2020–2022 and the new wave from 2024–2025 teach us that while the performance potential is enticing, careful system design is crucial. The balance between innovation and practicality will define the next generation of digital asset transfer systems.</p>

<hr />

<h2 id="references">References</h2>

<ol>
  <li><a href="https://doi.org/10.1145/1989284.1989321">Ameloot et al. (2011)</a></li>
  <li><a href="https://arxiv.org/abs/1901.01930">Alvaro et al. (2019)</a></li>
  <li><a href="https://doi.org/10.1007/s00446-021-00406-8">Guerraoui et al. (2022)</a></li>
  <li><a href="https://arxiv.org/abs/1905.11360">Wattenhofer &amp; Wang (2020)</a></li>
  <li><a href="https://arxiv.org/abs/1905.11360">Danezis et al. (2019)</a></li>
  <li><a href="https://arxiv.org/abs/2310.18042">Sui Lutris (2023)</a></li>
  <li><a href="https://arxiv.org/abs/2310.14821">Mysticeti (2023)</a></li>
  <li><a href="https://linera.io/whitepaper">Linera Whitepaper (2023)</a></li>
  <li><a href="https://arxiv.org/abs/2501.14931">Pod (2025)</a></li>
  <li><a href="https://cdn.prod.website-files.com/66e2c06b9d2650e91a88b6b1/6706852b548dcdb6540a9c92_litepaper.pdf">Delta Litepaper (2024)</a></li>
  <li><a href="https://doi.org/10.1007/s10664-019-09796-5">Ethereum Smart Contracts Study (2020)</a></li>
</ol>]]></content><author><name>François Garillot</name></author><category term="bcb" /><category term="consensus" /><summary type="html"><![CDATA[Digital asset transfer systems are at a crossroads. An idea that first captured attention between 2020 and 2022—Byzantine Consistent Broadcast (BCB)—is now experiencing a revival with projects like Pod and Delta. In this post, we to show that while BCB can unlock incredible performance through parallel state execution, it also introduces important challenges, especially around expressivity and the scalability of reads. The goal is to explain why this approach is both exciting and demanding.]]></summary></entry><entry><title type="html">PSA: maven central and sonatype are slow</title><link href="https://www.garillot.net/posts/2017/07/psa-mvn-nexus/" rel="alternate" type="text/html" title="PSA: maven central and sonatype are slow" /><published>2017-07-27T00:00:00-07:00</published><updated>2017-07-27T00:00:00-07:00</updated><id>https://www.garillot.net/posts/2017/07/PSA-maven-sonatype-slow</id><content type="html" xml:base="https://www.garillot.net/posts/2017/07/psa-mvn-nexus/"><![CDATA[<p>Most of the public maven repositories for downloading java artifacts (notably maven-central, and sonatype) are slow. Besides, build tools do not have a perfect track record of resolving dependencies from these repositories in an efficient manner.</p>

<p>A consequence of that is that if you are not sitting on a T1 or better connection and building from pure repos (sonatype, maven-central), rather than using a proxy, you are wasting your time waiting for the network on each build. This takes 15 mins to fix, forever:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">docker pull sonatype/nexus</code></li>
  <li><code class="language-plaintext highlighter-rouge">docker run -d -p 8081:8081 --name nexus -v /mnt/nexus-data:/nexus-data --restart unless-stopped sonatype/nexus3</code></li>
  <li>go to http://localhost:8081, login, configure two proxies for maven-central and sonatype, expose them through a group called public.</li>
  <li>in your local <code class="language-plaintext highlighter-rouge">.m2/settings.xml</code>, add:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;mirrors&gt;

  &lt;mirror&gt;`

    &lt;id&gt;local-public&lt;/id&gt;`

    &lt;mirrorof&gt;external:*&lt;/mirrorof&gt;

    &lt;name&gt;Local Mirror.&lt;/name&gt;

    &lt;url&gt;http://localhost:8081/repository/public/&lt;/url&gt;

  &lt;/mirror&gt;
&lt;/mirrors&gt;
</code></pre></div></div>]]></content><author><name>François Garillot</name></author><category term="maven" /><category term="xml" /><category term="nexus" /><summary type="html"><![CDATA[Most of the public maven repositories for downloading java artifacts (notably maven-central, and sonatype) are slow. Besides, build tools do not have a perfect track record of resolving dependencies from these repositories in an efficient manner.]]></summary></entry><entry><title type="html">A June 2016 roundup of distributed Deep Learning projects on Apache Spark</title><link href="https://www.garillot.net/posts/2016/06/june-roundup-deep-learning/" rel="alternate" type="text/html" title="A June 2016 roundup of distributed Deep Learning projects on Apache Spark" /><published>2016-06-28T00:00:00-07:00</published><updated>2016-06-28T00:00:00-07:00</updated><id>https://www.garillot.net/posts/2016/06/june-roundup-deep-learning</id><content type="html" xml:base="https://www.garillot.net/posts/2016/06/june-roundup-deep-learning/"><![CDATA[<p>Here’s a quick roundup of distributed deep learning efforts running on Apache Spark. This will only list active(-ish) projects rather than academic experiments (of which there are too many to list) There’s roughly two approaches:</p>

<h2 id="linking-spark-with-an-existing-framework">Linking Spark with an existing framework</h2>

<ul>
  <li><a href="https://github.com/amplab/SparkNet">SparkNet</a> from UC berkeley connects Apache Spark with <a href="http://caffe.berkeleyvision.org/">Caffe</a>. You can read <a href="https://arxiv.org/abs/1511.06051">the paper</a></li>
  <li><a href="https://github.com/yahoo/CaffeOnSpark">CaffeOnSpark</a> from Yahoo takes the same approach, see the <a href="http://yahoohadoop.tumblr.com/post/139916563586/caffeonspark-open-sourced-for-distributed-deep">blog post</a>.</li>
  <li>Arimo <a href="https://arimo.com/machine-learning/deep-learning/2016/arimo-distributed-tensorflow-on-spark/">distributed TensorFlow on Spark</a> for hyper-parameter tuninig, but that was before the release of the distributed version. Here’s a <a href="https://spark-summit.org/east-2016/events/distributed-tensor-flow-on-spark-scaling-googles-deep-learning-library/">video</a> from Spark Summit East.</li>
  <li><a href="https://github.com/maxpumperla/elephas">Elephas</a> connects <a href="http://keras.io/">Keras</a> with Apache Spark</li>
</ul>

<h2 id="implementing-a-full-fledged-frameworrk">Implementing a full-fledged frameworrk</h2>

<ul>
  <li><a href="http://deepdist.com/">DeepDist</a> (<a href="https://github.com/dirkneumann/deepdist">repo</a>) is a framework for DBNs implementing downpour gradient descent. The approach is reminiscent of <a href="https://amplab.cs.berkeley.edu/projects/splash/">Splash</a></li>
  <li><a href="http://deeplearning4j.org/">DeepLearning4J</a> is reimplementing a wide range of NNs, from a fast Java array lib. They run distributed on Spark, with GPU acceleration.</li>
</ul>

<p>This is just a quick preview, and the criteria for notability are somewhat arbitrary : e.g. I chose not to include <a href="https://github.com/guoding83128/OpenDL">OpenDL</a>, because it’s a seemingly unmaintained experiment based on Jeff Dean’s “<em>Large Scale Distributed Deep Networks</em>” paper. Feel free to mention anything I would have forgotten in comments !</p>]]></content><author><name>François Garillot</name></author><category term="deep learning" /><category term="apache" /><category term="big data" /><summary type="html"><![CDATA[Here’s a quick roundup of distributed deep learning efforts running on Apache Spark. This will only list active(-ish) projects rather than academic experiments (of which there are too many to list) There’s roughly two approaches:]]></summary></entry><entry><title type="html">May 2016 time series storage roundup</title><link href="https://www.garillot.net/posts/2016/05/may-roundup-time-series/" rel="alternate" type="text/html" title="May 2016 time series storage roundup" /><published>2016-05-09T00:00:00-07:00</published><updated>2016-05-09T00:00:00-07:00</updated><id>https://www.garillot.net/posts/2016/05/roundup_time_series</id><content type="html" xml:base="https://www.garillot.net/posts/2016/05/may-roundup-time-series/"><![CDATA[<p>A recent slew of blogs and articles have been shedding new insight on time series storage. I thought I’d list some of the zeitgeist.</p>

<p>Facebook came up with <a href="http://www.vldb.org/pvldb/vol8/p1816-teller.pdf"><em>Gorilla: A fast, scalable, in-memory time series database</em></a>. It’s reviewed by Adrian Colyer <a href="https://blog.acolyer.org/2016/05/03/gorilla-a-fast-scalable-in-memory-time-series-database/">here</a>.</p>

<p>The paper includes:</p>
<blockquote>
  <p>In the future, we hope that Gorilla enables more advanced data mining techniques on our monitoring time series data, such as those described in the literature for clustering and anomaly detection [<a href="http://www.cs.ucr.edu/~eamonn/sigkdd_tarzan.pdf">10</a>, <a href="http://ece.ut.ac.ir/dbrg/seminars/specialdb/2006/ghadimi-abbasi-pashaei/references/data%20mining/4.pdf">11</a>, <a href="http://www.cs.ucr.edu/~stelo/papers/KDD04_VizTree.pdf">16</a>].</p>
</blockquote>

<p>All papers are very cool free-form techniques either directly applicable or very interesting when taken down to the context of time series. Adrian Colyer reviews <a href="https://blog.acolyer.org/2016/05/09/finding-surprising-patterns-in-a-time-series-database-in-linear-time-and-space/">the first</a> and <a href="https://blog.acolyer.org/2016/05/10/towards-parameter-free-data-mining/">the second</a>.</p>

<p>Secondly, UC Berkeley came up with <a href="https://www.usenix.org/system/files/conference/fast16/fast16-papers-andersen.pdf"><em>BTrDB: Optimizing Storage System Design for Timeseries Processing</em></a>. Again, Adrian Colyer <a href="https://blog.acolyer.org/2016/05/04/btrdb-optimizing-storage-system-design-for-timeseries-processing/">reviews this result</a>.</p>

<p>More recently, Samsung came up with <a href="http://arxiv.org/pdf/1605.01435v1.pdf"><em>A Fast Lightweight Time-Series Store for IoT Data</em></a> : a data store designed to leverage the characteristics of time-series data in an IoT application context (think smartcities).</p>

<p>Finally, <a href="http://www.chronix.io/">Chronix</a> presents itself as an Apache Solr-inspired new kid on the block for the processing of time-series data. It touts a <a href="http://qaware.blogspot.ch/2015/12/open-source-project-chronix-efficient.html">blog post</a> and two talks at the <a href="http://events.linuxfoundation.org/events/apache-big-data-north-america">upcoming ApacheCon</a>.</p>

<p>These recent options add to the already existing:</p>

<ul>
  <li><a href="https://www.vividcortex.com/resources/webinars/catena/">Catena</a></li>
  <li><a href="https://speakerdeck.com/postwait/the-architecture-of-a-distributed-analytics-and-storage-engine-for-massive-time-series-data">Snowth</a></li>
</ul>

<p>The shape of event processing is changing, and it’s nice to see the correpsonding tools are changing as well. On the processing side, these newcomers can be linked to the already well-known ways of dealing with this sort of data, among which Flink’s <a href="https://flink.apache.org/news/2016/04/06/cep-monitoring.html">complex event processing</a>, or Spark’s <a href="https://databricks.com/blog/2015/09/28/improved-frequent-pattern-mining-in-spark-1-5-association-rules-and-sequential-patterns.html">frequent pattern mining</a>. There is also Cloudera’s <a href="https://blog.cloudera.com/blog/2016/01/spark-ts-0-2-0-released/">spark-ts library</a>.</p>

<p>See anything i’ve missed ? Shoot me a comment below !</p>]]></content><author><name>François Garillot</name></author><category term="time series" /><category term="big data" /><summary type="html"><![CDATA[A recent slew of blogs and articles have been shedding new insight on time series storage. I thought I’d list some of the zeitgeist.]]></summary></entry><entry><title type="html">Another update on streaming work</title><link href="https://www.garillot.net/posts/2015/07/another-update-streaming" rel="alternate" type="text/html" title="Another update on streaming work" /><published>2015-07-15T00:00:00-07:00</published><updated>2015-07-15T00:00:00-07:00</updated><id>https://www.garillot.net/posts/2015/07/another-update-streaming</id><content type="html" xml:base="https://www.garillot.net/posts/2015/07/another-update-streaming"><![CDATA[<p>This is an update on my
<a href="/posts/2015/07/update-streaming">previous post</a>
about work by <a href="http://www.typesafe.com/">Typesafe</a> to add resiliency to
<a href="https://spark.apache.org/streaming/">Spark Streaming</a>.</p>

<p>The part of this work that may enter Spark 1.5.0 consists in adding a
dynamic throttle to streaming execution, which continuously estimates the
maximum number of elements per second the system is able to take in, and
regulates data ingestion based on that. My colleague
<a href="http://github.com/skyluc">Luc</a>, the author of a cool
<a href="https://github.com/skyluc/spark-streaming-testbed">test bed</a> for this
feature, has written a
<a href="https://github.com/skyluc/spark-streaming-testbed/blob/blog-post1/tmp/1/post.md">summary</a>
of the main results, you should <em>go read
it</em>. <a href="https://github.com/typesafehub/spark/pull/15">The</a>
<a href="https://github.com/typesafehub/spark/pull/16">internal</a>
<a href="https://github.com/typesafehub/spark/pull/17">pull</a>
<a href="https://github.com/typesafehub/spark/pull/18">requests</a>, tied to
<a href="https://issues.apache.org/jira/browse/SPARK-7398">SPARK-7398</a>, are out -
you may want to look at them or at the design docs if you’re technically
inclined.</p>

<p>This differs from
<a href="https://github.com/typesafehub/spark/pull/13">the previous PoC implementation</a>
in that it does not include congestion management strategies other than
throttling (e.g. sampling data, or other destructive strategies), and does
not offer a connection to
<a href="http://www.reactive-streams.org/">Reactive-Streams-compliant</a> data
producers.</p>

<p>Pull-requests are not even issued against the Spark repository, yet I’d
still like to take this occasion to mention the great OSS work done so far
on the subject. Besides <a href="http://github.com/skyluc">Luc</a>’s great
<a href="https://github.com/skyluc/spark-streaming-testbed">test bed</a>, colleagues
<a href="https://github.com/huntchr">Christopher</a>,
<a href="https://github.com/deanwampler">Dean</a>,
<a href="https://github.com/dragos">Iulian</a>, and the whole Akka team (incl. notably
<a href="https://github.com/bantonsson">Björn</a>,
<a href="https://github.com/ktoso">Konrad</a>, <a href="https://twitter.com/drewhk">Endre</a>,
<a href="https://github.com/jboner">Jonas</a>,
<a href="https://github.com/viktorklang">Viktor</a>, and
<a href="https://github.com/rkuhn">Roland</a>) have been continuously providing great
comments, criticism and discussions since first internal proposals in
December 2014. <a href="https://github.com/jerryshao">Jerry Shao</a> from
<a href="http://www.intel.com">Intel</a> has provided
<a href="https://issues.apache.org/jira/browse/SPARK-6691">early work</a> and a
<a href="https://github.com/apache/spark/pull/5385">PR</a> in April that were a great
inspiration. <a href="https://github.com/maasg">Gérard Maas</a> from
<a href="http://www.virdata.com/">Virdata</a> suggested the essential idea that the
old fixed-rate limits should be kept as an upper bound to ensure a smooth
fault recovery. <a href="https://twitter.com/monaldax">Monal Daxini</a>,
<a href="https://github.com/cfregly">Chris Fregly</a>, and
<a href="https://github.com/rxin">Reynold Xin</a> provided tough questions and comments
in a video meeting during the Spark Summit in
June. <a href="https://github.com/helena">Helena Edelson</a> from
<a href="http://www.datastax.com/">DataStax</a> has offered to interface with the
<code class="language-plaintext highlighter-rouge">ReactiveReceiver</code> present in an early stage of this work. And of course
<a href="https://github.com/pwendell">Patrick Wendell</a> and
<a href="https://github.com/tdas">Tathagata Das</a> from
<a href="http://www.databricks.com/">Databricks</a> have been arguing, discussing,
improving and shepherding this for a long time (esp. the latter), ever since
a meeting in San Francisco in early March of this year. That’s not to
mention the fantastic environment Typesafe offers to its developers -
including in ways the above doesn’t make obvious -, for
which I’m extremely greatful.</p>]]></content><author><name>François Garillot</name></author><category term="apache spark" /><category term="streaming" /><category term="big data" /><summary type="html"><![CDATA[This is an update on my previous post about work by Typesafe to add resiliency to Spark Streaming.]]></summary></entry><entry><title type="html">A quick update on Spark Streaming work</title><link href="https://www.garillot.net/posts/2015/07/update-streaming/" rel="alternate" type="text/html" title="A quick update on Spark Streaming work" /><published>2015-07-10T00:00:00-07:00</published><updated>2015-07-10T00:00:00-07:00</updated><id>https://www.garillot.net/posts/2015/07/update-streaming</id><content type="html" xml:base="https://www.garillot.net/posts/2015/07/update-streaming/"><![CDATA[<p>Since I was asked a few times here at <a href="http://scaladays.org/">Scala Days</a>, I thought I’d write an update on how some of our work on making Spark Streaming more resilient is going. Naturally, all of this is open-source, otherwise I wouldn’t be writing this.</p>

<p>Remember that this is very much work in progress, so that while constructive advice is <em>very</em> welcomed, I for one hope that critics show a certain benevolence and focus on potential (that means ‘be gentle’, if you’re reading this).</p>

<p>In a nutshell, a Spark cluster, like any fixed processing system, can be sprayed with too much data with respect to what it can handle gracefully. That’s <em>congestion</em>, and the signal that communicates it is usually called <em>back-pressure</em>. We’re interested in making Spark Streaming react more gracefully to that congestion situation.</p>

<p>A first part of our work consists in having Spark Streaming itself measure how much load it’s on and trickle back that information to the point of ingestion of its input data. At this point, we have a few congestion-handling strategies that can deal with the situation, which include throttling data ingestion, dropping data on the floor (ignoring it) after you’ve reached a bound, or sampling.</p>

<p>Note that Spark Streaming already had throttling since <a href="https://issues.apache.org/jira/browse/SPARK-1341">a while ago</a>, but our
work focuses on deriving a bound on data ingestion from the real-time load on the cluster. This way, you don’t have to maintain your throttle actively in case your cluster topology or your job changes. And ideally, this lets your cluster always function at maximum capacity, without guesswork.</p>

<p>We also want to expose an API that extends Spark Streaming’s
<a href="https://spark.apache.org/docs/latest/streaming-custom-receivers.html">Receiver</a> so that you can provide your own congestion strategy, such as, say, keeping only the top-K elements you’ve seen on the last few minutes of the stream.</p>

<p>We’re working on a test bed that puts this capability through the paces. On synthetically-generated data (and, for now, at a relatively modest scale) we’re seeing interesting results, shown in the two pictures above. Free memory is represented in blue, so that you can pick which image is a run on the unmodified Spark: it’s the one where the blue line reaches zero. The other one drops elements.</p>

<p>Another part of our work is to expose a domain adapter for Spark Streaming, so that it can interface with the ecosystem of Reactive Streams. Reactive Streams are a simple API that lets Subscribers emitting a back-pressure signal interface upstream with a Publisher that is able to take that signal into account in a meaningful way (by pacing themselves appropriately), and percolates it upstream if necessary.</p>

<p><img src="../images/backpressure_without.png" alt="without backpressure" />
<img src="../images/backpressure_with.png" alt="with backpressure" /></p>

<p>What we have so far in terms of a runnable, working prototype is what I’ve described until the present sentence. The next steps include:</p>

<ul>
  <li>choosing or implementing a best-of-breed and yet <strong>dead simple</strong>
implementation of a Reactive Stream Publisher and a Spark Reactive
Receiver implementation to add to our test bed. Replicating the
congestion-handling results we have.</li>
  <li>Shipping code and test bed to our friends at
<a href="https://twitter.com/virdata_iot">Virdata</a> so that this is tested in a
real cluster, on a large-scale deployment.</li>
  <li>If the results of the previous steps are good, opening the   pull-request with our test bed as an attachement anybody can play with to test the code.</li>
</ul>

<p>As far as resources go, you can look at our
<a href="https://issues.apache.org/jira/browse/SPARK-7398">JIRA</a>, and at
<a href="https://docs.google.com/document/d/1ZhiP_yBHcbjifz8nJEyPJpHqxB1FT6s8-Zk7sAfayQw/edit?usp=sharing">our design document</a>,
and provide your comments !</p>]]></content><author><name>François Garillot</name></author><category term="streaming" /><category term="apache spark" /><category term="backpressure" /><summary type="html"><![CDATA[Since I was asked a few times here at Scala Days, I thought I’d write an update on how some of our work on making Spark Streaming more resilient is going. Naturally, all of this is open-source, otherwise I wouldn’t be writing this.]]></summary></entry><entry><title type="html">Diving In The Deep End of The Big Data Pool: Talk Abstract</title><link href="https://www.garillot.net/posts/2014/11/diving-deep-end" rel="alternate" type="text/html" title="Diving In The Deep End of The Big Data Pool: Talk Abstract" /><published>2014-11-19T00:00:00-08:00</published><updated>2014-11-19T00:00:00-08:00</updated><id>https://www.garillot.net/posts/2014/11/diving-pool-abstract</id><content type="html" xml:base="https://www.garillot.net/posts/2014/11/diving-deep-end"><![CDATA[<p>This is the Abstract for my Ignite talk at the <a href="http://strataconf.com/strataeu2014/public/content/home">Strata+Hadoop Barcelona</a> conference, on Wed Nov 19th, 2014 (at <a href="http://www.ccib.es/">CCIB</a>, room 116, 5:30PM). I haven’t found any place where O’Reilly would publish that abstract, and I thought some people would want a peek at what I’d talk about.</p>

<hr />
<p>##TL;DR##</p>

<p>Can you take four analytical PhDs fresh out of school, make them tackle a big data project, and solve a business problem? Can you do it in a month? This was the bet of the Data Science bootcamp this talk will report on. In this frantic story, you’ll hear about ramping up, knowledge sharing, implementation woes, and the joy of discovery. And you’ll learn about assembling your next data commando.</p>

<p>##Abstract##
This is an experience report of one of the <a href="http://blog.garillot.net/post/84520007401/a-very-data-sciencey-summer">six Data Science bootcamps</a> that ran over the summer 2014. Science to Data Science (<a href="http://s2ds.org/">S2DS</a>) was organized in London by Strata speaker <a href="http://strataconf.com/strataeu2014/public/schedule/speaker/167717">Kim Nilsson</a> pairing recent PhDs with industry mentors on a hands-on project.</p>

<p>The speaker and his three colleagues thus worked with <a href="http://www.weve.com/">Weve</a>, on a project that involved finding overlooked and relevant market segments in millions of mobile phone customers.</p>

<p>This talk will address the challenges of four former academics in making sense of industry’s complex business rules, sharing knowledge at a breakneck pace, choosing algorithms, tools and implementations when not one of them is an exact fit for the problem and time frame, and finally on what made us succeed despite all of the above.</p>]]></content><author><name>François Garillot</name></author><category term="data science" /><category term="big data" /><summary type="html"><![CDATA[This is the Abstract for my Ignite talk at the Strata+Hadoop Barcelona conference, on Wed Nov 19th, 2014 (at CCIB, room 116, 5:30PM). I haven’t found any place where O’Reilly would publish that abstract, and I thought some people would want a peek at what I’d talk about.]]></summary></entry><entry><title type="html">Installing Xen on an Apple iMac</title><link href="https://www.garillot.net/posts/2014/11/xen-imac" rel="alternate" type="text/html" title="Installing Xen on an Apple iMac" /><published>2014-11-13T00:00:00-08:00</published><updated>2014-11-13T00:00:00-08:00</updated><id>https://www.garillot.net/posts/2014/11/xen-mac</id><content type="html" xml:base="https://www.garillot.net/posts/2014/11/xen-imac"><![CDATA[<h2 id="introduction"><strong>Introduction</strong></h2>

<p><em>This is a guest post by my colleague <a href="http://www.cunei.com/">Antonio Cunei</a>, who battled an iMac long enough to manage installing Xen (and Ubuntu as Dom0) on top of it. Kudos to him !</em></p>

<p>If you install <a href="http://www.ubuntu.com/">Ubuntu</a> on an iMac, it will install it by default in <a href="https://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface">EFI</a> mode.</p>

<p>On some machines — for instance on a Macbook Air—, it will also tweak the EFI firmware in order to boot through <a href="https://help.ubuntu.com/community/UEFI">EFI-grub</a>. However, on the iMac, you need to boot into OSX, usually from an external USB key (e.g. by installing OSX on said USB — a shortcut would also be to boot from Apple installation media).</p>

<p>Then, you should got to the terminal and <a href="https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man8/bless.8.html">bless</a> the grub EFI file.</p>

<h2 id="blessing-an-efi-file"><strong>Blessing an EFI file</strong></h2>

<p><em>Generic Macs :</em></p>

<p>You can use the bless command from within Mac OS X to set grubx64.efi as the default boot option. You can also boot from the Mac OS X install disc and launch a Terminal there if you only have Linux installed. In the Terminal, create a directory and mount the EFI System Partition:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># cd /Volumes
# mkdir efi
# mount -t msdos /dev/disk0s1 /Volumes/efi
</code></pre></div></div>

<p>Then run bless on grub.efi and on the EFI partition to set them as the default boot options.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># bless --folder=/Volumes/efi --file=/Volumes/efi/efi/arch_grub/grubx64.efi --setBoot
# bless --mount=/Volumes/efi --file=/Volumes/efi/efi/arch_grub/grubx64.efi --setBoot
</code></pre></div></div>

<p>Do not try to use <code class="language-plaintext highlighter-rouge">bless --info</code>. It’s broken and may corrupt the disk, reportedly. Also, you may have to reboot resetting the PRAM multiple times (switch it on while pressing ⌘-Option-P-R until it chimes and reboots), otherwise the security “<em>features</em>” will ignore attempts to overwrite the firmware info using <code class="language-plaintext highlighter-rouge">bless</code>.</p>

<p><a href="http://www.tlviewer.org/xen/ubuntu/trusty/44x/">Here you can find a version of the <code class="language-plaintext highlighter-rouge">Xen.efi</code> file, for version 4.4.x.</a></p>

<p>You can use just xen.efi, and install the rest in Ubuntu, installing
the regular <code class="language-plaintext highlighter-rouge">xen-hypervisor-xxx</code> package, as per the manual pages.</p>

<p>In <code class="language-plaintext highlighter-rouge">xen.cfg</code>, you can put something like:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[global]
default=polenta

[polenta]
options=console=vga,com1 com1=115200 loglvl=all noreboot
kernel=vmlinuz-3.14-2-amd64 ignore_loglevel  root=/dev/mappe/clava-root ro quiet #earlyprintk=xen
ramdisk=initrd.img-3.14-2-amd64
</code></pre></div></div>

<p>or:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[global]
default=polenta

[polenta]
options=console=vga loglvl=all noreboot
kernel=vmlinuz-3.16.0-24-generic root=/dev/sda2 rw ignore_loglevel     ramdisk=initrd.img-3.16.0-24-generic
</code></pre></div></div>

<p>depending on your exact target kernel and dsired options.</p>

<p>Here’s how to do chainloading, in case you want to go through grub:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>menuentry "Xen EFI" {
    insmod part_gpt
    insmod search_fs_uuid
    insmod chain
    chainloader (hd0,gpt1)/EFI/XEN/xen.efi
}
</code></pre></div></div>

<h2 id="grub-woes-and-more-details-on-the-above"><strong>Grub Woes and more details on the above</strong></h2>

<p>Grub, in EFI Mode, in the default installation of Xen provided by Ubuntu, will not load Xen properly.</p>

<p>The standard Ubuntu Xen package is designed for BIOS boot. In order to boot Xen in EFI mode, there are two ways. In both cases, you need a Xen.EFI file, which is not provided by Ubuntu. So you can either compile it from source, or find it on the Internet (see above).</p>

<p>The <code class="language-plaintext highlighter-rouge">Xen.efi</code> needs to be aligned with the version of Xen installed from the Ubuntu package.</p>

<p>This<code class="language-plaintext highlighter-rouge"> Xen.efi</code> needs to be placed in the EFI boot partition (usually <code class="language-plaintext highlighter-rouge">/boot/EFI/EFI/ubuntu/xen.efi</code>).</p>

<p>You can boot <code class="language-plaintext highlighter-rouge">xen.efi</code> by either blessing from OSX that specific file, or using a feature of grub called chain-loader. Chain-loading is the only way to boot on Ubuntu without Xen.</p>

<p>Together with <code class="language-plaintext highlighter-rouge">xen.efi</code>, you need to place a <code class="language-plaintext highlighter-rouge">xen.cfg</code> file in the EFI boot partition. In there, you need to specify the root as a kernel parameter, and the ramdisk location.</p>

<p>The trick is : the Xen loader (<code class="language-plaintext highlighter-rouge">xen.efi</code>) is unable to look into a different partition, so that if you have your EFI partition mounted at /boot/EFI, the kernel is unreachable. Hence you need to mount it at /boot.</p>

<h2 id="last-detail">Last detail</h2>

<p>Since the Xen loader does not boot anything but what it can find on its own partition, you also need to copy the kernel image there !</p>]]></content><author><name>François Garillot</name></author><category term="EFI" /><category term="Xen" /><category term="Mac" /><summary type="html"><![CDATA[Introduction]]></summary></entry><entry><title type="html">A question about the Option Monad Transformer</title><link href="https://www.garillot.net/posts/2014/07/option-monad-transformer" rel="alternate" type="text/html" title="A question about the Option Monad Transformer" /><published>2014-07-14T00:00:00-07:00</published><updated>2014-07-14T00:00:00-07:00</updated><id>https://www.garillot.net/posts/2014/07/option-monad-transformer</id><content type="html" xml:base="https://www.garillot.net/posts/2014/07/option-monad-transformer"><![CDATA[<p>I’ve recently heard the following suprisingly general question:</p>

<blockquote>
  <p>The premise is that we have three services which return <code class="language-plaintext highlighter-rouge">Future[Option[Int]]</code>:</p>

  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>trait FooService {
  def find(id:Int): Future[Option[Foo]]
}

trait BarService {
  def find(id:Int): Future[Option[Bar]]
}

trait QuuxService {
  def find(id:Int): Future[Option[Quux]]
}
</code></pre></div>  </div>

  <p>And we need to query across all three services, i.e. in a non blocking/no
option service we would have:</p>

  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>val foo = fooService.find(1)
val bar = barService.find(foo.barId)
val quux = quuxService.find(bar.quuxId)
</code></pre></div>  </div>

  <p>Now, monads don’t compose, and because we have multiple <code class="language-plaintext highlighter-rouge">Future[Option[T]]</code>
here, the quickest route to resolving an Option from a Future (without
short-circuiting the failure case) is to use a partial function or fold,
and then just break things down into very small methods so it doesn’t get
too nesty.</p>

  <p>I’ve heard that there’s a third option which is to use a monad transformer
or a Reader monad.</p>
</blockquote>

<p>Then he ran into implementation-specific terminology for that particular
method. So, this is my (pointed) answer to the specific sub-question of
how to deal with this problem ‘using a monad transformer’. I’ll try to
make it prerequisite-free, using just Wikipedia-accessible mathematical
definitions and Scala.</p>

<h1 id="basics">Basics<a id="sec-2"></a></h1>

<p>So, just to check our bases, the idea of defining a Monad transformer for
<code class="language-plaintext highlighter-rouge">Future</code> and <code class="language-plaintext highlighter-rouge">Option</code> would require them to indeed be monads. They’re
functors, and they have a constructor, and a <code class="language-plaintext highlighter-rouge">flatMap</code>. Do they verify
the monadic laws ?</p>

<p>For <code class="language-plaintext highlighter-rouge">Option</code> (where, in scala, the apply Option(x) resolves to Some(x) on
non-derelict inputs):</p>

<ul>
  <li>left identity:
∀ (f: A, g: A → Option[B]) <code class="language-plaintext highlighter-rouge">Option</code> (f) <code class="language-plaintext highlighter-rouge">flatMap</code> g = g f</li>
  <li>right identity:
∀ (f: Option[A]), f <code class="language-plaintext highlighter-rouge">flatMap</code> ( λ(x:A). Option(x) ) = f</li>
  <li>associativity:
∀ (f: Option[A], g: A → Option[B], h: B → Option[C]) f <code class="language-plaintext highlighter-rouge">flatMap</code> g
<code class="language-plaintext highlighter-rouge">flatMap</code> h = f <code class="language-plaintext highlighter-rouge">flatMap</code> ( λ(x:A). g x <code class="language-plaintext highlighter-rouge">flatMap</code> h)</li>
</ul>

<p>It’s a good exercise to check, e.g. for Option, that these equalities hold
whatever the output of the functions whose type matches the pattern (X →
Option[Y]) is.</p>

<p>For <code class="language-plaintext highlighter-rouge">Future</code>, the monadic laws look like this:</p>

<ul>
  <li>left identity:
∀ (f: A, g: A → Future[B])   <code class="language-plaintext highlighter-rouge">future</code> { f } <code class="language-plaintext highlighter-rouge">flatMap</code> g = g f</li>
  <li>right identity:
∀ (f: Future[A]), f <code class="language-plaintext highlighter-rouge">flatMap</code> ( λ(x:A). <code class="language-plaintext highlighter-rouge">future</code> { x } ) = f</li>
  <li>associativity:
∀ (f: Future[A], g: A → Future[B], h: B -&gt; Future[C]) f <code class="language-plaintext highlighter-rouge">flatMap</code> g
<code class="language-plaintext highlighter-rouge">flatMap</code> h = f <code class="language-plaintext highlighter-rouge">flatMap</code> ( λ(x:A). g x <code class="language-plaintext highlighter-rouge">flatMap</code> h)</li>
</ul>

<p>By the way, the left identity law for Futures doesn’t work if g throws an
exception before returning its Future:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>scala&gt; val g = { (x: Int) =&gt; if (x == 0) throw new IllegalArgumentException("Zero !") else Future { 3 / x } }
g: Int =&gt; scala.concurrent.Future[Int] = &lt;function1&gt;

scala&gt; g(0)
java.lang.IllegalArgumentException: Zero !
  at $anonfun$1.apply(&lt;console&gt;:11)
  at $anonfun$1.apply(&lt;console&gt;:11)
  ... 32 elided

scala&gt; Future { 0 } flatMap g
res11: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@68f3b76b
</code></pre></div></div>

<p>In sum, it tells us something we knew : <code class="language-plaintext highlighter-rouge">Future</code>s put some
exception-raising behavior of their arguments in the future.  We’ll have
to be careful about which results depend on that left identity in the
following.</p>

<h1 id="composition">Composition<a id="sec-3"></a></h1>

<p>On to the statement that ‘monads don’t compose’. This is true, but it
means that there is no general function that takes two monads as input,
and systematically returns a monad for the composition of the two underlying functors, for <em>any two input monads</em>. At best,
what one can <em>always</em> hope to return is a functor.</p>

<p>That being said, it’s a starkly different statement from dealing with two
particular monads. For two very specific, fixed monads, there may well be
a way to compose them into a monad, and that is not a contradiction with
the prior statement.</p>

<p>And we’re in the case of two very specific monads: Option and Future.</p>

<p>In fact, there’s even a construction called a monad transformer, slightly
more demanding than a monad, that can be injected into a monad to yield
another (<em>transformed</em>) monad (<sup id="fnref:constructor" role="doc-noteref"><a href="#fn:constructor" class="footnote" rel="footnote">1</a></sup>).</p>

<p>So, a monad transformer requires an interface with:</p>

<ul>
  <li>
    <p>A type constructor T which takes a type constructor and returns
another. Technically, it’s said to be of kind (★ → ★) → ★ → ★.
As can be expected, the intent is to make it take the “<em>transformee</em>”
monad as argument.</p>
  </li>
  <li>
    <p>Monad operations (a constructor and a <code class="language-plaintext highlighter-rouge">flatMap</code>), for every output T(M)
(the <em>transformed</em> monad), provided the input M (the <em>transformee</em>) is a
monad. Notice how making sure the transformed monad is here a
<em>requirement</em>.</p>
  </li>
  <li>
    <p>Another operation, <code class="language-plaintext highlighter-rouge">lift</code> : ∀A: ★, ∀M: ★ → ★. M[A] → T[M[A]] (this reads,
∀ A a <em>type</em> and M a <em>type constructor</em>) satisfying the following
laws:</p>
    <ul>
      <li>∀ M: ★ → ★,  <code class="language-plaintext highlighter-rouge">lift</code> ∘ M = T</li>
      <li><code class="language-plaintext highlighter-rouge">lift</code> (M <code class="language-plaintext highlighter-rouge">flatMap</code> k) = (<code class="language-plaintext highlighter-rouge">lift</code> M) <code class="language-plaintext highlighter-rouge">flatMap</code> (<code class="language-plaintext highlighter-rouge">lift</code> ∘ k)</li>
    </ul>
  </li>
</ul>

<p>This becomes more clear, as with every abstract structure, after building
a couple of concrete cases. Intuitively, the transformed monad has the
operation of the transformer injected in its <em>inputs</em>. So, given that
we’re interested in services that return a Future[Option[A]] (as opposed
to an Option[Future[A]]), we’re interested in defining the Option Monad
Transformer (as opposed to the Future Monad Transformer).</p>

<p>Thankfully, not only does this Option Monad Transformer exists, but it’s
easy to define.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>trait ApplicativeFunctor[A, F[A]] {
  def apply[X](a:X): F[X]
  def map[B](f: A =&gt; B): F[B]
}

trait Monad[A, M[A]] extends ApplicativeFunctor[A, M] {
  def flatMMap[B](f: A =&gt; M[B]): M[B]
}


class OptionT[A, M[A]] (m:ApplicativeFunctor[Option[A], M]) extends ApplicativeFunctor[A, ({type T[X]=M[Option[X]]})#T] {
  override def apply[X](a:X): M[Option[X]] = m(Option(a))
  override def map[B](f: A =&gt; B): M[Option[B]] =
    m map {(x: Option[A]) =&gt; x map f}
}

class OptionTM[A, M[A]](m:Monad[Option[A], M]) extends OptionT[A, M](m) with Monad[A, ({type T[X]=M[Option[X]]})#T] {
  override def flatMMap [B] (f:A =&gt; M[Option[B]]) : M[Option[B]] =
    m flatMMap {
      case Some(z) =&gt; f(z)
      case None =&gt; m(None)
    }
}
</code></pre></div></div>

<p>The name <code class="language-plaintext highlighter-rouge">flatMMap</code> instead of flatMap is here to avoid conflicts. The
<code class="language-plaintext highlighter-rouge">({type T[X]=M[Option[X]]})#T</code> is unsightly, and pollutes the scope of the
program, but how to iron that particular wrinkle is beyond the scope of
this post.</p>

<p>Let’s give a moment of pause to the three laws:</p>

<ul>
  <li>left identity:
∀(f:A, g: A =&gt; Future[Option[B]]) Future { Option(f) } flatMap g = g ( f )
Unfolding this one reveals that for this equality to hold, we’d need the
left equality for the Future monad to hold. Not that it’s the first
time we’ve seen</li>
  <li>right identity:
∀ (f: Future[Option[A]]), f <code class="language-plaintext highlighter-rouge">flatMap</code> ( λ(x:A). Future{ Option(x) } ) = f</li>
  <li>associativity:
∀ (f: Option[A], g: A → Option[B], h: B → Option[C]) f <code class="language-plaintext highlighter-rouge">flatMap</code> g
<code class="language-plaintext highlighter-rouge">flatMap</code> h = f <code class="language-plaintext highlighter-rouge">flatMap</code> ( λ(x:A). g x <code class="language-plaintext highlighter-rouge">flatMap</code> h)</li>
</ul>

<p>All that’s left is to test it. The inevitable part is reminding Scala
there’s a Monad instance for Future, even in the context where <code class="language-plaintext highlighter-rouge">Option[A]</code>
is the parameter, but it’s more about mapping our terminology with
existing Scala methods. Then there is the related implicit declaration to
palliate some insufficiencies in implicit search not jumping order in type
parameters when a suitable application of a lower-kind constructor is
found.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>abstract class MyTest{

  import scala.concurrent.Future
  import scala.concurrent.ExecutionContext.Implicits._

  // The unchanged future monad, but applied to Option[A]
  class FutureOM[A](fut: Future[Option[A]]) extends Monad[Option[A], Future] {
    def apply[X](a:X): Future[X] = Future { a }
    def map[B](f: Option[A] =&gt; B): Future[B] = fut map f
    def flatMMap[B](f: Option[A] =&gt; Future[B]): Future[B] = fut flatMap f
  }

  implicit def optionMF[A](f:Future[Option[A]]) = new OptionTM(new FutureOM(f))


  trait FooService {
    def find(id: Int): Future[Option[Int]]
  }

  trait BarService {
    def find(id: Int): Future[Option[Int]]
  }

  trait QuuxService {
    def find(id:Int): Future[Option[Int]]
  }

  val fooService: FooService
  val barService: BarService
  val quuxService: QuuxService

  def finalRes(): Future[Option[Int]] =
    fooService.find(1) flatMMap (barService.find _) flatMMap (quuxService.find _)
}
</code></pre></div></div>

<p>The whole source is on <a href="https:">github</a></p>

<p>In the following, I’ll use liberally of the Scala `apply` syntactic sugar of
calling the constructor in the same way as the resulting type. Since I’m
typing every variable, it should be easy to see what I’m talking about. In
case of doubt, I apply the constructor with parentheses, and the type
constructor with brackets. the For instance, Option is a type constructor: λ(A:★).Option[A]: ★ → ★, which returns a term of an Option type:   ∀A: ★, (λ(x:A). Option(x)): A → Option[A]. So is List λ(A:★).List[A]: ★ → ★, which returns a term of a List type:  ∀A: ★, (λ(x:A). List(x)): A → List[A].</p>
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:constructor" role="doc-endnote">

      <p><a href="#fnref:constructor" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>François Garillot</name></author><category term="Scala" /><category term="monad transformer" /><category term="monad" /><summary type="html"><![CDATA[I’ve recently heard the following suprisingly general question:]]></summary></entry></feed>